Android 的 RecylerView (一)

RecyclerView - 比 ListView 更強大易用效率高的滾動元件

雖然 ListView 可以完成我們大部分列表的需求,不過我們需要使用額外的方式來提高 ListView 的效率,然後 ListView 的擴展性也還不夠全面,它無法做到橫向滾動的效果,所以 Android 提供了一個更強大的元件 — RecyclerView

關於 RecyclerView

可以說是一個加強版的 ListView ,可以實現與 ListView 同樣的效果,也優化了 ListView 中其他不足的地方, Android 官方推薦使用 RecycleView ,也可以實現橫向滾動跟瀑布流佈局。

RecyclerView 基本用法

由於是新增的元件,為了讓Android所有的版本都能使用,將 RecyclerView 定義在了 support 庫當中,所以我們必須先在專案的 build.gradle 中添加相對應的依賴庫才行。

1
2
3
4
5
6
7
8
9
10
11
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:recyclerview-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'

testCompile 'junit:junit:4.12'
}

我們在 dependencies 區塊中添加 compile 'com.android.support:recyclerview-v7:25.3.1' ,接著修改我們的 activity_main.xml 佈局代碼 :

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent">

</android.support.v7.widget.RecyclerView>

</LinearLayout>

RecyclerView Adapter

接著我們要實現與 ListView 相同的效果,所以我們直接延用之前的圖片及 Fruit 類別以及 layout 檔案,當然 RecyclerView 也跟 ListView 相同,需要一個 Adapter 類別,我們建立一個 FruitApapter :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {

private List<Fruit> mFruitList;
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView fruitImage;
TextView fruitName;

public ViewHolder(View view) {
super(view);
fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
fruitName = (TextView) view.findViewById(R.id.fruit_name);
}
}

public FruitAdapter(List<Fruit> fruitList) {
mFruitList = fruitList;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.fruit_item, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Fruit fruit = mFruitList.get(position);
holder.fruitImage.setImageResource(fruit.getImageId());
holder.fruitName.setText(fruit.getName());
}

@Override
public int getItemCount() {
return mFruitList.size();
}
}

首先,在這個 Adapter 中, 需要定義一個內部類別 ViewHolder , 它需要繼承 RecyclerView.ViewHolder 。 然後在這個 ViewHolder 的建構子中要傳入一個 View 參數,這個 View 通常都是指向 RecyclerView 子物件中的最外層佈局,接著我們就能用 findViewById() 方法來獲取佈局中的 ImageViewTextView 的實體。

FruitAdpater 中也有一個建構子,我們會將需要用到的資料透過建構子注入。由於是繼承 RecyclerView.ViewHolder ,我們必須實作三個 abstract 方法 onCreateViewHolder()onBindViewHolder()getItemCount() ,首先 onCreateViewHolder() 是用來建立 ViewHolder 實體,並把讀取出來的佈局傳入到建構子當中,最後回傳這個實體。 onBindViewHolder() 方法是用於對 RecyclerView 子物件的數據進行賦值,會在子物件出現在可顯示範圍中執行,這裡我們透過 position 參數得到目前的 Fruit 實體,然後再將數據設置到 ViewHolderImageViewTextViewgetItemCount() 用來告訴 RecyclerView 有多少子元件,直接回傳顯示資料的筆數就可以了。

開始使用 RecyclerView

當我們準備好 Adapter 之後,我們就可以開始使用 RecyclerView 了 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class MainActivity extends AppCompatActivity {

private List<Fruit> fruitList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruits();
RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
FruitAdapter adapter = new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
}

private void initFruits() {
for(int i = 0; i < 2; i++) {
Fruit apple = new Fruit("蘋果", R.drawable.apple_pic);
fruitList.add(apple);
Fruit banana = new Fruit("香蕉", R.drawable.banana_pic);
fruitList.add(banana);
Fruit orange = new Fruit("橘子", R.drawable.orange_pic);
fruitList.add(orange);
Fruit watermelon = new Fruit("西瓜", R.drawable.watermelon_pic);
fruitList.add(watermelon);
Fruit pear = new Fruit("梨子", R.drawable.pear_pic);
fruitList.add(pear);
Fruit grape = new Fruit("葡萄", R.drawable.grape_pic);
fruitList.add(grape);
Fruit pineapple = new Fruit("鳳梨", R.drawable.pineapple_pic);
fruitList.add(pineapple);
Fruit strawberry = new Fruit("草莓", R.drawable.strawberry_pic);
fruitList.add(strawberry);
Fruit cherry = new Fruit("櫻桃", R.drawable.cherry_pic);
fruitList.add(cherry);
Fruit mango = new Fruit("芒果", R.drawable.mango_pic);
fruitList.add(mango);

}
}
}

這邊我們使用跟之前一樣的資料,所以一樣有 initFruits() 方法,接著我們在 onCreate() 方法中我們先拿到 RecyclerView 的實體,接著我們建立一個 LinearLayoutManager ,並設置到 RecyclerView 中,LayoutManager 用於指定 RecyclerView 的佈局方式,這裡使用的 LinearLayoutManager 是線性佈局的意思,接下來建立 FruitAdapter 實體,並且使用 RecyclerViewsetAdapter 方法完成 Adapter 的設定。這樣就完成了整個 RecyclerView 的實現,並且能做到跟 ListVIew 一模一樣的效果。