※Understanding Ankoをほぼ日本語訳しただけのものですが、ご了承ください。
※また、私自身、英語力には自信がありませんので、誤りがありましたらご指摘ください。
#基本
Ankoライブラリを利用するために、org.jetbrains.anko.*
パッケージをインポートしましょう。
それでは、onCreate()
の例を見てみましょう。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
verticalLayout {
padding = dip(30)
editText {
hint = "Name"
textSize = 24f
}
editText {
hint = "Password"
textSize = 24f
}
button("Login") {
textSize = 26f
}
}
}
Ankoでは、このようなDSLで記述できます。従来のように、setContentView(R.layout.something)
を呼び出す必要はありません。
これを詳しく見れば、
-
hint
,textSize
: JavaBeansのgetter/setter仕様に乗っ取った拡張プロパティ -
padding
: Ankoの拡張プロパティ -
verticalLayout
,editText
,button
:View
インスタンスを生成し、親View
に追加する拡張関数
であることがわかります。
このような記法は、Androidフレームワーク下のほぼ全てのView
に採用され、Activity
, Fragment
, Context
上で動作します。
#AnkoComponent
前項では、onCreate()
内にDSLを記述しましたが、通常は別のクラスを作ったほうが良いでしょう。
以下のように、onCreate()
内で、AnkoComponent
インターフェースを実装したクラスのインスタンスのsetContentView()
を呼び出しましょう。
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
MyActivityUI().setContentView(this)
}
}
class MyActivityUI : AnkoComponent<MyActivity> {
override fun createView(ui: AnkoContext<MyActivity>) = with(ui) {
verticalLayout {
val name = editText()
button("Say Hello") {
onClick { ctx.toast("Hello, ${name.text}!") }
}
}
}
}
#ブロックの省略
もしView
にプロパティが不要であれば、{}を省略して、button("Ok")
やbutton()
とできます。
例:
verticalLayout {
button("Ok")
button(R.string.cancel)
}
また、以下のように、テンプレートを付加することもできます。
verticalLayout {
themedButton("Ok", theme = R.style.myTheme)
}
※Themed blocksを利用し次第、書き改めます。
#レイアウトの記述
レイアウトを記述する際に、従来では、XML内に、
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginTop="10dip"
android:src="@drawable/something" />
のように記述していましたが、Ankoでは、View
の後ろにlparams()
を続けて、
linearLayout {
button("Login") {
textSize = 26f
}.lparams(width = wrapContent) {
horizontalMargin = dip(5)
topMargin = dip(10)
}
}
のように記述できます。width
やheight
は、lparams()
の名前付き引数として定義されており、省略した場合は、いずれもwrapContext
のデフォルト値が使用されます。
また、
-
horizontalMargin
: 左右 -
verticalMargin
: 上下 -
margin
: 上下左右
のプロパティを用いることで、対応する余白が同時に指定できます。
lparams()
の記述はレイアウト(ViewGroup
)によって異なります。例えば、RelativeLayout
であれば、
val ID_OK = 1
relativeLayout {
button("Ok") {
id = ID_OK
}.lparams { alignParentTop() }
button("Cancel").lparams { below(ID_OK) }
}
となります。
#Listeners
ボタンを作成する際、
button("Login") {
onClick {
// do something
}
}
と記述していました。実はこれ、
button.setOnClickListener(object : OnClickListener {
override fun onClick(v: View) {
launch(UI) {
// do something
}
}
})
とほぼ同じ記述なのです。つまり、拡張関数内でコルーチンが作成されるため、非同期処理をシームレスに記述することができるのです。
Ankoには、他にも可読性を向上させる記述方法があります。例えば、
seekBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
// Something
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
// Just an empty method
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
// Another empty method
}
})
を現在のAnkoでは、
seekBar {
onSeekBarChangeListener {
onProgressChanged { seekBar, progress, fromUser ->
// Something
}
}
}
と記述できます。onProgressChanged()
とonStartTrackingTouch()
を同じView
内に記述することも可能です。同じ関数を呼び出した場合は、最後に呼び出したものが適用されます。
また、以下のように、自前のコルーチンコンテキストを利用することもできます。
button("Login") {
onClick(yourContext) {
val user = myRetrofitService.getUser().await()
showUser(user)
}
}
#リソースの扱い
前項までの例では、文字列をそのまま用いていましたが、本来ならば、文字列データはres/values/
ディレクトリ以下にあり、実行時に呼ばれるべきです。
もちろんAnkoでも、今まで、getString(R.string.login)
と記述していたように、
button(R.string.login)
や
button { textResource = R.string.login }
と記述することが可能です。ここで注意しなければならないのが、text
, hint
, image
ではなく、textResource
, hintResource
, imageResource
を用いる必要があるということです。
#インスタンスの取得
Ankoでは、ctx
と記述するだけで、Context
インスタンスを取得できます。インナークラスであっても、this@SomeActivity
と記述する必要はありません。また、Activity
インスタンスはact
で取得できます。
#DSL内でXMLを利用する
include()
を用いて、
include<View>(R.layout.something) {
backgroundColor = Color.RED
}.lparams(width = matchParent) { margin = dip(12) }
と記述することで、簡単にXMLをDSLに挿入できます。
lparams()
はいつでも利用でき、View
以外の特定の型を用いる場合も同じ記述ができます。
例:
include<TextView>(R.layout.textfield) {
text = "Hello, world!"
}
#参考
https://github.com/Kotlin/anko/wiki/Anko-Layouts#understanding-anko