大部分的開發者對於ListView應該不陌生吧,但是今天要來介紹的是RecyclerView,Android是一個不斷進化的平台,Android 5.0的v7版本支持包中引入了新的RecyclerView控制項,正如官方文檔所言,RecyclerView是ListView的豪華增強版。它主要包含以下幾處新的特性,如ViewHolder,ItemDecorator,LayoutManager,SmothScroller以及增加或刪除item時item動畫等。官方推薦我們採用RecyclerView來取代ListView。
優點:
在很多的ListView 範例中,常常會看到ViewHolder的使用,因為在ListView中有時候會大量的加載View,這樣會造成記憶體浪費,影響性能,這時候就可以使用ViewHolder 靜態類別方法的設計方法,避免造成過多的記憶體浪費,那在RecylerView 中強制要使用ViewHolder,雖然可能會變得比較複雜一點,但是我們在ListView中所遇到的一些問題都被更有效率的解決!
優點:
1) ViewHolder Pattern
在很多的ListView 範例中,常常會看到ViewHolder的使用,因為在ListView中有時候會大量的加載View,這樣會造成記憶體浪費,影響性能,這時候就可以使用ViewHolder 靜態類別方法的設計方法,避免造成過多的記憶體浪費,那在RecylerView 中強制要使用ViewHolder,雖然可能會變得比較複雜一點,但是我們在ListView中所遇到的一些問題都被更有效率的解決!
可以參考這篇ViewHolder用法
2) LayoutManager
ListView只提供垂直的上下滑動,不能水平滑動等,現在使用RecylerView提供了3種
i. LinearLayoutManager 支援水平或垂直的清單(lists)
ii. StaggeredLayoutManager 支援拼貼樣式像是交錯的清單
iii. GridLayoutManager 支援呈現網格像是圖集的清單
最好的一件事是我們可以動態地做我們想要呈現的layout
i. LinearLayoutManager 支援水平或垂直的清單(lists)
ii. StaggeredLayoutManager 支援拼貼樣式像是交錯的清單
iii. GridLayoutManager 支援呈現網格像是圖集的清單
最好的一件事是我們可以動態地做我們想要呈現的layout
3) Item Animator
LisrView 缺少好的動畫,但是RecyclerView 帶來全新的動畫方式,藉由RecyclerView.ItemAnimator 類別,動畫的呈現變得更簡單於直觀,可以在添加刪除或移動項目時做動畫
4) Item Decoration
在ListView中,動態地裝飾項目像是增加界線或是分隔線都是不容易的,但是在RecyclerView的 RecyclerView.ItemDecorator 類別給予開發者很大的控制彈性,但卻也會造成更多的時間浪費與複雜
5) OnItemTouchListener
在ListView中點擊項目的動作是很簡單的,多虧有了 AdapterView.OnItemClickListenerinterface,
而RecyclerView 藉由RecyclerView.OnItemTouchListener給予開發者更強的控制,卻也變得比較複雜
介紹完我就在下面簡單實作RecyclerView
1:Gradle配置 build.gradle
compile 'com.android.support:recyclerview-v7:23.0.0'
2:建立Main Layout activity_recyclerview.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
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.example.yi_an.myrecyleview.MainActivity"> <android.support.v7.widget.RecyclerView
android:id="@+id/myrecycle"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
由於測試需要多種item Layout的加載,需要建立2個item layout
3:建立Item 1 Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"> <TextView
android:text="TextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:id="@+id/textView" /> </LinearLayout>
4:建立Item 2 Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.yi_an.myrecyleview.MySpinner
android:id="@+id/button"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textSize="20sp"
/>
</LinearLayout>
5:建立Activity跟RecyclerView Adapter
RecyclerView.Adapter 負責提供 child-view 給 RecyclerView 使用,同時也負責把資料跟 child-view 綁在一起。實際上並不是直接對上 View,而是對上 ViewHolder。從設計上來看就是強迫使用 ViewHolder pattern 來增加效率。此抽象類別需要實作這四個 method
- getItemCount() - Adapter才知道如何儲存資料及回傳有多少筆資料
- onCreateViewHolder(ViewGroup parent, int viewtype) - 現有的 ViewHolder不夠用,要求Adapter產生一個新的viewholder,也可以根據viewtype產生你要的viewholder(對應第四個function)
- onBindViewHolder(ViewHolder viewholder, int position) - 重用之前產生的 ViewHolder,把特定位置的資料連結上去準備顯示
- getItemViewType(int) - 根據位置回傳你要View的樣式
public class MainActivity extends AppCompatActivity{
private RecyclerView mRecyclerView;
private RecyclerView.LayoutManager mLayoutManager;
private MyAdapter mAdapter;
private String [] myDataset;
private List<MyItem> myItemList;
private String [] selectdata;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myDataset = new String[]{"test","test1","test3","4","5","6","7","8"};
myItemList = new ArrayList<>();
MyItem myItem1 = new MyItem("1","select","1/2/3/4/5/6");
MyItem myItem2 = new MyItem("2","text",null);
myItemList.add(myItem1);
myItemList.add(myItem2);
selectdata = new String[myItemList.size()];
mRecyclerView = (RecyclerView)findViewById(R.id.myrecycle);
// use this setting to improve performance if you know that changes // in content do not change the layout size of the RecyclerView mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
// specify an adapter (see also next example) mAdapter = new MyAdapter(this,myItemList);
mRecyclerView.setAdapter(mAdapter);
}
}
private class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
private String[] mdataset;
private List<MyItem> list;
private LayoutInflater mLayoutInflater;
public class ViewHolder extends RecyclerView.ViewHolder {
public MySpinner mySpinner;
public ViewHolder(View v) {
super(v);
mySpinner = (MySpinner)v.findViewById(R.id.button);
}
}
public class ViewHolder1 extends RecyclerView.ViewHolder {
public TextView mTextView;
public ViewHolder1(View v) {
super(v);
mTextView = (TextView) v.findViewById(R.id.textView);
}
}
public MyAdapter(Context context, List<MyItem> myItem ){
list = myItem;
mLayoutInflater = LayoutInflater.from(context);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.d("recycle","onCreateViewHolder");
if(viewType==0) {
View v = mLayoutInflater.inflate(R.layout.my_spinner, parent, false);
return new ViewHolder(v);
}else {
View v = mLayoutInflater.inflate(R.layout.my_text_view, parent, false);
return new ViewHolder1(v);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Log.d("recycle","onBindViewHolder");
Log.d("position",position+"");
if(holder instanceof ViewHolder){
((ViewHolder) holder).mySpinner.initContent(MainActivity.this,list.get(position).value.split("/"),position);
if(selectdata[position]!=null){
((ViewHolder) holder).mySpinner.setText(selectdata[position],null);
}
for(int x = 0; x<selectdata.length;x++){
if(selectdata[x]!=null)
Log.d("selectdata",selectdata[x]);
}
}else if(holder instanceof ViewHolder1){
((ViewHolder1) holder).mTextView.setText(list.get(position).value);
}
}
@Override
public int getItemViewType(int position) {
Log.d("recycle","getItemViewType");
if("select".equals(list.get(position).type)){
return 0;
}else{
return 1;
}
}
@Override
public int getItemCount() {
return list.size();
}
}
附上gitgub
https://github.com/andy086912597/MyRecyclerView/tree/master
歡迎大家來討論
(References)
http://stackoverflow.com/questions/28525112/android-recyclerview-vs-listview-with-viewholder
https://read01.com/kE4z2.html