使用 RecyclerView 建立動態清單 Android Jetpack 的一部分。

嘗試 Compose 方法
Jetpack Compose 是 Android 推薦的 UI 工具包。瞭解如何在 Compose 中處理版面配置。

藉由 RecyclerView,您可以輕鬆有效地顯示大型資料集。由您提供資料並定義每個項目的外觀,而 RecyclerView 程式庫則會在需要時動態建立元素。

顧名思義,RecyclerView 就是回收個別元素。當向下捲動螢幕而未顯示項目時,RecyclerView 並不會刪除其檢視畫面。反之,RecyclerView 會重複使用捲動畫面的新項目的檢視畫面。RecyclerView 可提升效能和應用程式回應速度,並降低耗電量。

主要類別

有幾個類別可以共同建立動態清單。

  • RecyclerViewViewGroup,包含對應至資料的檢視表。本身是檢視畫面,因此您可以在版面配置中新增 RecyclerView,方法和加入任何其他 UI 元素相同。

  • 清單中的每個個別元素都是由「檢視容器」物件定義。建立檢視容器時,沒有任何相關聯的資料。建立檢視容器後,RecyclerView 就會將該資料繫結至其資料。您可以藉由擴充 RecyclerView.ViewHolder 來定義檢視容器。

  • RecyclerView 會要求檢視畫面,並透過轉接程式呼叫方法,將檢視畫面繫結至其資料。擴充 RecyclerView.Adapter 即可定義轉接程式。

  • 版面配置管理員會排列清單中的個別元素。您可以使用 RecyclerView 程式庫提供的其中一個版面配置管理員,也可以定義自己的版面配置。版面配置管理員都是以程式庫的 LayoutManager 抽象類別為基礎。

您可以在 RecyclerView 範例應用程式 (Kotlin)RecyclerView 範例應用程式 (Java) 中查看所有元件如何搭配運作。

實作 RecyclerView 的步驟

如要使用 RecyclerView,您需要完成幾個步驟。詳情請見後續章節。

  1. 決定清單或格線的外觀。一般來說,您可以使用 RecyclerView 程式庫的標準版面配置管理工具。

  2. 設計清單中的每個元素外觀和行為。根據這個設計,擴充 ViewHolder 類別。您的 ViewHolder 版本提供清單項目的所有功能。檢視容器是 View 的包裝函式,而該檢視畫面由 RecyclerView 管理。

  3. 定義將資料與 ViewHolder 檢視畫面相關聯的 Adapter

您也可以使用進階自訂選項,依據自己的需求自訂 RecyclerView。

規劃版面配置

RecyclerView 中的項目是由 LayoutManager 類別排列。RecyclerView 程式庫提供三個版面配置管理工具,可用於處理最常見的版面配置情境:

  • LinearLayoutManager 會在一個維度清單中排列項目。
  • GridLayoutManager 會在二維格線中排列項目:
    • 如果網格是垂直排列的,GridLayoutManager 會嘗試讓每個資料列中的所有元素具有相同的寬度和高度,但不同的資料列高度不同。
    • 如果格線已水平排列,GridLayoutManager 會嘗試讓每個資料欄的所有元素具有相同的寬度和高度,但不同資料欄寬度不同。
  • StaggeredGridLayoutManagerGridLayoutManager 類似,但不要求一列中的項目高度 (適用於垂直網格) 或同一欄中的項目寬度相同 (適用於水平格線)。因此,資料列或資料欄中的項目可能會相互偏移。

此外,您也需要設計個別項目的版面配置。設計檢視容器時,您需要這個版面配置,如下一節所述。

實作轉接程式和檢視容器

決定版面配置後,您需要實作 AdapterViewHolder。這兩個類別會一起運作,以定義資料的顯示方式。ViewHolderView 的包裝函式,其中包含清單中個別項目的版面配置。Adapter 會視需要建立 ViewHolder 物件,並設定這些檢視畫面的資料。將檢視畫面與資料建立關聯的程序稱為「繫結」

定義轉接器時,您將覆寫三種主要方法:

  • onCreateViewHolder():每當需要建立新的 ViewHolder 時,RecyclerView 都會呼叫這個方法。這個方法會建立及初始化 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.adapter = customAdapter

    }

}

Java


RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setAdapter(customAdapter);

程式庫也提供多種自訂實作方式。詳情請參閱「進階 RecyclerView 自訂功能」。

其他資源

如要進一步瞭解如何在 Android 裝置上測試,請參閱下列資源。

範例應用程式