ListViewやRecycleViewの作成は手順がそれなりに多く忘れがちになります。
ただ最近はLiveDataやDataBindingが出てきて少し楽になりました。
私は現時点でこんな感じで作っていますが、もっと良い方法があると思うので随時ブラッシュアップしていきたいです。
※Activityクラスとレイアウト、Fragmentクラスとレイアウト、ViewModelクラスがあることが前提です。無い場合は別途用意が必要です。
目次
- 1 ①Fragmentのレイアウトをlayoutタグで囲む
- 2 ②バインディング変数にViewModelを定義
- 3 ③レイアウトにListView追加
- 4 ④リストに表示する内容でデータクラスを作成
- 5 ⑤ListView1行分のレイアウトを作成する
- 6 ⑥リストに表示するデータを入れるLiveDataを用意
- 7 ⑦リストに表示するデータを作成しLiveDataに追加するメソッド作成
- 8 ⑧ListView用のAdapter作成
- 9 ⑨Fragmentの.onActivityCreated()メソッドで⑧のAdapterをListViewにセット
- 10 ⑩Activityで⑥で用意したLiveDataをsubscribe
- 11 ⑪FragmentのonResume()メソッドで⑦のメソッドを呼びLiveDataにデータを入れる
- 12 ⑫LiveDataにデータが入ったらsubscribeしているActivityにデータ変更の通知が届くのでAdapterに渡す
①Fragmentのレイアウトをlayoutタグで囲む
DataBindingを使用するために必要です。
1 2 3 4 5 6 7 8 9 10 |
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" tools:context=".list.ListFragment"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> </androidx.constraintlayout.widget.ConstraintLayout> </layout> |
②バインディング変数にViewModelを定義
dataタグ内のvariableタグ部分です。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" tools:context=".list.ListFragment"> <data> <variable name="listViewModel" type="info.mukaiyachi.demoapp.list.ListViewModel"/> </data> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> </androidx.constraintlayout.widget.ConstraintLayout> </layout> |
③レイアウトにListView追加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" tools:context=".list.ListFragment"> <data> <variable name="listViewModel" type="info.mukaiyachi.demoapp.list.ListViewModel"/> </data> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/item_list" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout> </layout> |
④リストに表示する内容でデータクラスを作成
1 |
data class ListData(val itemName: String?) |
⑤ListView1行分のレイアウトを作成する
■Fragmentと同じ様にレイアウトlayoutタグで囲みます。
■バインディング変数には④のデータクラスを定義します。
■TextViewのtextはDataBindingで渡します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="listData" type="info.mukaiyachi.demoapp.list.ListData"/> </data> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:text="@{listData.itemName}" android:layout_gravity="center_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/black" android:textSize="28sp"/> </LinearLayout> </layout> |
⑥リストに表示するデータを入れるLiveDataを用意
1 2 3 4 5 |
class ListViewModel : ViewModel() { private val _listItems = MutableLiveData<List<ListData>>() val listItems: LiveData<List<ListData>> get() = _listItems } |
⑦リストに表示するデータを作成しLiveDataに追加するメソッド作成
1 2 3 4 5 6 7 8 9 10 |
fun loadItemData() { val fruitsList = arrayListOf( ListData("りんご"), ListData("みかん"), ListData("れもん"), ListData("ばなな"), ListData("めろん") ) _listItems.value = fruitsList } |
⑧ListView用のAdapter作成
■⑤のレイアウトで定義したバインディング変数にはAdapterに渡ってきたデータクラスを入れます。
■executePendingBindings()メソッドで入れたデータをBindingオブジェクトに即反映させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
class ListDataAdapter( private var listDatas: List<ListData> ) : BaseAdapter() { override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { val binding = if (convertView == null) { // Binding作成 val inflater = LayoutInflater.from(parent.context) ListItemBinding.inflate(inflater, parent, false) } else { DataBindingUtil.getBinding(convertView) ?: throw IllegalStateException() } with(binding) { listData = listDatas[position] // Bindingオブジェクトに即反映 executePendingBindings() } return binding.root } fun replaceData(listDatas: List<ListData>) { this.listDatas = listDatas } override fun getItem(position: Int) = listDatas[position] override fun getItemId(position: Int) = position.toLong() override fun getCount() = listDatas.size } |
⑨Fragmentの.onActivityCreated()メソッドで⑧のAdapterをListViewにセット
1 2 3 4 5 6 7 8 9 10 11 |
override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) // ListViewにAdapterをセット val listViewModel = viewDataBinding.listViewModel if (listViewModel != null) { // ViewModelがDataBindingに存在する場合のみ listDataAdapter = ListDataAdapter(ArrayList(0)) viewDataBinding.itemList.adapter = listDataAdapter } } |
⑩Activityで⑥で用意したLiveDataをsubscribe
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class ListActivity : AppCompatActivity() { private lateinit var listViewModel: ListViewModel fun obtainViewModel(): ListViewModel = obtainViewModel(ListViewModel::class.java) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_list) supportFragmentManager.findFragmentById(R.id.content) ?: replaceFragmentInActivity(ListFragment.newInstance(), R.id.content) subscribeLiveData() } // ViewModel内のLiveDataをsubscribe private fun subscribeLiveData() { listViewModel = obtainViewModel(ListViewModel::class.java).apply { listItems.observe(this@ListActivity, Observer { data -> }) } } } |
⑪FragmentのonResume()メソッドで⑦のメソッドを呼びLiveDataにデータを入れる
1 2 3 4 5 6 |
override fun onResume() { super.onResume() // リストに表示する内容を作成 viewModel.loadItemData() } |
⑫LiveDataにデータが入ったらsubscribeしているActivityにデータ変更の通知が届くのでAdapterに渡す
1 2 3 4 5 6 7 8 9 |
// ViewModel内のLiveDataをsubscribe private fun subscribeLiveData() { listViewModel = obtainViewModel(ListViewModel::class.java).apply { listItems.observe(this@ListActivity, Observer { data -> val adapter = item_list.adapter as ListDataAdapter adapter.replaceData(data) }) } } |
これでアプリの画面にデータ含まれたListViewが表示されます。
その後ListViewの内容を変えたい場合は、表示したいデータを⑥のLiveDataに入れてあげればOKです。