時間 2014-10-22 20:08:48 CSDN博客html
原文 http://blog.csdn.net/allen315410/article/details/40379159java
主題 RecyclerView ListViewandroid
轉載請註明出處: http://blog.csdn.net/allen315410/article/details/40379159ios
萬衆矚目的android最新5.0版本不久前已經正式發佈了,對於我這樣對新事物不感冒的人來講,天然也是會關注的,除了新的android5.0帶來的新的UI設計和用戶體驗以外,最讓android程序員感興趣的是5.0版本的sdk和一大堆新的API。5.0聽說是額外增長或者修改了5000個API,新增了一些新的組件,下面介紹的RecyclerView就是其中之一,有人說Google設計出的RecyclerView是爲了替代一直經常使用的ListView的,因此既然如此,咱們就沒理由不看看這個「傳說」中的RecyclerView是怎麼使用的了。程序員
該RecyclerView widget是一種更先進的柔性版的ListView。這個小工具是一個容器,用於顯示,能很是有效地維護了意見數量有限,滾動大的數據集。使用 RecyclerView當你擁有的數據的集合,它的元素在運行時改變基於用戶行爲和網絡事件的小部件。緩存
該RecyclerView類簡化,提供顯示和處理大數據集:網絡
定位項目佈局管理器app
默認的動畫爲公用項的操做,例如刪除或增長的項目ide
您還能夠在自定義的佈局管理器和動畫的靈活性RecyclerView部件。函數
要使用RecyclerView小部件,你必須指定一個適配器和一個佈局管理器。要建立一個適配器,擴展RecyclerView.Adapter類。實施的細節取決於你的數據集的具體狀況和意見的類型。欲瞭解更多信息,請參見示例以下。
佈局管理器 A的內部位置的項目意見RecyclerView,並肯定什麼時候再利用項目的見解再也不對用戶可見。重用(或回收)的圖,佈局管理器可能會問適配器與數據集不一樣的元素替換視圖的內容。以這種方式回收的觀點提升經過避免產生沒必要要的視圖或執行昂貴性能findViewById()的查找。
RecyclerView提供這些內置的佈局管理器:
LinearLayoutManager 顯示在垂直或水平滾動列表項。
GridLayoutManager 顯示在網格中的項目。
StaggeredGridLayoutManager 顯示了交錯網格項目。
要建立自定義佈局管理器,擴展RecyclerView.LayoutManager類。
動畫
動畫的添加和刪除項目中默認啓用的RecyclerView。要自定義這些動畫,延長 RecyclerView.ItemAnimator類,並使用RecyclerView.setItemAnimator() 方法。
以上內容來自 Google官方文檔 的翻譯,翻譯比較生澀(我這英文水平,哎~~對付本身還行),下面直接上一個Demo看看具體的用法。
下面簡單介紹製做一個小Demo,來一步步分析一下RecyclerView的用法。首先說明一下,RecyclerView是android.support.v7包下提供的組件,因此須要使用RecyclerView時,須要下載這個包,因爲我已經將SDK升級到最新版本——API21,因此很容易在/sdk/extras/android/support/v7/appcompat/libs目錄下找到這個jar以及源碼,建議先升級sdk,再動手作!實在不想動手的下載的,點擊博文下方的連接下載源碼,源碼裏有RecyclerView的JAR包。
主界面佈局,activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <android.support.v7.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="80dp" android:layout_centerVertical="true" android:background="@android:color/transparent" android:scrollbars="none" /> </RelativeLayout>
Item佈局,item_recyclerview.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="120dp" android:layout_height="120dp" > <ImageView android:id="@+id/iv_image" android:layout_width="80dp" android:layout_height="80dp" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:scaleType="centerCrop" /> </RelativeLayout>
RecyclerView的數據適配器,MyAdapter.java
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private int[] mDataset; // 外面傳入的數據 public static class ViewHolder extends RecyclerView.ViewHolder { ImageView mImageView; // TODO Auto-generated method stub public ViewHolder(View v) { super(v); } } public MyAdapter(int[] mDataset) { this.mDataset = mDataset; } /** * 獲取總的條目數量 */ @Override public int getItemCount() { // TODO Auto-generated method stub return mDataset.length; } /** * 建立ViewHolder */ @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // TODO Auto-generated method stub View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycleview, parent, false); ViewHolder holder = new ViewHolder(v); holder.mImageView = (ImageView) v.findViewById(R.id.iv_image); return holder; } /** * 將數據綁定到ViewHolder上 */ @Override public void onBindViewHolder(ViewHolder holder, int position) { // TODO Auto-generated method stub holder.mImageView.setImageResource(mDataset[position]); } }
從上面能夠看出這個數據適配器跟ListView用的BaseAdapter上比,已經發生了很大的變化。首先數據適配器須要繼承RecyclerView.Adapter<VH>類,該類是個泛型類,泛型類型也是ViewHolder,這個ViewHolder毋庸置疑就是實現組件複用的,Google已經幫咱們定義好了,在RecyclerView裏是個內部類,可是具體實現仍是扔給android App開發者去實現,須要在適配器類創建一個內部類,而且繼承RecyclerView,ViewHolder,在這個內部類裏面定義出Item佈局上全部須要複用的組件,最後將這個內部類做爲泛型傳遞給RecyclerView.Adapter<VH>,實現須要複寫的3個方法:
getItemCount() 獲取Item的總數。
onCreateViewHolder(ViewGroup parent, int viewType) 建立ViewHolder。
onBindViewHolder(ViewHolder holder, int position) 將數據綁定到ViewHolder。
與ListView數據適配的對比
ListView裏面有個getView()方法返回的View是Item的佈局,那麼這個RecyclerView的Item的佈局在哪控制?實際上是這樣的,RecyclerView對ViewHolder也進行了必定的封裝,咱們建立的ViewHolder必須繼承RecyclerView.ViewHolder,這個RecyclerView.ViewHolder的構造時必須傳入一個View,這個View至關於咱們ListView的getView()中的convertView (即:咱們須要inflate的item佈局須要傳入)。
還有一點,ListView中convertView是複用的,在RecyclerView中,是把ViewHolder做爲緩存的單位了,而後convertView做爲ViewHolder的成員變量保持在ViewHolder中,也就是說,假設沒有屏幕顯示10個條目,則會建立10個ViewHolder緩存起來,每次複用的是ViewHolder,因此他把getView這個方法變爲了onCreateViewHolder。
最後,就在Activity裏使用這個RecyclerView,MainActivity.java
public class MainActivity extends Activity { /** RecyclerView對象 */ private RecyclerView recyclerView; /** 圖片資源 */ private int[] mDataset; /** 數據適配器 */ private MyAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = (RecyclerView) findViewById(R.id.recyclerview); // 初始化圖片數據 mDataset = new int[] { R.drawable.a, R.drawable.b, // R.drawable.c, R.drawable.d, R.drawable.e, // R.drawable.f, R.drawable.g, R.drawable.h, R.drawable.i }; // 設置佈局管理器 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); recyclerView.setLayoutManager(linearLayoutManager); // 設置適配器 mAdapter = new MyAdapter(mDataset); recyclerView.setAdapter(mAdapter); } }
在MainActivity使用RecyclerView如同使用ListView同樣的簡單,惟一不一樣的地方就是,須要給RecyclerView設置一個佈局管理器,Google爲咱們提供了3種不一樣的佈局管理(詳細請看最上面的簡介),這裏我使用的LinearLayoutmanager,而且設置佈局爲水平顯示。 好了,關於RecyclerView的基本用法講完了,那個關於RecyclerView的另外兩個佈局管理器就暫時不說了,大同小異。下面是運行效果圖
再使用RecyclerView組件時,發現了一個使人「痛心疾首」的問題:RecyclerView竟然沒有點擊Item的事件監聽設置,相似於ListView中起碼有個setOnItemClickListener方法,用於監聽Item點擊並做出相應的邏輯處理。可是翻遍了RecyclerView的API,都沒有發現這個或者相似這個功能的方法可用,這不得不說是個「悲劇」,還據說這個是爲了替代ListView的,看來並非這樣的,請Google出來解釋解釋啊!
好了,Google應該近期是不會解釋的了,可是咱們得本身想辦法解決這個問題,就是爲RecyclerView添加一個回調函數,這個倒不難吧!實在沒法領會的,能夠看看我前面的那篇博文, Android自定義組件——仿ios滑動按鈕 ,裏面有一些相關的用法。下面是我在Adapter裏添加的回調函數。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private int[] mDataset; // 外面傳入的數據 /** * Item的回調接口 * */ public interface OnItemClickListener { void onItemClickListener(View view, int position); } private OnItemClickListener listener; // 點擊Item的回調對象 /** * 設置回調監聽 * * @param listener */ public void setOnItemClickListener(OnItemClickListener listener) { this.listener = listener; } public static class ViewHolder extends RecyclerView.ViewHolder { ImageView mImageView; // TODO Auto-generated method stub public ViewHolder(View v) { super(v); } } public MyAdapter(int[] mDataset) { this.mDataset = mDataset; } /** * 獲取總的條目數量 */ @Override public int getItemCount() { // TODO Auto-generated method stub return mDataset.length; } /** * 建立ViewHolder */ @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // TODO Auto-generated method stub View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycleview, parent, false); ViewHolder holder = new ViewHolder(v); holder.mImageView = (ImageView) v.findViewById(R.id.iv_image); return holder; } /** * 將數據綁定到ViewHolder上 */ @Override public void onBindViewHolder(ViewHolder holder, final int position) { // TODO Auto-generated method stub holder.mImageView.setImageResource(mDataset[position]); if (listener != null) { holder.mImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { listener.onItemClickListener(v, position); } }); } } }
首先在Adapter裏定義一個內部接口,接口內定義回調函數,而後向外暴露一個設置這個接口對象的方法,經過這個方法設置內部接口的對象,最後在ViewHolder綁定數據的方法中,經過接口對象調用接口方法,將相關信息傳遞出去。下面是在MainActivity裏設置這個監聽方法:
mAdapter.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClickListener(View view, int position) { // TODO Auto-generated method stub Toast.makeText(MainActivity.this, position + "", Toast.LENGTH_SHORT).show(); } });
如下是運行效果圖:
</div> <div class="article_social"> <div class="article_like"> <div class="circle circle-like" id="my_zan" data_id="3IziIba"> </div>