RecyclerView で動的リストを作成する Android Jetpack の一部。
RecyclerView を使用すると、大規模なデータセットを簡単かつ効率的に表示できます。データを指定し、各アイテムの表示方法を定義すると、必要に応じて、RecyclerView ライブラリが動的に要素を作成します。
RecyclerView は、その名のとおり、これらの個々の要素をリサイクルします。アイテムが画面外にスクロールされても、RecyclerView はビューを破棄せず、画面上にスクロールされた新しいアイテムのビューを再利用します。RecyclerView は、パフォーマンスとアプリの応答性を向上させ、消費電力を削減します。
主なクラス
複数のクラスが連携して動的リストをビルドします。
RecyclerViewは、データに対応するビューを含むViewGroupです。これはビュー自体であるため、他の UI 要素と同じようにRecyclerViewをレイアウトに追加できます。リスト内の各要素はビューホルダー オブジェクトによって定義されます。ビューホルダーは、作成されるときにデータが関連付けられることはありません。ビューホルダーは、作成された後で
RecyclerViewによってそのデータにバインドされます。ビューホルダーを定義するには、RecyclerView.ViewHolderを拡張します。RecyclerViewは、アダプターのメソッドを呼び出し、ビューをリクエストしてそのデータにビューをバインドします。アダプターを定義するには、RecyclerView.Adapterを拡張します。レイアウト マネージャーによって、リスト内の個々の要素が配置されます。RecyclerView ライブラリによって提供されるレイアウト マネージャーを使用することも、独自のレイアウト マネージャーを定義することもできます。レイアウト マネージャーはいずれも、ライブラリの
LayoutManager抽象クラスに基づいています。
すべての要素が連携している状態については、RecyclerView サンプルアプリ(Kotlin)または RecyclerView サンプルアプリ(Java)をご覧ください。
RecyclerView を実装する手順
RecyclerView を使用する場合は、いくつかの手順が必要になります。詳細については、以降のセクションで説明します。
リストやグリッドの外観を決めます。通常、RecyclerView ライブラリの標準レイアウト マネージャーを使用できます。
リストの各要素の表示方法や動作方法を設計します。この設計に基づいて、
ViewHolderクラスを拡張します。ViewHolderのバージョンでは、リスト項目のすべての機能が提供されます。ビューホルダーはViewのラッパーであり、そのビューはRecyclerViewによって管理されます。データを
ViewHolderビューに関連付けるAdapterを定義します。
また、RecyclerView をニーズに合わせて的確に調整できる高度なカスタマイズ オプションも用意されています。
レイアウトの計画
RecyclerView のアイテムは LayoutManager クラスによって並べ替えられます。RecyclerView ライブラリには 3 つのレイアウト マネージャーがあり、レイアウトの標準的な状況を処理します。
LinearLayoutManagerは 1 次元のリスト内にアイテムを配置します。GridLayoutManagerは、次の 2 次元グリッド内にあるアイテムを配置します。- グリッドが垂直方向に配置されている場合、
GridLayoutManagerは各行のすべての要素が同じ幅と高さになるようにしますが、行ごとに異なる高さを指定することもできます。 - グリッドが水平方向に配置されている場合、
GridLayoutManagerは各列のすべての要素の幅と高さが同じになるようにしますが、列ごとに異なる幅を指定することもできます。
- グリッドが垂直方向に配置されている場合、
StaggeredGridLayoutManagerはGridLayoutManagerと似ていますが、行のアイテムの高さが同じである必要もなく(垂直グリッドの場合)、同じ列のアイテムの幅が同じである必要もありません(水平グリッドの場合)。結果として、行または列内のアイテムが互いにオフセットされることになります。
また、個々のアイテムのレイアウトも設計する必要があります。このレイアウトは、ビューホルダーを設計する際に必要になります。次のセクションで説明します。
アダプタとビューホルダーを実装する
レイアウトが決まったら、Adapter と ViewHolder を実装する必要があります。これら 2 つのクラスが連携して、データの表示方法を定義します。ViewHolder は、リスト内の各アイテムのレイアウトを含む View のラッパーです。Adapter は、必要に応じて ViewHolder オブジェクトを作成するとともに、これらのビューのデータを設定します。ビューをこれらのデータに関連付けるプロセスは、バインディングと呼ばれます。
アダプターを定義する際は、次の 3 つの主要なメソッドをオーバーライドします。
onCreateViewHolder():RecyclerViewは、新しいViewHolderを作成する必要があるたびにこのメソッドを呼び出します。このメソッドは、ViewHolderとそれに関連するViewを作成して初期化しますが、ビューのコンテンツは埋めません(ViewHolderはこの時点で特定のデータにバインドされていません)。onBindViewHolder():RecyclerViewはこのメソッドを呼び出して、ViewHolderをデータに関連付けます。このメソッドは適切なデータを取得し、そのデータを使用してビューホルダーのレイアウトを埋めます。たとえば、RecyclerViewが名前のリストを表示する場合、このメソッドはリストの中から適切な名前を見つけて、ビューホルダーのTextViewウィジェットを埋めます。getItemCount():RecyclerViewはこのメソッドを呼び出して、データセットのサイズを取得します。たとえば、アドレス帳アプリの場合、このデータセットのサイズは住所の合計数になります。RecyclerView はこの情報を使用して、表示できるアイテムがほかにないかどうかを判断します。
次に、ネストされ、データのリストを表示する ViewHolder を持つ簡単なアダプターの典型的な例を示します。この例では、RecyclerView はテキスト要素の簡単なリストを表示しています。アダプターには、ViewHolder 要素のテキストを含む文字列の配列が渡されます。
Kotlin
class CustomAdapter(private val dataSet: Array<String>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() { /** * Provide a reference to the type of views that you are using * (custom ViewHolder) */ class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { val textView: TextView init { // Define click listener for the ViewHolder's View textView = view.findViewById(R.id.textView) } } // Create new views (invoked by the layout manager) override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder { // Create a new view, which defines the UI of the list item val view = LayoutInflater.from(viewGroup.context) .inflate(R.layout.text_row_item, viewGroup, false) return ViewHolder(view) } // Replace the contents of a view (invoked by the layout manager) override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) { // Get element from your dataset at this position and replace the // contents of the view with that element viewHolder.textView.text = dataSet[position] } // Return the size of your dataset (invoked by the layout manager) override fun getItemCount() = dataSet.size }
Java
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> { private String[] localDataSet; /** * Provide a reference to the type of views that you are using * (custom ViewHolder) */ public static class ViewHolder extends RecyclerView.ViewHolder { private final TextView textView; public ViewHolder(View view) { super(view); // Define click listener for the ViewHolder's View textView = (TextView) view.findViewById(R.id.textView); } public TextView getTextView() { return textView; } } /** * Initialize the dataset of the Adapter * * @param dataSet String[] containing the data to populate views to be used * by RecyclerView */ public CustomAdapter(String[] dataSet) { localDataSet = dataSet; } // Create new views (invoked by the layout manager) @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { // Create a new view, which defines the UI of the list item View view = LayoutInflater.from(viewGroup.getContext()) .inflate(R.layout.text_row_item, viewGroup, false); return new ViewHolder(view); } // Replace the contents of a view (invoked by the layout manager) @Override public void onBindViewHolder(ViewHolder viewHolder, final int position) { // Get element from your dataset at this position and replace the // contents of the view with that element viewHolder.getTextView().setText(localDataSet[position]); } // Return the size of your dataset (invoked by the layout manager) @Override public int getItemCount() { return localDataSet.length; } }
各ビューアイテムのレイアウトは、通常どおり XML レイアウト ファイルで定義されます。この場合、アプリの text_row_item.xml ファイルは次のようになります。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
android:layout_marginLeft="@dimen/margin_medium"
android:layout_marginRight="@dimen/margin_medium"
android:gravity="center_vertical">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/element_text"/>
</FrameLayout>
次のステップ
次のコード スニペットは、RecyclerView の使用方法を示しています。
Kotlin
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val dataset = arrayOf("January", "February", "March") val customAdapter = CustomAdapter(dataset) val recyclerView: RecyclerView = findViewById(R.id.recycler_view) recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.adapter = customAdapter } }
Java
RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.layoutManager = new LinearLayoutManager(this) recyclerView.setAdapter(customAdapter);
このライブラリには、実装をカスタマイズするためのさまざまな方法も用意されています。詳細については、高度な RecyclerView のカスタマイズをご覧ください。
エッジ ツー エッジ表示を有効にする
RecyclerView でエッジ ツー エッジ ディスプレイを有効にする手順は次のとおりです。
enableEdgeToEdge()を呼び出して、下位互換性のあるエッジ ツー エッジ表示を設定します。- リストアイテムが最初にシステムバーと重なっている場合は、
RecyclerViewにインセットを適用します。これを行うには、android:fitsSystemWindowsをtrueに設定するか、ViewCompat.setOnApplyWindowInsetsListenerを使用します。 RecyclerViewのandroid:clipToPaddingをfalseに設定して、スクロール中にリスト項目がシステムバーの下に描画されるようにします。
次の動画は、エッジ ツー エッジ ディスプレイが無効(左)と有効(右)の RecyclerView を示しています。
インセット コードの例:
Kotlin
ViewCompat.setOnApplyWindowInsetsListener( findViewById(R.id.my_recycler_view) ) { v, insets -> val innerPadding = insets.getInsets( WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() // If using EditText, also add // "or WindowInsetsCompat.Type.ime()" to // maintain focus when opening the IME ) v.setPadding( innerPadding.left, innerPadding.top, innerPadding.right, innerPadding.bottom) insets }
Java
ViewCompat.setOnApplyWindowInsetsListener( activity.findViewById(R.id.my_recycler_view), (v, insets) -> { Insets innerPadding = insets.getInsets( WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout() // If using EditText, also add // "| WindowInsetsCompat.Type.ime()" to // maintain focus when opening the IME ); v.setPadding( innerPadding.left, innerPadding.top, innerPadding.right, innerPadding.bottom ); return insets; } );
RecyclerView XML:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="match_parent" />
参考情報
Android でのテストの詳細については、次のリソースをご覧ください。