在 Android 設備上使用 RecyclerView 和 CardView 組合
Chinese (Traditional) (中文(繁體)) translation by Fuhuan (you can also view the original English article)
如果您有興趣構建壹個利用列表顯示數據的 Android 應用程序,Android Lollipop 具有兩個新的輕松構建該類應用的小部件:RecyclerView 和 CardView。 使用這些小部件,很容易讓您的應用程序的外觀和感覺符合 Google 材料設計規範中提及的準則。
前提條件
構建這樣的程序,您應該使用最新版本的 Android Studio。 妳可以從 Android 開發者網站獲得。
1. 支持舊版本
在寫作的時候,小於 2% 的 Android 設備運行 Android Lollipop 系統。 然而,幸虧 v7 支持庫 (Support Library),您可以在運行舊版本 Android 的設備上使用 RecyclerView 和 CardView 小部件,方法是將以下代碼添加到項目 build.grade 文件中的依賴項 (dependencies) 部分:
1 |
compile 'com.android.support:cardview-v7:21.0.+' |
2 |
compile 'com.android.support:recyclerview-v7:21.0.+' |
2. 創建 CardView
CardView 是壹個 ViewGroup. 像任何其他 ViewGroup 壹樣,它可以使用布局 XML 文件添加到您的 Activity 或 Fragment 中。
要創建壹個空的 CardView,您必須將以下代碼添加到布局 XML 中,如下代碼片段所示:
1 |
<android.support.v7.widget.CardView
|
2 |
xmlns:card_view="https://schemas.android.com/apk/res-auto" |
3 |
android:layout_width="match_parent" |
4 |
android:layout_height="wrap_content"> |
5 |
|
6 |
</android.support.v7.widget.CardView>
|
作為壹個更真實的例子,讓我們現在創建壹個 LinearLayout 並在其中放置壹個 CardView。 例如,CardView 可以代表壹個人,包含以下內容:
- 壹個 TextView 顯示的人的名字
- 壹個 TextView 顯示該人的年齡
- 壹個 ImageView 來顯示人的照片
XML 會是下面這樣子
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
3 |
android:layout_width="match_parent" android:layout_height="match_parent" |
4 |
android:padding="16dp" |
5 |
>
|
6 |
|
7 |
<android.support.v7.widget.CardView
|
8 |
android:layout_width="match_parent" |
9 |
android:layout_height="wrap_content" |
10 |
android:id="@+id/cv" |
11 |
>
|
12 |
|
13 |
<RelativeLayout
|
14 |
android:layout_width="match_parent" |
15 |
android:layout_height="wrap_content" |
16 |
android:padding="16dp" |
17 |
>
|
18 |
|
19 |
<ImageView
|
20 |
android:layout_width="wrap_content" |
21 |
android:layout_height="wrap_content" |
22 |
android:id="@+id/person_photo" |
23 |
android:layout_alignParentLeft="true" |
24 |
android:layout_alignParentTop="true" |
25 |
android:layout_marginRight="16dp" |
26 |
/>
|
27 |
|
28 |
<TextView
|
29 |
android:layout_width="wrap_content" |
30 |
android:layout_height="wrap_content" |
31 |
android:id="@+id/person_name" |
32 |
android:layout_toRightOf="@+id/person_photo" |
33 |
android:layout_alignParentTop="true" |
34 |
android:textSize="30sp" |
35 |
/>
|
36 |
|
37 |
<TextView
|
38 |
android:layout_width="wrap_content" |
39 |
android:layout_height="wrap_content" |
40 |
android:id="@+id/person_age" |
41 |
android:layout_toRightOf="@+id/person_photo" |
42 |
android:layout_below="@+id/person_name" |
43 |
/>
|
44 |
|
45 |
</RelativeLayout>
|
46 |
|
47 |
</android.support.v7.widget.CardView>
|
48 |
|
49 |
</LinearLayout>
|
如果此 XML 布局文件用作壹個 Activity 的布局,將 TextView 和 ImageView 填充上有意義的值,那麽在 Android 設備上選然後如下:



