Android開發筆記(一百二十二)迴圈器檢視RecyclerView
RecyclerView
RecyclerView是Android在support-v7庫中新推出控制元件,中文別名為迴圈器檢視,它的功能非常強大,可分別實現ListView、GridView,以及瀑布流網格的顯示效果。RecyclerView相關工程在sdk中的路徑為sdk\extras\android\support\v7\recyclerview,不過幸好用它不像用Toolbar那樣麻煩,要想使用Toolbar得先匯入並引用v7-appcompat工程(具體步驟參見《Android開發筆記(一百一十九)工具欄Toolbar》),而使用RecyclerView只需像其他第三方jar一樣往libs目錄新增android-support-v7-recyclerview.jar就好了。
但是若在Eclipse/ADT中呼叫RecyclerView,可能app執行時會報錯“Caused by: java.lang.NoClassDefFoundError: android.support.v7.recyclerview.R$styleable”,這時就不能使用sdk\extras\android\support\v7\recyclerview下面的jar包,而要到extras/android/m2repository/com/android/support/recyclerview-v7目錄下,在版本號21.0.0的子目錄中找到recyclerview-v7-21.0.0.aar,該aar檔案其實是個壓縮檔案,解壓該檔案可得到classes.jar,將該jar包更名並加入到你的工程,上面的執行錯誤應該就沒有了。
下面看看強悍的RecyclerView都提供了哪些常用方法:
setAdapter : 設定列表項的介面卡。有關介面卡的詳細說明見下一標題。
setLayoutManager : 設定列表項的佈局管理器。目前有三種,分別是:線性佈局管理器LinearLayoutManager、網格佈局管理器GridLayoutManager、瀑布流網格佈局管理器StaggeredGridLayoutManager。有關佈局管理器的詳細說明見本文的後半部分。
addItemDecoration : 新增列表項的分割線。
removeItemDecoration : 移除列表項的分割線。
setItemAnimator : 設定列表項的增刪動畫。
addOnItemTouchListener : 新增列表項的觸控監聽器。因為RecyclerView沒有實現列表項的點選介面,所以開發者可通過這裡的觸控監聽器來監控使用者手勢。
removeOnItemTouchListener : 移除列表項的觸控監聽器。
迴圈介面卡
RecyclerView有專門的介面卡類,即RecyclerView.Adapter。在呼叫RecyclerView的setAdapter方法前,我們要先實現一個從RecyclerView.Adapter派生而來的資料介面卡,用來定義列表項的佈局與具體操作。下面是與RecyclerView.Adapter相關的常用方法:下面是自定義介面卡必須要重寫的方法:
getItemCount : 獲得列表項的數目。
onCreateViewHolder : 建立整個佈局的檢視持有者。輸入引數中包括檢視型別,可根據檢視型別載入不同的佈局,從而實現帶頭部的列表佈局。
onBindViewHolder : 繫結每項的檢視持有者。
下面是可以重寫也可以不重寫的方法:
getItemViewType : 返回每項的檢視型別。這裡返回的檢視型別給onCreateViewHolder方法使用。
getItemId : 獲得每項的編號。
下面是可以直接呼叫的方法:
notifyItemInserted : 通知介面卡在指定位置插入了新項。
notifyItemRemoved : 通知介面卡在指定位置刪除了原有項。
notifyItemChanged : 通知介面卡在指定位置的專案發生了變化。
notifyDataSetChanged : 通知介面卡整個列表的資料發生了變化。
總的來說,RecyclerView.Adapter與我們之前經常遇到的BaseAdapter在處理流程上是基本一致的,當然它們之間也有不小的差異,下面是RecyclerView.Adapter和其他介面卡的主要區別:
1、自帶ViewHolder及其重用功能,無需開發者手工重用ViewHolder;
2、未自帶列表項的點選和長按功能,需要開發者自己實現點選和長按事件的監聽;
3、增加區分不同列表項的檢視型別,方便開發者根據型別載入不同的佈局;
4、可單獨對個別項進行增刪改操作,無需重新整理整個列表;
下面是RecyclerView.Adapter的一個自定義類的程式碼例子:
import com.example.exmrecycler.R;
import com.example.exmrecycler.interfaces.OnItemClickListener;
import com.example.exmrecycler.interfaces.OnItemLongClickListener;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
public class RecyclerAdapter extends RecyclerView.Adapter<ViewHolder>
implements OnItemClickListener, OnItemLongClickListener {
private final static String TAG = "RecyclerAdapter";
private Context mContext;
private LayoutInflater mInflater;
private int mType;
private String[] mTitleArray;
public RecyclerAdapter(Context context, int type, String[] titleArray) {
mContext = context;
mInflater = LayoutInflater.from(context);
mType = type;
mTitleArray = titleArray;
}
@Override
public int getItemCount() {
return mTitleArray.length;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup vg, int viewType) {
View v = null;
ViewHolder holder = null;
v = mInflater.inflate(R.layout.list_title, vg, false);
holder = new TitleHolder(v);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder vh, final int position) {
TitleHolder holder = (TitleHolder) vh;
holder.tv_seq.setText(""+(position+1));
holder.tv_title.setText(mTitleArray[position]);
LayoutParams params = holder.ll_item.getLayoutParams();
if (mType == 1) { //表示是線性佈局
params.height = 50;
holder.ll_item.setLayoutParams(params);
} else if (mType == 2) { //表示是網格佈局
params.height = 100;
holder.ll_item.setLayoutParams(params);
} else { //表示是瀑布流網格佈局
params.height = (int) Math.round(300 * Math.random());
if (params.height < 60) {
params.height = 60;
}
//很奇怪,setLayoutParams對瀑布流網格不起作用,只能用setHeight
holder.tv_title.setHeight(params.height);
}
//列表項的點選事件需要自己實現
holder.ll_item.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(v, position);
}
}
});
holder.ll_item.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mOnItemLongClickListener != null) {
mOnItemLongClickListener.onItemLongClick(v, position);
}
return true;
}
});
}
@Override
public int getItemViewType(int position) {
//這裡返回每項的型別,開發者可自定義頭部型別與一般型別,
//然後在onCreateViewHolder方法中根據型別載入不同的佈局,從而實現帶頭部的網格佈局
return 0;
}
@Override
public long getItemId(int position) {
return position;
}
public class TitleHolder extends RecyclerView.ViewHolder {
public LinearLayout ll_item;
public TextView tv_seq;
public TextView tv_title;
public TitleHolder(View v) {
super(v);
ll_item = (LinearLayout) v.findViewById(R.id.ll_item);
tv_seq = (TextView) v.findViewById(R.id.tv_seq);
tv_title = (TextView) v.findViewById(R.id.tv_title);
}
}
private OnItemClickListener mOnItemClickListener;
public void setOnItemClickListener(OnItemClickListener listener) {
this.mOnItemClickListener = listener;
}
private OnItemLongClickListener mOnItemLongClickListener;
public void setOnItemLongClickListener(OnItemLongClickListener listener) {
this.mOnItemLongClickListener = listener;
}
@Override
public void onItemClick(View view, int position) {
String desc = String.format("您點選了第%d項,內容是%s", position+1, mTitleArray[position]);
Toast.makeText(mContext, desc, Toast.LENGTH_SHORT).show();
}
@Override
public void onItemLongClick(View view, int position) {
String desc = String.format("您長按了第%d項,內容是%s", position+1, mTitleArray[position]);
Toast.makeText(mContext, desc, Toast.LENGTH_SHORT).show();
}
}
佈局管理器
佈局管理器LayoutManager是RecyclerView的精髓,也是RecyclerView之所以強悍的源泉。它不但提供了三類佈局管理,分別實現類似ListView、GridView、瀑布流網格的效果,而且可在程式碼中隨時由RecyclerView呼叫setLayoutManager方法設定新的佈局;一旦呼叫了setLayoutManager方法,介面就會根據新佈局重新整理列表項,這個特性特別適合於手機在豎屏/橫屏之間的顯示切換(如豎屏時展示ListView,橫屏時展示GridView),也適合在不同螢幕解析度如手機/平板之間的顯示切換(如手機上展示ListView,平板上展示GridView)。LinearLayoutManager
線性佈局管理器LinearLayoutManager類似於LinearLayout,當它是垂直方向佈局時,則展示效果類似於ListView;當它是水平方向佈局時,則展示效果類似於HorizontalListView,當然這個HorizontalListView不是Android的原生控制元件,而是大神們自定義的控制元件,有關HorizontalListView的說明參見《Android開發筆記(一百零一)滑出式選單》。下面是LinearLayoutManager的常用方法:
建構函式 : 可指定列表的方向與是否為相反方向開始佈局。
setOrientation : 單獨設定列表的方向。
setReverseLayout : 單獨設定是否為相反方向開始佈局。預設false,如果設定為true,那麼垂直方向將從下往上開始佈局,水平方向將從右往左開始佈局。
下面是線性佈局的效果截圖:
下面是LinearLayoutManager的示例程式碼:
import com.example.exmrecycler.adapter.RecyclerAdapter;
import com.example.exmrecycler.widget.DividerItemDecoration;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.LinearLayout;
public class LinearActivity extends Activity {
private RecyclerView rv_linear;
private LinearLayoutManager mLayoutManager;
private RecyclerAdapter mAdapter;
private String[] starArray = {"水星", "金星", "地球", "火星", "木星", "土星"};
private String[] yearArray = {"鼠年", "牛年", "虎年", "兔年", "龍年", "蛇年",
"馬年", "羊年", "猴年", "雞年", "狗年", "豬年"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_linear);
rv_linear = (RecyclerView) findViewById(R.id.rv_linear);
mLayoutManager = new LinearLayoutManager(this);
mLayoutManager.setOrientation(LinearLayout.VERTICAL);
rv_linear.setLayoutManager(mLayoutManager);
mAdapter = new RecyclerAdapter(this, 1, yearArray);
rv_linear.setAdapter(mAdapter);
rv_linear.setItemAnimator(new DefaultItemAnimator());
rv_linear.addItemDecoration(new DividerItemDecoration(this,
DividerItemDecoration.VERTICAL_LIST));
}
}
GridLayoutManager
網格佈局管理器GridLayoutManager類似於GridLayout,GridLayout是Android4.0新增的佈局型別。話說Android陸陸續續增加了一些佈局,比如前幾節提到的側滑佈局SlidingPaneLayout和DrawerLayout(詳細說明參見《Android開發筆記(一百二十)兩種側滑佈局》),還有下一節要介紹的SwipeRefreshLayout(詳細說明參見《Android開發筆記(一百二十三)下拉重新整理佈局》),這些新佈局著實增加了廣大碼農的學習時間,所以還是能省則省,從展示效果來看,GridLayoutManager類似於GridView,所以就不再另外學習GridLayout了。下面是GridLayoutManager的常用方法:
建構函式 : 可指定網格的列數。
setSpanCount : 單獨設定網格的列數。
setSpanSizeLookup : 設定列表項的佔位規則。預設一項佔一列,如果想某項佔多列,則可在此設定自定義的佔位規則,即由抽象類GridLayoutManager.SpanSizeLookup派生出具體的實現類。
下面是網格佈局的效果截圖:
下面是GridLayoutManager的示例程式碼:
import com.example.exmrecycler.adapter.RecyclerAdapter;
import com.example.exmrecycler.widget.DividerGridItemDecoration;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
public class GridActivity extends Activity {
private RecyclerView rv_grid;
private GridLayoutManager mLayoutManager;
private RecyclerAdapter mAdapter;
private String[] yearArray = {"鼠年", "牛年", "虎年", "兔年", "龍年", "蛇年",
"馬年", "羊年", "猴年", "雞年", "狗年", "豬年"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_grid);
rv_grid = (RecyclerView) findViewById(R.id.rv_grid);
mLayoutManager = new GridLayoutManager(this, 4);
// mLayoutManager.setSpanCount(3);
// //以下佔位規則的意思是:第一項佔四列,第二列和第三項各佔兩列
// //如果網格的列數為四,那麼第一項將佔滿第一行,第二列和第三項平分第二行,第三行開始每行有四項
// mLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
// @Override
// public int getSpanSize(int position) {
// if (position == 0) {
// return 4;
// } else if (position==1 || position==2) {
// return 2;
// } else {
// return 1;
// }
// }
// });
rv_grid.setLayoutManager(mLayoutManager);
mAdapter = new RecyclerAdapter(this, 2, yearArray);
rv_grid.setAdapter(mAdapter);
rv_grid.setItemAnimator(new DefaultItemAnimator());
rv_grid.addItemDecoration(new DividerGridItemDecoration(this));
}
}
StaggeredGridLayoutManager
瀑布流網格相信大家多多少少都有所瞭解了,如有不太清楚的,可參考《Android開發筆記(二十二)瀑布流網格》。之前我們要想實現瀑布流效果,都得自定義控制元件或者藉助於第三方開源庫如StaggeredGridView、PinterestLikeAdapterView等等;現在Android在support-v7庫中推出了StaggeredGridLayoutManager,這讓我們對瀑布流效果的開發大大簡化了,只要在介面卡程式碼中動態設定每個網格的高度,系統便會自動在介面上依次排列瀑布流網格。下面是StaggeredGridLayoutManager的常用方法:
建構函式 : 可指定網格的列數和方向。
setSpanCount : 單獨設定網格的列數。
setOrientation : 單獨設定瀑布流佈局的方向。LinearLayout.VERTICAL表示垂直方向,LinearLayout.HORIZONTAL表示水平方向,通常預設LinearLayout.VERTICAL。
setReverseLayout : 設定是否為相反方向開始佈局。預設false,如果設定為true,那麼垂直方向將從下往上開始佈局,水平方向將從右往左開始佈局。
下面是瀑布流網格佈局的效果截圖:
下面是StaggeredGridLayoutManager的示例程式碼:
import com.example.exmrecycler.adapter.RecyclerAdapter;
import com.example.exmrecycler.widget.SpacesItemDecoration;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.widget.LinearLayout;
public class StaggeredActivity extends Activity {
private RecyclerView rv_staggered;
private StaggeredGridLayoutManager mLayoutManager;
private RecyclerAdapter mAdapter;
private String[] yearArray = {"鼠年", "牛年", "虎年", "兔年", "龍年", "蛇年",
"馬年", "羊年", "猴年", "雞年", "狗年", "豬年"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_staggered);
rv_staggered = (RecyclerView) findViewById(R.id.rv_staggered);
mLayoutManager = new StaggeredGridLayoutManager(4, LinearLayout.VERTICAL);
// mLayoutManager.setSpanCount(3);
// mLayoutManager.setOrientation(LinearLayout.HORIZONTAL);
// mLayoutManager.setReverseLayout(true);
rv_staggered.setLayoutManager(mLayoutManager);
mAdapter = new RecyclerAdapter(this, 3, yearArray);
rv_staggered.setAdapter(mAdapter);
rv_staggered.setItemAnimator(new DefaultItemAnimator());
//每項周圍的空隙是5,那麼項與項之間的間隔就是5+5=10。
SpacesItemDecoration decoration=new SpacesItemDecoration(5);
rv_staggered.addItemDecoration(decoration);
}
}
點選下載本文用到的RecyclerView的工程程式碼
點此檢視Android開發筆記的完整目錄
相關文章
- 「學習筆記」迴圈、列表筆記
- Android開發---在RecyclerView列表中新增自定義的列表頭部與尾部檢視AndroidView
- node事件迴圈學習筆記事件筆記
- 【C++學習筆記】for迴圈C++筆記
- Android開發筆記Android筆記
- Android TV開發——RecyclerView For TVAndroidView
- iOS開發:Swift實現的輪播圖、無限迴圈檢視控制元件iOSSwift控制元件
- Android開發筆記(一百二十五)自定義視訊播放器Android筆記播放器
- Android個人開發筆記Android筆記
- Android開發 - RecyclerView 類詳解AndroidView
- JavaScript事件迴圈及非同步原理筆記JavaScript事件非同步筆記
- 學習筆記之事件迴圈-Event loop筆記事件OOP
- 【廖雪峰python入門筆記】for迴圈Python筆記
- ScrollView 之 實現檢視的迴圈顯示View
- MySQL筆記 13 檢視MySql筆記
- 學習筆記 檢視筆記
- Android 開發學習筆記Android筆記
- web前端開發教程-while迴圈Web前端While
- 鴻蒙開發TypeScript語言:【迴圈】鴻蒙TypeScript
- JS筆記(2) JS中的迴圈遍歷JS筆記
- 【廖雪峰python入門筆記】while迴圈Python筆記While
- 【廖雪峰python入門筆記】多重迴圈Python筆記
- 記憶體二三事: Xcode 記憶體圖、Instruments 視覺化檢測迴圈引用記憶體XCode視覺化
- Android訊息迴圈Android
- iOS開發系列--無限迴圈的圖片瀏覽器iOS瀏覽器
- JS優化迴圈之展開迴圈JS優化
- Android開發筆記——點選檢視大圖過渡動畫與圖片縮放與移動Android筆記動畫
- Android開發 - 檢視佈局屬性解析Android
- android原生開發recyclerview基礎例項AndroidView
- Android應用開發筆記(一)Android筆記
- 物化檢視學習筆記筆記
- 【筆記】 使用物化檢視(一)筆記
- Vue mock模擬獲取資料 迴圈遍歷檢視VueMock
- 直播平臺原始碼,迴圈滾動RecyclerView的實現原始碼View
- Python3學習筆記4 , 迴圈、模組Python筆記
- Swift學習筆記(二十五)——迴圈結構Swift筆記
- Android開發 - inflate方法與建立檢視解析Android
- Android應用開發—RecyclerView繪製蒙層AndroidView