1. Code
  2. Coding Fundamentals
  3. Tools

在 Android 設備上使用 RecyclerView 和 CardView 組合

如果您有興趣構建壹個利用列表顯示數據的 Android 應用程序,Android Lollipop 具有兩個新的輕松構建該類應用的小部件:RecyclerView 和 CardView。  使用這些小部件,很容易讓您的應用程序的外觀和感覺符合 Google 材料設計規範中提及的準則。
Scroll to top

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 設備上選然後如下:

A Stand-alone CardA Stand-alone CardA Stand-alone Card

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 子類:

  • LinearLayoutManager
  • GridLayoutManager
  • 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 開發人員參考。