出力データの作成
型を定義する
RecleViewのリストを表示するためには、まずは表示する!
データの型を定義いたします。
//Affirmation.kt
package com.example.affirmaiton.model
import androidx.annotation.DrawableRes
import androidx.annotation StringRes
data class Affirmation(
@StringRes val stringResourceId: Int,
@DrawableRes val image ResourceId: Int
)
Affirmationという型を作って、中にはtextidとimageidを作成する
形式を整える
アプリによって様々なデータ表示形式があリます
例えば、インターネットに接続し、外部データを取り込むような場合、必要な形式になっていない場合があります。
そのために、データを適切な型に変換するDatasourceクラスを作成します
Datasource.ktクラスを作成します
// Datasource.kt
package com.example.affirmations.data
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation
class Datasource {
fun loadAffirmations(): List<Affirmation>{
return listOf<Affirmation>(
Affirmation(R.string.affirmation1, R.drawable.image1),
Affirmation(R.string.affirmation2, R.drawable.image2),
Affirmation(R.string.affirmation3, R.drawable.image3),
Affirmation(R.string.affirmation4, R.drawable.image4),
Affirmation(R.string.affirmation5, R.drawable.image5),
Affirmation(R.string.affirmation6, R.drawable.image6),
Affirmation(R.string.affirmation7, R.drawable.image7),
Affirmation(R.string.affirmation8, R.drawable.image8),
Affirmation(R.string.affirmation9, R.drawable.image9),
Affirmation(R.string.affirmation10, R.drawable.image10)
)
}
}
Datasourceクラスは先ほど作成したAffirmationという型をリスト形式で返却します。
データの準備完了!
RecyleView XML
外観から入りましょう。
使用箇所のイメージ
RecycleViewのレイアウトはまずこんな感じ
リスト形式で表示する大枠的なイメージです
// actibity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:layoutManager="LinearLayoutManager" />
</FrameLayout>
スクロールを可能にするために、android:scrollbars="vertical"
を記載
またRecycleViewはグリッドだったり、リストだったり表示できるようで、リストにして表示する場合はapp:layoutManager="LinearLayoutManager"
を記載したりします。
list_item.xmlについて
list_item.xmlはリストで表示する子アイテムの1個についてです。
以下のイメージはカードビューで、カード内上部に画像、その下にテキストが描かれているイメージです。
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="194dp"
android:id="@+id/item_image"
android:importantForAccessibility="no"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:textAppearance="?attr/textAppearanceHeadline6"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
imageのidはitem_image、textのidはitem_titleとします。
どちらもここで定義するもののため、@+id/item_imageのように+をつけるのを忘れないようにすること
CartView、LinearLayout、ImageViewでは横いっぱいに表示するため、
android:layout_width=”match_parent” とします。
これにて、データの中身と、側の作成が完了しました。
次はデータの中身と側をつなげるAdapterについて見ていきます。
Adapterの実装
Androidではリスト表示にする場合、リストデータと表示の間にAdapterが必要になります。
ItemAdapter.ktクラスを作成します。
結論からいうと、下記のようになります。
// ItemAdapter.kt
package com.example.affirmations.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation
class ItemAdapter (
private val context: Context,
private val dataset: List<Affirmation>
) : RecyclerView.Adapter<ItemAdapter.ItemViewHolder>() {
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder.
// Each data item is just an Affirmation object.
class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.item_title)
val imageView: ImageView = view.findViewById(R.id.item_image)
}
/**
* Create new views (invoked by the layout manager)
*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
// create a new view
val adapterLayout = LayoutInflater.from(parent.context)
.inflate(R.layout.list_item, parent, false)
return ItemViewHolder(adapterLayout)
}
/**
* Replace the contents of a view (invoked by the layout manager)
*/
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val item = dataset[position]
holder.textView.text = context.resources.getString(item.stringResourceId)
holder.imageView.setImageResource(item.imageResourceId)
}
/**
* Return the size of your dataset (invoked by the layout manager)
*/
override fun getItemCount() = dataset.size
}
MainActivityでは上記で作成したadapterを下記のように実装します。
// MainActivity.kt
package com.example.affirmations
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import com.example.affirmations.data.Datasource
import com.example.affirmations.adapter.ItemAdapter
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Initialize data.
val myDataset = Datasource().loadAffirmations()
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
recyclerView.adapter = ItemAdapter(this, myDataset)
// Use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
recyclerView.setHasFixedSize(true)
}
}
大雑把ですが以下のイメージです。
①myDataset変数にloadAffirmation()より、リスト形式のAffirmationデータを代入します。
②recyclerView変数に、 XMLで定義したRecycleViewを代入します。
③recylerView.adapterに ItemAdapter(this, mydataset)を適用し、データの接合を行います。
ちなみにここのthisはActivityを継承しているクラスのContextを取得するためのthisらしいです。
調べたところ、thisにもパターンが2種類存在するようです。
Adapter処理を詳しく見ていく
上記のソースを見るとItemAdapterはRecyclerView.Adapterを拡張しているものということがわかります。
(class ItemAdapterがRecyclerView.Adapter()を引き継いでいる)
拡張したメソッドはItemViewHolder、getItemCount、onBindViewHolderの3つです。
getItemCount
getItemCount()には適切なデータサイズを返却する必要があります。
override fun getItemCount(): Int {
return dataset.size
}
onCreateViewHolder
onCreateViewHolder()メソッドは、RecyclerViewの新しいViewHolderを作成する際に呼び出されます。
自作したビューホルダーを作り直すっていうイメージです。
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
// create a new view
val adapterLayout = LayoutInflater.from(parent.context)
.inflate(R.layout.list_item, parent, false)
return ItemViewHolder(adapterLayout)
}
onBindViewHolder
onBindViewHolder()はリストアイテムビューにコンテンツを置き換えるために呼び出されるようです。
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val item = dataset[position]
holder.textView.text = context.resources.getString(item.stringResourceId)
holder.imageView.setImageResource(item.imageResourceId)
}
まとめ
うーん、正直難しいですね。。。
ちょっと触れただけでここまでなのに、しっかりと活用するためにはもうちょっと理解が必要そうです。
最後にonBindViewHopderのオーバーライドで画像を適切にセットしてあげてください。
参考までに、RecyclerViewについては下記のような図がわかりやすいために引用する
コメント