- 簡介
- 基本使用流程
- 1.導包
- 2.設定布局管理器
- 3.設定Adapter
- 4. 添加分割線
- 5. 設定動畫
- 6.點選事件
- 7.HeadView + FootView
- 7.去掉滑動收尾的下拉動畫
- 複雜布局層數簡化
- 1. 布局要求
- 2. 布局解析
- 3. 布局實作
- 4. 最終效果展示
簡介
A flexible view for providing a limited window into a large data set.
一個展示大量資料、靈活的View控件。
個人了解為ListView、GridView的官方更新版本,将ViewHolder、複用itemView等ListView優化方案吸收,更加靈活、解耦的展示大量資料。
2017.11.20 增加推薦點選事件處理、HeadView+FootView的封裝.
基本使用流程
1.導包
使用RecycleView需要引入v7包對應。
// 版本号跟v7包版本号一緻就行
compile 'com.android.support:recyclerview-v7:xx.x.x'
2.設定布局管理器
RecycleView.setLayoutManager(LayoutManager);
自帶的三個布局管理器:
StaggeredGridLayoutManager : 流式布局管理器
A LayoutManager that lays out children in a staggered grid formation.
It supports horizontal & vertical layout as well as an ability to layout children in reverse..
以交錯網格的形式布局,支援水準和垂直布局,同時支援反向。
LinearLayoutManager:線性布局管理器
similar functionality to {@link android.widget.ListView}
官方解釋:功能和ListView類似。。。
GridLayoutManager:表格布局管理器
By default, each item occupies 1 span. You can change it by providing a custom
{@link SpanSizeLookup} instance via {@link #setSpanSizeLookup(SpanSizeLookup)}.
預設每個Item占據一個跨度(span:表格的列數既定之後,每個item的寬度),但是你可以setSpanSizeLookup()方法修改每個item的跨度。
功能類似于GridView,繼承了LinearLayoutManager,但是官方的解釋上面是重點,通過上面的功能能夠實作更加靈活的表格布局,将往常隻能嵌套使用的布局在不嵌套的情況展示。
3.設定Adapter
RecycleView.setAdapter();
adapter必須重寫方法如下:
new RecyclerView.Adapter() {
/**
* 根據viewType傳回想要的ViewHolder,強行綁定ListView中ViewHolder模式。
*
* 每個Item都會調用僅且調用一次,即每個Item的ViewHolder對象都不被其他Item(即使類型相同)複用。
* 這裡與ListView使用ViewHolder有所差別。
*
* 當Item需要被複用,調用方法{@link #onBindViewHolder(RecyclerView.ViewHolder, int)}
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item1, parent, false);
RecyclerViewAdapter1.ViewHolder viewHolder = new RecyclerViewAdapter1.ViewHolder(view);
return viewHolder;
}
/**
* 根據加載位置進行資料展示
* 當Item被展示到螢幕上時調用,進行Item展示、更新
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
}
/**
* 傳回總的Item數量
*/
@Override
public int getItemCount() {
return ;
}
});
4. 添加分割線
RecycleView.addItemDecoration(RecyclerView.ItemDecoration);
以前添加分割線的方法不再有效。
android:divider="#ff0000"
android:dividerHeight="1dp"
自定義分割線
new RecyclerView.ItemDecoration() {
/**
* 調用在繪制Item之前
* 一般情況兩個Draw方法選一個重寫即可
*/
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
}
/**
* 調用在繪制Item之後
*/
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
}
/**
* 設定偏移量
*/
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
// 對Item進行偏移
outRect.set(,,,);
}
});
5. 設定動畫
RecyclerView.setItemAnimator(new DefaultItemAnimator());
這裡使用預設的系統動畫。
同時調用如下方法進行Item的add和remove:
public void addItem(int position, String s){
arrayList.add(position,s);
notifyItemInserted(position);
}
public void remove(int position){
arrayList.remove(position);
notifyItemRemoved(position);
}
6.點選事件
方式一:由于RecycleView沒有直接給出點選事件的接口,可以将事件監聽接口放到Adapter中,在布局容器進行實作,容器中調用就好了,這裡不做實作。
方式二(推薦使用):RxJava PublishSubject實作監聽事件的傳遞。
沒有使用RxJava不能使用!!!
adapter實作:
private final PublishSubject<Model> onClickSubject = PublishSubject.create();
/**
* 點選事件 進行訂閱
*
* @author fengzhen
* @version v6.3.0, 2017/11/18 17:43
*/
public PublishSubject<Model> getOnClickSubject() {
return onClickSubject;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Model model = mListData.get(position);
ViewHolder viewHolder = (ViewHolder) holder;
viewHolder.mTvContent.setOnClickListener(v -> onClickSubject.onNext(model));
}
外部訂閱:
mXXXAdapter.getOnClickSubject().subscribe(new DefaultSubscriber<Model>() {
@Override
public void onNext(Modeldata) {
// 點選事件處理
showShortToast(data.getString());
}
});
好,就醬!
7.HeadView + FootView
從ListView到RecyclerView怎麼能把很常用的HeadView、FootView給忘了。
這裡直接貼封裝的一個簡單Adapter,使用直接繼承My Adapter 就可以直接用了。
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
/**
* 擴充RecyclerView.Adapter
* 添加HeadView、FootView
*
* @author fengzhen
* @version v6.3.0, 2017/11/20
*/
public abstract class RecyclerViewExtendAdapter extends RecyclerView.Adapter {
public static final int ITEM_TYPE_HEADVIEW = ;
public static final int ITEM_TYPE_FOOTVIEW = ;
private View mHeadview;
private View mFootview;
private boolean hasHeadView = false;
public void setHeadview(View headview) {
hasHeadView = headview != null;
this.mHeadview = headview;
notifyDataSetChanged();
}
public void setFootview(View footview) {
this.mFootview = footview;
notifyDataSetChanged();
}
public View getmHeadview() {
return mHeadview;
}
public View getmFootview() {
return mFootview;
}
/**
* 不可重寫,
* 重寫方法{@link RecyclerViewExtendAdapter#getNormalItemViewType}實作具體子類操作
*
* @author fengzhen
* @version v6.3.0, 2017/11/20 15:57
*/
@Override
public final int getItemViewType(int position) {
if (mHeadview != null && position < ) {
return ITEM_TYPE_HEADVIEW;
} else if (mFootview != null && position == getItemCount() - ) {
return ITEM_TYPE_FOOTVIEW;
} else {
return getNormalItemViewType(hasHeadView ? position - : position);
}
}
/**
* 子類實作此方法,等同于直接實作{@link RecyclerView.Adapter#getItemViewType(int)} ()}
*
* @return The view type of this ViewHolder.
* @author fengzhen
* @version v6.3.0, 2017/11/20 15:52
*/
protected int getNormalItemViewType(int position) {
return super.getItemViewType(position);
}
/**
* 不可重寫
* 子類實作{@link RecyclerViewExtendAdapter#getNormalItemCount()}
*
* @author fengzhen
* @version v6.3.0, 2017/11/20 16:10
*/
@Override
public final int getItemCount() {
return getNormalItemCount() + (mHeadview == null ? : ) + (mFootview == null ? : );
}
/**
* 子類實作此方法,等同于實作{@link RecyclerView.Adapter#getItemCount()}
*
* @author fengzhen
* @version v6.3.0, 2017/11/20 16:06
*/
protected abstract int getNormalItemCount();
/**
* 不可重寫
* 子類實作{@link RecyclerViewExtendAdapter#onNormalCreateViewHolder(ViewGroup, int)}
*
* @author fengzhen
* @version v6.3.0, 2017/11/20 16:10
*/
@Override
public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case ITEM_TYPE_HEADVIEW:
return new HeadViewHolder(mHeadview);
case ITEM_TYPE_FOOTVIEW:
return new FootViewHolder(mFootview);
default:
return onNormalCreateViewHolder(parent, viewType);
}
}
/**
* 子類實作此方法,等同于實作{@link RecyclerView.Adapter#onCreateViewHolder(ViewGroup, int)}
*
* @author fengzhen
* @version v6.3.0, 2017/11/20 16:06
*/
protected abstract RecyclerView.ViewHolder onNormalCreateViewHolder(ViewGroup parent, int viewType);
/**
* 不可重寫
* 子類實作{@link RecyclerViewExtendAdapter#onNormalBindViewHolder(RecyclerView.ViewHolder, int, int)}
*
* @author fengzhen
* @version v6.3.0, 2017/11/20 16:10
*/
@Override
public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int itemViewType = getItemViewType(position);
switch (itemViewType) {
case ITEM_TYPE_HEADVIEW:
case ITEM_TYPE_FOOTVIEW:
break;
default:
onNormalBindViewHolder(holder, hasHeadView ? position - : position, itemViewType);
break;
}
}
/**
* 子類實作此方法,等同于實作{@link RecyclerView.Adapter#onBindViewHolder(RecyclerView.ViewHolder, int)}
*
* @author fengzhen
* @version v6.3.0, 2017/11/20 16:06
*/
protected abstract void onNormalBindViewHolder(RecyclerView.ViewHolder holder, int position, int itemViewType);
private class HeadViewHolder extends RecyclerView.ViewHolder {
public HeadViewHolder(View itemView) {
super(itemView);
}
}
private class FootViewHolder extends RecyclerView.ViewHolder {
public FootViewHolder(View view) {
super(view);
}
}
}
7.去掉滑動收尾的下拉動畫
設定屬性:
android:overScrollMode="never"
複雜布局層數簡化
1. 布局要求
實作如下的布局:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyMwcDMyQjM1EDNygDM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
2. 布局解析
實作方式一: 直接硬布局,最外層用一個ScrollView,裡面用 TextView + ListView + TextView + GridView。還需要對ListView和GridView進行重寫測量方法,才能實作效果。
實作方式二: 整個作為一個ListView,Title、ListView 、GridView都看成是父ListView 的一個Item。但是對于其中的互動邏輯的代碼不要控制,寫出來肯定很不“優美”。
實作方式三: 使用RecycleView的GridLayoutManager布局,通過item type 設定,将Title、ListVite item和GridView item都作為RecycleView 的item,使用一層布局,這也是推薦的做法。
3. 布局實作
實作布局的重點在于GridLayoutManager的setSpanSizeLookup()方法。
設定布局管理器:
// 設定布局管理器
private void initLayout() {
// 這裡的4,取所需列數的最小公倍數
mRecyclerView1.setLayoutManager(new GridLayoutManager(this, ));
}
Adapter實作:
/**
* Created by fengzhen.
*
* recyclerView 擴充卡
*/
public class RecyclerViewAdapter1 extends RecyclerView.Adapter<RecyclerViewAdapter1.ViewHolder> {
// 布局類型
public static final int TITLE_1 = ;
public static final int TITLE_2 = ;
public static final int LINEAR_1 = ;
public static final int GRID_2 = ;
// 資料集
private List<String> arrayList;
public RecyclerViewAdapter1(List<String> list) {
arrayList = list;
}
/**
* 查找item布局,強制綁定ViewHolder
*/
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// 沒做類型判定 需要時判斷 viewType
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item1, parent, false);
return new ViewHolder(view);
}
/**
* 根據加載位置進行資料展示
*/
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// 沒做類型判定 需要時判斷 viewType
holder.textView1.setText(arrayList.get(position));
}
/**
* 實作布局的重點
*/
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
/**
* 處理GridLayoutManager布局
* LayoutManager列數設定為 所有可能出現的列數的最小公倍數
* 具體的列數,傳回在總列數的比例
* 例:可能出現的列數有: 1、3、4、7
* LayoutManager的列數設定為 : 1*3*4*7 = 84;
* 對應列數的傳回值: 84、 28、21、12;
*/
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if(manager instanceof GridLayoutManager) {
final GridLayoutManager gridManager = ((GridLayoutManager) manager);
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
int type = getItemViewType(position);
switch (type){
case TITLE_1:
case TITLE_2:
return ;
case LINEAR_1:
return ;
case GRID_2:
return ;
default:
return ;
}
}
});
}
}
/**
* 傳回不同的類型
*
* @author fengzhen
* @version v1.0, 2017/8/23 15:47
*/
@Override
public int getItemViewType(int position) {
if (position == ) {
return TITLE_1;
} else if (position < ) {
return LINEAR_1;
} else if (position == ) {
return TITLE_2;
} else {
return GRID_2;
}
}
/**
* 類似listview中的方法,擷取總item數
*/
@Override
public int getItemCount() {
return arrayList.size();
}
/**
* 繼承RecycleView的ViewHolder,對item控件進行初始化
*/
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView textView1;
public ViewHolder(View itemView) {
super(itemView);
textView1 = (TextView) itemView.findViewById(R.id.textView1);
}
}
}