ListViewに挑む!表示編

Android初心者の墓場、またはAndroid開発者かそうでないかを分ける試金石、ListViewに挑みます。 二回に分けて作業していきます。前篇のここでは、リストのデータを表示する事にチャレンジ。

概要動画と作業動画

さっぱり分からん、と言われたので、登場人物を説明する程度の、概要動画を作った。

また、今回の作業を実際にやってみる作業動画を作ったので合わせてどうぞ。

第一段階: 素のsimple_list_item_1を使って表示する

まずはアイテムのカスタマイズを一切行わない表示から。

ListView一段階目のスクリーンショット

メンバ変数の雑な説明と表示するデータ

最初、新規のプロジェクトを作ると以下のようなコードがあります。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

このonCreateの外に定義する変数をメンバ変数といいます。(メンバ変数が何かはクラスの話が必要になってくるので、現時点ではこの説明で納得してください)

例えば、以下のlistDataはメンバ変数です。

    val listData = listOf("1つ目のアイテム", "2つ目のアイテム", "3つ目のアイテム", "4つ目のアイテム", "5つ目のアイテム")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

以後、「メンバ変数としてXXを定義してください」と言ったら、このonCreateの外に変数XXを定義する、と理解してください。

ここから先はこのlistDataを表示するのを目指します。

ListViewをレイアウトに置く

Layout側にListViewを置き、idをlistViewにする

画面いっぱいになるようにする。

メンバ変数にArrayAdapterをlazyで作る

adapterをメンバ変数として定義します。ただし、ちょっと特殊な事があるので、以下のコードをそのまま写してください。(場所はメンバ変数のところ)

val adapter by lazy { ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listData) }

by lazyじゃないとこのタイミングではまだLayoutInflaterは使えん(getSystemServiceをonCreateの前に呼ぶな)、と言われて落ちる。

githubのAOSPミラーのsimple_list_item_1.xml

showMessageを作る

以下はListViewとは関係ないのですが、今後もちょくちょく使うのでshowMessageを作っておきます。 JS入門のMessageBox.showと似たものです。

関数の説明をするところまで来たら詳細を説明するので、今は下のコードをコピペしておいてください。 ただし、onCreateの外にコピペします(メンバ変数と同じあたり)

fun showMessage(msg: String) { Toast.makeText(this, msg, Toast.LENGTH_LONG).show() }

onCreateでListViewにadapterをセットしてitemのクリックリスナーを作る

ListViewをfindVewByIdで取り出して、adapterとsetOnItemClickListenerをセットします。

findViewById<ListView>(R.id.listView).adapter = adapter

onCreateでListViewにitemのクリックリスナーを作る

findViewById<ListView>(R.id.listView).setOnItemClickListener { parent, view, position, id ->
    val selectedText = view.findViewById<TextView>(android.R.id.text1).text.toString()
    showMessage("${selectedText}が選ばれました")
}

課題: listDataをMutableListにして100件くらい何か文字列を入れる

ListViewはスクロールする方が何なのか分かりやすいので、

  1. listDataをMutableListにする
  2. onCreateの中で100件くらい何か詰める

という事をやりましょう。

第二段階: 自分のレイアウトを定義する

自分のレイアウトを差し替える方法を学ぶ。

ListView二段階目のスクリーンショット

新しいレイアウトを定義して、以下の要件を満たすようにする

  • ファイル名はlist_item.xml
  • トップはLinearLayout
  • TextViewを置く、idはitemLabelとする
  • Buttonを置く、idはitemButtonとする、textは”ボタン”とかかな(なんでもいい)

ArrayAdapterのgetViewを差し替える

val adapter by lazy { object: ArrayAdapter<String>(this, R.layout.list_item, listData) {
            override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
                val view = if(convertView == null) layoutInflater.inflate(R.layout.list_item, null) else convertView

                val data = listData[position]
                view.findViewById<TextView>(R.id.itemLabel).text = data
                return view
            }
        }
    }

なお、getViewをoverrideするので本当はコンストラクタのR.layout.list_itemはなんでも良い(使わないので)。

ここは一番意味不明な所だと思うので、解説動画を作りました。 何回か作業をした後に見てみてください。

onCreateの方のsetOnItemClickListenerを消す

getViewをオーバーライドしたらこちらは不要になるので消します。

ボタンが押された時の処理も書いてみる

getViewの中で、以下みたいな感じで何か書く(showMessageでアイテムの内容を使った何かを表示するのがいいかもしれない)

    view.findViewById<Button>(R.id.itemButton).setOnClickListener = ...