もうAnko使ったよね！？

どうも。
先日別のadventCalendarにて[まだAnko使ってないの！？
](http://qiita.com/Yuki_Yamada/items/5138082dd651bf96ecad)というタイトルで`Anko`の説明を軽くしました。
もしよかったらチェックしてみて下さい。

読んでいただいた方にはAnkoの魅力が伝わっていればいいなと思います。
そして、もっと紹介してくれ、という要望（？）にお答えして
今日はさらに`Anko`の魅力を紹介するために少し応用的な使い方をしていきます。
`kotlin`的な文法もかなり使っていくので`kotlin`の魅力にも気づいていただけたらと思います。

# 非同期処理
`Anko`を使っているとすごく簡単にバックスレッドに移動、`UI`スレッドに移動することができます。
まずは`Java`コードなら`Handle`使ったり`Async`でなんかしたりといろいろあると思いますが、冗長な部分が多く、しかも匿名メソッドなので全体の見通しが悪くなりがちです。

```kotlin
ui.doAsync {
    Thread.sleep(500)
    activityUiThreadWithContext {
        if (checkCredentials(text)) toast("Login")
        else toast("error")
    }
}
```

前回の記事中の`MainActivity`内で行っていた処理でもあります。何気なく記述しましたが`Anko`の恩恵を２点受け取っています。

まずはこの項目である、非同期処理

`ui`は`AnkoContext`です。それにたいして`doAsync`を行うだけです。別スレッドで順次処理されていきます。`Runnnable`と記述が似ています。

# Toast
`show`忘れたり引数が多い`Toast` ですが上記のように一文で記述できます。
またリソースIdだけ渡しても問題ありません。Longを出す場合は下記です。

```kotlin
longToast("長いToastを出したい")
```

簡単でしょう。

# ログ
デバグ中によく使うLog.x
特にその中でも`d`や`e`は使うのではないでしょうか。

```kotlin
if (checkCredentials(text)) debug("login success")
else error("login error")
```

明示的に何をしているのか、さらに簡単に記述。
`AnkoLogger`を継承する必要があります。

```kotlin
class MainActivity : AppCompatActivity(),AnkoLogger {
```

# AlertDialog
`DialogManager` を呼び出して～インスタンス化して～`PositiveButton`のテキストと無名ClickListener実装して～引数多くて見づらいし～ともうネスト深くなりまくる地獄。
なんとかラップして見やすくしたけどコールバックが～とわりと鬱陶しいやつですがAnkoなら瞬殺です。

```kotlin
alert("タイトルです", "メッセージです") {
    yesButton {}
    noButton {}
}.show()
```

残念ながらリソースIDではだめです。ちょっと惜しいな。
しかし、見通しはかなりよくなりました。

ちなみにこんなこともできます。

```kotlin
alert {
    customView {
        editText {
            hint = "こうなったら逃げられまい"
        }
    }
    yesButton {}
    noButton {}
}.show()
```

その場でCustomViewを作り上げ適用。なんてことだ、なぜ使ってなかったんだ今までってなったらもう一度僕の１個目の記事を読み直してPMに早く打診しに行くんだよ！！

# ListAdapterを作ってみる
他にも便利機能はあるのですが少しアプローチを変えて、`Anko`で普段使いそうなものを書いてみます。
タイトル通り`ListAdapter`を作ります。汎用的なやつです。

まずは前回同様Listに表示するアイテムを作ります。もちろん`.xml`は使いません。最も簡単な作りのものでこちらを継承して見た目を変えていくことにします。

コードを上げておくので詳しいものはそちらを見てください。こちらの記事では端折ったものを載せておきます。
[こちら！！！！](https://github.com/SasakiYuki/AnkoChan)

ListAdapterと同ファイル（ここはなんでも。個人的にはせっかく`Anko`で書いてるのでレイアウトも同じファイルにしたいと思っています。）に記述。ベースになる`View`です。


```kotlin
interface ListItem : AnkoComponent<AnkoListAdapter> {
    fun apply(convertView: View)
}

internal open class TextListItem(val text: String) : ListItem {
    protected inline fun createTextView(ui: AnkoContext<AnkoListAdapter>, init: TextView.() -> Unit) = ui.apply {
        textView {
            id = android.R.id.text1
            init()
        }
    }.view

    override fun createView(ui: AnkoContext<AnkoListAdapter>) = createTextView(ui) {
        gravity = Gravity.CENTER_VERTICAL
        padding = ui.dip(20)
        textSize = 13f
    }

    private fun getHolder(convertView: View): Holder {
        return (convertView.tag as? Holder) ?: Holder(convertView as TextView).apply {
            convertView.tag = this
        }
    }

    override fun apply(convertView: View) {
        val h = getHolder(convertView)
        h.textView.text = text
    }

    internal class Holder(val textView: TextView)
}

```

ここでのポイントは`View`の内部ではなく`Listner`です。`AnkoComponent<AnkoListAdapter>`を実装しています。このapplyでListAdapterを繋がっています。このような実装になることで依存関係がなくなるのでBaseがTextListItemであればレイアウトは自由自在というわけです。今回の例では`TextView`ですが、`LineaLayout`で作ればもっと柔軟なものが出来上がるでしょう。

肝心のadapterですが、特に難しいことはしてません。というかいつもと同じです。前述通り今作ったViewとのつながりはapplyでそれを`getView`の中で呼んでいるくらいです。

```kotlin
    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? {
        val item = getItem(position)
        if (item != null) {
            val view = convertView ?: item.createView(ankoContext)
            item.apply(view)
            return view
        } else return convertView
    }
```

これでBaseの`ListAdapter`が完成しました。これだけだと味気ないので、よく実装するセクション区切りも実装できるようにしたいと思います。
よく必要になるセクション区切りをつけます。

```kotlin
        val items = listOf(
                "地球連邦軍" to listOf("ジム", "ガンキャノン", "陸戦型ガンダム"),
                "ジオン公国軍" to listOf("ザク", "ギャン", "イフリート改"))
```

具体的にはこのリストを表示します。
それぞれxx軍をセクションヘッダーにします。

ではヘッダーとなるレイアウトを作成します。

```kotlin
internal class LitItem(text: String = "") : TextListItem(text)

internal class SectionHeaderItem(text: String = "") : TextListItem(text) {
    override fun createView(ui: AnkoContext<AnkoListAdapter>) = createTextView(ui) {
        gravity = Gravity.CENTER_VERTICAL
        padding = dip(10)
        textColor = Color.BLUE
        backgroundColor = Color.GRAY
        textSize = 17f
    }
}
```

通常に`ListItem`はこれで先ほど実装した`TextListItem`のままでオッケー（という判断）
セクションヘッダーはそのままだと困るので新たにViewを作ります。継承して実装。バックグラウンドにカラーを付けて文字サイズを大きくしてみました。よさそう。

```kotlin
    protected abstract val listItems: List<Class<out ListItem>>
```

`out`修飾子がついているので型安全にListItemに移行？することができます。

作ったviewをlistItemsに渡します。

```kotlin
internal class MSListAdapter(context: Context, items: List<ListItem>) : AnkoListAdapter(context, items) {
    override val listItems = listOf(SectionHeaderItem::class.java, LitItem::class.java)
}
```

おっけー。
あとはこのadapterをセットするだけで表示されるわけです。

`CustomView`の実装が非常に簡単かつ横にいるので非常に見通しがいいです。
また、Javaではできなかった簡単なコレクション操作がkotlinのおかげでできるので見通しもいいわけです。

# 終わりに

本日のサンプルコードはこちらにあります。
[こちら！！！！](https://github.com/SasakiYuki/AnkoChan)
以上でAnkoの紹介を終わります。
また自分の中で使っていって面白い発見やサンプルになりそうなものがあれば書きたいと思っています。