谷歌在support v7中,加入了新的控件——RecyclerView,該控件整合了ListView、GridView的特點,而且最大的優點是可以很方便實現瀑布流效果,因此RecyclerView受到越來越多的開發者重視。所以,學習RecyclerView的使用也是很有必要的。
引入RecyclerView
由於該控件並不在Andorid SDK中的,而是在support v7包中,因此我們要手動添加該控件。
在build.gradle中添加如下依賴:
dependencies {
...
compile 'com.android.support:recyclerview-v7:23.1.1' }
幾個重要的類
在認識RecyclerView的用法之前,我們要先認識幾個它常用的內部類,因爲這幾個內部類很重要,貫穿整個使用過程:
1、RecyclerView.Adapter:抽象類,爲RecyclerView提供數據,一般根據不同的業務需求來編寫具體的實現類。
2、RecyclerView.LayoutManager:抽象類,主要用於測量RecyclerView的子Item,以及根據不同的佈局方式來實現Item的佈局效果,v 7包自帶的實現類有:LinearLayoutManager、StaggeredGridLayoutManager、GridLayoutManager。
3、RecyclerView.ItemDecoration:抽象類,這個主要用於不同的Item之間添加分割線(可選)。官方沒有實現類,所以如果要添加分割線,我們需要手動實現這個抽象類。
4、RecyclerView.ItemAnimator:抽象類,這個主要用於當一個item添加或者刪除的時候出現的動畫效果,官方提供一個默認的實現類。如果想要使我們的RecyclerView在添加、刪除數據的時候有炫酷的動畫,可以實現這個抽象類。
可以看到,這些重要的類都是抽象類,這就爲RecyclerView的高度可定製性打下了堅實的基礎,利用不同的實現類,能自由、靈活地使用RecyclerView,這也是RecyclerView的優秀之處。
開始上代碼
一、recyclerView的佈局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.recyclerview.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
二、MainActivity中的代碼
public class MainActivity extends AppCompatActivity {
private Toolbar toolbar;
private RecyclerView mRecyclerView;
private RecyclerView.LayoutManager mLayoutManager;
private MyAdapter mAdapter;
private List<String> mData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initToolbar();
initData();
initRecyclerView();
}
private void initData() {
mData = new ArrayList<>();
for(int i=0;i<20;i++){
mData.add("Item "+i);
}
}
private void initRecyclerView() {
//1 實例化RecyclerView
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
mLayoutManager = new LinearLayoutManager(this);
//2 爲RecyclerView創建佈局管理器,這裏使用的是LinearLayoutManager,表示裏面的Item排列是線性排列
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new MyAdapter(mData);
//3 設置數據適配器
mRecyclerView.setAdapter(mAdapter);
}
三、最重要的適配器的Adapter的代碼
與ListView類似地,RecyclerView也需要適配器來提供數據。上面說到RecyclerView提供了一個抽象類:RecyclerView.Adapter,我們通過繼承該類來寫自己的適配器。
public static abstract class Adapter<VH extends ViewHolder> {
public abstract VH onCreateViewHolder(ViewGroup parent, int viewType); // 1
public abstract void onBindViewHolder(VH holder, int position); // 2
public abstract int getItemCount(); // 3
}
繼承該類的時候,必須重寫這三個方法,我們分別解釋一下這三個方法是什麼作用:
①onCreateViewHolder:創建ViewHolder,該方法會在RecyclerView需要展示一個item的時候回調。重寫該方法時,應該使ViewHolder加載item view的佈局。這個能發避免了不必要的findViewById操作,提高了性能。如果熟悉ListView的ViewHolder操作那麼也能很容易理解這個。
②onBindeViewHolder:該方法在RecyclerView在特定位置展示數據時候回調,顧名思義,把數據綁定、填充到相應的item view中。
③getItemCount:返回數據的數量。
我們注意到,繼承該類的時候需要聲明它的泛型類型VH,VH繼承自RecyclerView.ViewHolder,同時第①個方法的返回值也是VH,由於ViewHolder是根據業務需求而變化的,不同的業務需求而需要的ViewHolder不盡相同,所以沒必要單獨寫一個ViewHolder.java文件,因此我們可以在Adapter子類內部實現一個內部類ViewHolder,這樣也符合單一職責原則。具體的Adapter適配器代碼如下所示,MyAdapter.java:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<String> mDataSet;
//構造器,接受數據集
public MyAdapter(List<String> data){
mDataSet = data;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//加載佈局文件
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.itemlayout,parent,false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
//將數據填充到具體的view中
holder.mTextView.setText(mDataSet.get(position));
}
@Override
public int getItemCount() {
return mDataSet.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
public TextView mTextView;
public ViewHolder(View itemView) {
super(itemView);
//由於itemView是item的佈局文件,我們需要的是裏面的textView,因此利用itemView.findViewById獲
//取裏面的textView實例,後面通過onBindViewHolder方法能直接填充數據到每一個textView了
mTextView = (TextView) itemView.findViewById(R.id.num);
}
}
}
以上的代碼的執行結果大概是這樣