まだAnko使ってないの！？

はいどうも、こんばんは。
Ankoの紹介をします。

# Anko イズ 何
AnkoはAndroidのレイアウト構築をするためのものです。
DSL...何か決まっている問題を解決するための言語です。AnkoはAndroidのレイアウト構築だけを考えられて作られた言語です。つまり...なんで使わないの。

ちなみにこちら[Jetbrains](https://blog.jetbrains.com/kotlin/2015/04/announcing-anko-for-android/)製です。中身もkotlinで書かれています。

なので、もちろんKotlinの強みであるNull安全や型推論等サポートされているわけです。

# 導入
gradleプロジェクトなら一瞬です。
依存関係を記述します。

```gradle
compile 'org.jetbrains.anko:anko-sdk15:0.8.3'
```

たった一行で済みます。うんうん。

ただ、新しい環境（記述時2.3)だと動きません。
僕はAndroidStudio2.0で動かしました。

凄く粗削りですが[こちら](https://github.com/SasakiYuki/AnkoChan/tree/master/AnkoChan)にコードもおいてあります。かなり記事にする上で端折っているのでよかったら合わせて読んでください。

# 使おう

```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:text="登録"/>

</LinearLayout>
```

よく見る（見ない）レイアウト構成です。
LinearLayoutの中にEditTextとButtonが入っています。

まずはこれをAnkoってみましょう。

```kotlin
        linearLayout {
            orientation = LinearLayout.VERTICAL

            editText().lparams(width = matchParent, height = wrapContent)
            button(R.string.subscribe) {
                gravity = Gravity.RIGHT
            }.lparams(width = wrapContent, height = wrapContent)
        }
```

超簡単じゃないですか。というか見たことがあると思います。ほぼxmlのままです。
xmlが書ければankoが書ける...ankoが書ければxmlが書ける...といったことが読んでもらえばわかると思います。
プロジェクトへの進言もしやすいですね。

とはいえこれだけではまぁ...使う気にはならないですよね。
もーっといろいろスマートになります。

# id要らない
idが不要になります。どういうことでしょうか。
まずはActivityのほうにクリック後の処理を書きましょう。

```kotlin
fun subscribe(ui: AnkoContext<MainActivity>, text: String) {
    ui.doAsync {
        Thread.sleep(500)
        activityUiThreadWithContext {
            if (checkCredentials(text)) toast("Login")
        }
    }
}
```

登録ボタンをしてる感処理です。


```java
    override fun createView(ui: AnkoContext<MainActivity>) = with(ui) {
        linearLayout {
            orientation = LinearLayout.VERTICAL

            val name = editText().lparams(width = matchParent, height = wrapContent)
            button(R.string.subscribe) {
                onClick {
                    ui.owner.subscribe(ui,name.text.toString())
                }
                gravity = Gravity.RIGHT
            }.lparams(width = wrapContent, height = wrapContent)
        }
    }
```

そして先ほど用意したレイアウトのほうに戻ります。
少しいじってありますが。まずはbuttonに`OnClick`が定義してあるのがわかると思います。
そしてその中でMainActivityにある`subscribe`メソッドを呼び出しているのがわかると思います。
これは普段だったら....

```kotlin
        findViewById(R.id.button).setOnClickListener { 
            subscribe()
        }
```

といったことをしなきゃいけないものだと思います。Ankoなら昔からずっと言われている冗長番長`findViewById`を消し去り、.xmlからもid属性を消すことができます。（というか.xmlが消えるんだけど）

さらに、

今までだったら...

```kotlin
findViewById(R.id.button).setOnClickListener { 
    subscribe((findViewById(R.id.edittext) as EditText).text.toString())
}
```

と書いていたものが。

もう一点先ほどのコードと変わったところがあります。

```kotlin
val name = editText().lparams(width = matchParent, height = wrapContent)
```

`EditText`を変数に代入しています。これもまたidを消すことができていて、`subscribe`メソッドで`String`を渡さなければいけないところを楽にしてくれています。
`OnClick`の中で

```kotlin
ui.owner.subscribe(ui,name.text.toString())
```

nameをごにょるだけでなんとかなっています。素晴らしい...

# CustomViewを作る
ただこれだと少しネストが深いとうんざりしちゃいますかね？（もちろんそれは.xmlにも言えることですが）どうすれば解決するでしょう。とりあえず`CustomView`にしてみましょう。

まぁとりあえずいつもの.xmlで。

```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="horizontal">

    <ImageView
        android:id="@+id/imageview"
        android:layout_width="80dp"
        android:layout_height="80dp"
        tools:src="@android:drawable/alert_dark_frame"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="10dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/text_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="6dp"
                tools:text="佐々木"/>

            <TextView
                android:id="@+id/text_id"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@android:color/darker_gray"
                tools:text="\@Sasaki_YuKi"/>

            <ImageView
                android:id="@+id/image_lock"
                android:layout_width="15dp"
                android:layout_height="15dp"
                android:layout_gravity="center"
                android:src="@android:drawable/ic_lock_lock"
                android:visibility="gone"
                tools:visibility="visible"/>
        </LinearLayout>

        <TextView
            android:id="@+id/text_description"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="4dp"
            tools:text="今日も頑張って仕事をしよう。週末はおいしいものでも食べたいなぁ。"/>
    </LinearLayout>
    
</LinearLayout>
```

![custom.png](C:\Users\yuki.n\Desktop\custom.png)

こんなやつです。
Ankoで書くとこんな感じです。

```kotlin
    private fun init() = AnkoContext.createDelegate(this).apply {
        orientation = LinearLayout.HORIZONTAL

        image = imageView(imageResource = android.R.drawable.ic_menu_report_image) {
            layoutParams = LinearLayout.LayoutParams(dip(80), dip(80))
        }

        linearLayout {
            layoutParams = LinearLayout.LayoutParams(matchParent, wrapContent)
            orientation = LinearLayout.VERTICAL
            padding = dip(10)

            linearLayout {
                orientation = LinearLayout.HORIZONTAL

                textView(text = "佐々木") {
                }.lparams(width = wrapContent, height = wrapContent) {
                    rightMargin = dip(6)
                }
                textView(text = "@Sasaki_Yuki") {
                    textColor = android.R.color.darker_gray
                }.lparams(width = wrapContent, height = wrapContent)
                imageView {
                    setImageResource(android.R.drawable.ic_lock_lock)
                    visibility = View.VISIBLE
                }.lparams(width = dip(15), height = dip(15)) {
                    gravity = Gravity.CENTER
                }
            }.lparams(width = matchParent, height = wrapContent)
            textView(text = "今日も頑張って仕事をしよう。週末はおいしいものでも食べたいなぁ。") {
                padding = dip(4)
            }.lparams(width = matchParent, height = wrapContent)
        }
    }
```
(toolsに当たるものを見つけることができなかった）

Root要素が`LinearLayout`のため`ImageView`と名前とかが入っている`LinearLayout`が入っています。

```kotlin
@Suppress("NOTHING_TO_INLINE")
inline fun ViewManager.myLikeTweetView(theme: Int = 0) = myLikeTweetView({}, theme)

inline fun ViewManager.myLikeTweetView(init: LikeTweetView.() -> Unit, theme: Int = 0) = ankoView(::LikeTweetView, theme, init)
```

呼び出し口を用意して、Activity側から呼び出します。

```kotlin
            val name = editText().lparams(width = matchParent, height = wrapContent)
            button(R.string.subscribe) {
                onClick {
                    ui.owner.subscribe(ui,name.text.toString())
                }
                gravity = Gravity.RIGHT
            }.lparams(width = wrapContent, height = wrapContent)
            myLikeTweetView()
```

これでよい。

これの呼び出し口にRecyclerViewならConvertViewやらEntityを渡せば反映させることもできるようになるわけです。

# 終わりに
以上です。
Kotlinを使っているなら思い切ってankoにしてみるのもいいんじゃないでしょうか。
いつかより応用的な記事を書ければいいなと思います。

凄く粗削りですが[こちら](https://github.com/SasakiYuki/AnkoChan/tree/master/AnkoChan)にコードもおいてあります。かなり記事にする上で端折っているのでよかったら合わせて読んでください。