3. 創建 RecyclerView
步驟 1: 在布局中定義它
使用 RecyclerView 實例稍微更復雜壹點。 然而,在布局 XML 文件中定義它是相當簡單的. 您可以在布局中定義它,如下所示:
1 |
<android.support.v7.widget.RecyclerView
|
2 |
android:layout_width="match_parent" |
3 |
android:layout_height="match_parent" |
4 |
android:id="@+id/rv" |
5 |
/>
|
要在 Activity 中獲取句柄,請使用以下代碼段:
1 |
RecyclerView rv = (RecyclerView)findViewById(R.id.rv); |
如果您確定 RecyclerView 的 (item) 數目不會改變,您可以添加以下內容來改善性能:
1 |
rv.setHasFixedSize(true); |
步驟 2: 使用 LayoutManager
與 ListView 不同,RecyclerView 需要壹個 LayoutManager 來管理其條目 (item) 的位置。 您可以通過擴展 RecyclerView.LayoutManager 類來定義自己的 LayoutManager。 但是,在大多數情況下,您可以簡單地使用壹個預定義的 LayoutManager 子類:
LinearLayoutManagerGridLayoutManager- StaggeredGridLayoutManager
在本教程中,將使用 LinearLayoutManager。 默認情況下,此 LayoutManager 子類將使您的 RecyclerView 看起來像壹個 ListView。
1 |
LinearLayoutManager llm = new LinearLayoutManager(context); |
2 |
rv.setLayoutManager(llm); |
步驟 3:定義數據
就像 ListView 壹樣,RecyclerView 需要壹個適配器來訪問它的數據。 但在創建適配器之前,讓我們創建可以使用的數據。 創建壹個簡單的類來表示壹個人,然後編寫壹個初始化 Person 對象 List 的方法:
1 |
class Person { |
2 |
String name; |
3 |
String age; |
4 |
int photoId; |
5 |
|
6 |
Person(String name, String age, int photoId) { |
7 |
this.name = name; |
8 |
this.age = age; |
9 |
this.photoId = photoId; |
10 |
}
|
11 |
}
|
12 |
|
13 |
private List<Person> persons; |
14 |
|
15 |
// This method creates an ArrayList that has three Person objects
|
16 |
// Checkout the project associated with this tutorial on Github if
|
17 |
// you want to use the same images.
|
18 |
private void initializeData(){ |
19 |
persons = new ArrayList<>(); |
20 |
persons.add(new Person("Emma Wilson", "23 years old", R.drawable.emma)); |
21 |
persons.add(new Person("Lavery Maiss", "25 years old", R.drawable.lavery)); |
22 |
persons.add(new Person("Lillie Watts", "35 years old", R.drawable.lillie)); |
23 |
}
|
步驟 4:創建適配器
要創建 RecyclerView 可以使用的適配器,必須擴展 RecyclerView.Adapter。 該適配器遵循視圖支架 (view holder) 設計模式,這意味著您可以自定義擴展 RecyclerView.ViewHolder 的類。 此模式最大限度地減少了對昂貴的 findViewById 方法的調用次數。
在本教程前面,我們已經為代表壹個人的 CardView 定義了 XML 布局。 現在我們將重用那個布局。 在自定義 ViewHolder 的構造函數內,初始化屬於 RecyclerView 條目的視圖。
1 |
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder>{ |
2 |
|
3 |
public static class PersonViewHolder extends RecyclerView.ViewHolder { |
4 |
CardView cv; |
5 |
TextView personName; |
6 |
TextView personAge; |
7 |
ImageView personPhoto; |
8 |
|
9 |
PersonViewHolder(View itemView) { |
10 |
super(itemView); |
11 |
cv = (CardView)itemView.findViewById(R.id.cv); |
12 |
personName = (TextView)itemView.findViewById(R.id.person_name); |
13 |
personAge = (TextView)itemView.findViewById(R.id.person_age); |
14 |
personPhoto = (ImageView)itemView.findViewById(R.id.person_photo); |
15 |
}
|
16 |
}
|
17 |
|
18 |
}
|
接下來,向自定義適配器添加構造函數,以便它具有 RecyclerView 顯示數據的句柄。 由於我們的數據是 Person 對象的 List,請使用以下代碼:
1 |
List<Person> persons; |
2 |
|
3 |
RVAdapter(List<Person> persons){ |
4 |
this.persons = persons; |
5 |
}
|
RecyclerView.Adapter 有三個我們必須覆蓋的抽象方法。 讓我們從 getItemCount 方法開始。 它應該返回數據中現存的條目 (item) 數。 由於我們的數據是 List 的形式,我們只需要調用 List 對象的 size 方法:
1 |
@Override
|
2 |
public int getItemCount() { |
3 |
return persons.size(); |
4 |
}
|
由於我們的數據是 List 的形式,我們只需要調用 List 對象的 size 方法: 顧名思義,當需要初始化自定義 ViewHolder 時調用此方法。 我們指定 RecyclerView 每個條目應使用的布局。 這是通過使用 LayoutInflater 來填充 (inflate) 布局來完成的,將輸出傳遞給自定義 ViewHolder 的構造函數。
1 |
@Override
|
2 |
public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { |
3 |
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false); |
4 |
PersonViewHolder pvh = new PersonViewHolder(v); |
5 |
return pvh; |
6 |
}
|
覆蓋 onBindViewHolder 以指定 RecyclerView 的每個項目的內容。 此方法與 ListView 適配器的 getView 方法非常相似。 在我們的示例中,您必須在此方法內設置 CardView 的名稱,年齡和照片字段的值。
1 |
@Override
|
2 |
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) { |
3 |
personViewHolder.personName.setText(persons.get(i).name); |
4 |
personViewHolder.personAge.setText(persons.get(i).age); |
5 |
personViewHolder.personPhoto.setImageResource(persons.get(i).photoId); |
6 |
}
|
最後,您需要重寫 onAttachedToRecyclerView 方法。 現在,我們可以簡單地使用這個方法的超類實現,如下所示。
1 |
@Override
|
2 |
public void onAttachedToRecyclerView(RecyclerView recyclerView) { |
3 |
super.onAttachedToRecyclerView(recyclerView); |
4 |
}
|
步驟 5:使用適配器
現在適配器準備就緒,將以下代碼添加到 Activity 中以通過調用適配器的構造函數和 RecyclerView 的 setAdapter 方法來初始化並使用適配器:
1 |
RVAdapter adapter = new RVAdapter(persons); |
2 |
rv.setAdapter(adapter); |
步驟 6: 編譯並運行
當您在 Android 設備上運行 RecyclerView 示例時,應該會看到類似於以下結果的內容。



結論
在本教程中,您已經學會了如何使用 Android Lollipop 中引入的 CardView 和 RecyclerView 小部件。 您還看到了如何在 Material Design 應用程序中使用這些小部件的示例。 請註意,盡管 RecyclerView 幾乎可以完成 ListView 可以執行的所有操作,但對於小型數據集,使用 ListView 仍然是可取的,因為它需要較少的代碼行。
有關 CardView 和 RecyclerView 類的更多信息,您可以查閱 Android 開發人員參考。



