使用 RecyclerView 建立動態清單 Android Jetpack 的一部分。
藉由 RecyclerView,您可以輕鬆有效地顯示大型資料集。由您提供資料並定義每個項目的外觀,而 RecyclerView 程式庫則會在需要時動態建立元素。
顧名思義,RecyclerView 就是回收個別元素。當向下捲動螢幕而未顯示項目時,RecyclerView 並不會刪除其檢視畫面。只不過,RecyclerView 會重複使用捲動螢幕後顯示新項目的檢視畫面。RecyclerView 可改善效能和應用程式的回應速度,並降低耗電量。
主要類別
有數種不同的類別可建立動態清單。
RecyclerView
是ViewGroup
,包含對應至資料的檢視表。其本身是檢視畫面,因此您可以在版面配置中新增RecyclerView
,方法和加入其他 UI 元素相同。清單中的每個個別元素都是由「檢視容器」物件定義。建立檢視容器時,沒有任何相關聯的資料。建立檢視容器後,
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 程式庫提供三個版面配置管理工具,可用於處理最常見的版面配置情境:
LinearLayoutManager
會在一個維度清單中排列項目。GridLayoutManager
會將項目排列成二維格線:- 如果網格是垂直排列的,
GridLayoutManager
會嘗試讓每個資料列中的所有元素具有相同的寬度和高度,但不同的資料列高度不同。 - 如果格線已水平排列,
GridLayoutManager
會嘗試讓每個資料欄的所有元素具有相同的寬度和高度,但不同資料欄寬度不同。
- 如果網格是垂直排列的,
StaggeredGridLayoutManager
與GridLayoutManager
類似,但不要求一列中的項目高度 (適用於垂直網格) 或同一欄中的項目寬度相同 (適用於水平格線)。因此,資料列或資料欄中的項目可能會相互偏移。
此外,您也必須設計個別項目的版面配置。設計檢視區塊容器時,需要使用這個版面配置,詳情請見下一節。
實作轉接程式和檢視容器
決定版面配置後,請實作 Adapter
和 ViewHolder
。這兩個類別會一起運作,以定義資料的顯示方式。ViewHolder
是 View
的包裝函式,其中包含清單中個別項目的版面配置。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.layoutManager = LinearLayoutManager(this) recyclerView.adapter = customAdapter } }
Java
RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.layoutManager = new LinearLayoutManager(this) recyclerView.setAdapter(customAdapter);
這個程式庫也提供許多自訂實作方法。詳情請參閱「進階 RecyclerView 自訂功能」。
其他資源
如要進一步瞭解如何在 Android 裝置上測試,請參閱下列資源。