よくあるListViewの最終セルに次のN件の読み込み的なやつ。ページネーションと読んでいいのかどうか。
Activity
class MainActivity : AppCompatActivity() { lateinit var myListView:ListView lateinit var myAdapter:MyAdapter val listItems = ArrayList<String>() var columnIndex = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) //listItemの追加 addItem() myListView = findViewById<ListView>(R.id.postsListView) myAdapter = MyAdapter(this, listItems) myListView.adapter = myAdapter } private fun addItem(){ listItems.add( columnIndex.toString() ) columnIndex++ } public fun loadNextItem(){ addItem() //itemの変更をadapterに通知 myAdapter.notifyDataSetChanged() } }
Adapter
ViewHolder
private class ViewHolder(view: View) { val name = view.findViewById<TextView>(R.id.name) }
各セルになるViewの作成メソッド
itemセルはlist_item_cell.xml、次へのセルはlist_next_cell.xmlにlayout定義されているものとする。
次へのセルとなるViewにもタグをつけておくとgetView()時に再利用されるconvertViewの識別に利用できる。
mainActivity.loadNextItem()
のnotifyDataSetChanged()
はthis.notifyDataSetChanged()
としてもこのケースでは動作するが、ほとんどのケースでは別スレッドから取得したデータをUIスレッドに渡すと思うので、Activity側でadapterに通知するほうがハマりどころが少ない。
class MyAdapter( val context:Context, val items: ArrayList<String> ) :BaseAdapter() { private val inFlater = LayoutInflater.from(context) private fun makeNextView(parent: ViewGroup?):View{ val view = inFlater.inflate(R.layout.list_next_cell, parent, false) view.tag = "nextView" view.setOnClickListener { val mainActivity = context as MainActivity mainActivity.loadNextItem() } return view } private fun createView(parent: ViewGroup?):View{ val view = inFlater.inflate(R.layout.list_item_cell, parent, false) view.tag = ViewHolder(view) return view } }
getCount()
getCount()
は次へセルの分を足してreturnする
override fun getCount(): Int { return items.size + 1 }
getView()
positionがitems配列の終端に達した時はページネーションセルを返す。
またconvertViewが次へになるセルのリサイクルになる時がある為、セットされたタグで再利用可能であるViewか確認を行う。
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { //ページネーションセル if(items.size <= position){ return makeNextView(parent) } //コンテンツセル var view = convertView ?: createView(parent) if(view.tag == "nextView"){ view = createView(parent) } val viewHolder = view.tag as ViewHolder viewHolder.name.text = items[position].title return view }
MyAdapter
上記を記述したAdapterクラス
class MyAdapter( val context:Context, val items: ArrayList<String> ) :BaseAdapter() { private val inFlater = LayoutInflater.from(context) private class ViewHolder(view: View) { val name = view.findViewById<TextView>(R.id.name) } private fun makeNextView(parent: ViewGroup?):View{ val view = inFlater.inflate(R.layout.list_next_cell, parent, false) view.tag = "nextView" view.setOnClickListener { val mainActivity = context as MainActivity mainActivity.loadNextItem() } return view } private fun createView(parent: ViewGroup?):View{ val view = inFlater.inflate(R.layout.list_item_cell, parent, false) view.tag = ViewHolder(view) return view } override fun getCount(): Int { return items.size + 1 } override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { //ページネーションセル if(items.size <= position){ return makeNextView(parent) } //コンテンツセル var view = convertView ?: createView(parent) if(view.tag == "nextView"){ view = createView(parent) } val viewHolder = view.tag as ViewHolder viewHolder.name.text = items[position].title return view } }
実際にIDEで記述して実行したわけではないので、ところどころTypoだったり、足りないところがあるかもしれません。
リンク
リンク