RecyclerView使用详解
第1节 常用属性理解
- stopScroll 停止滚动
1.1 setHasFixedSize 优化
官方推荐设置true 理解:告诉RecyclerView我的Item大小不会变,重新绘制的时候不用重新计算
解释博文:RecyclerView setHasFixedSize(true)的意义
1.2 RecyclerView.Adapter 不同数据不同布局
Demo.java
@Override
public int getItemViewType(int position) {
if (mTypeList.get(position) == 0) { // 横向
return TYPE_HORIZONTAL;
} else if (mTypeList.get(position) == 1) { // 纵向
return TYPE_VERTICAL;
} else {
return super.getItemViewType(position);
}
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == TYPE_HORIZONTAL) {
//inflate viewHorizontal
return new HorizontalViewHolder(viewHorizontal);
} else if (viewType == TYPE_VERTICAL) {
//inflate viewVertical
return new VerticalViewHolder(viewVertical);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
// 布局控制
if (holder instanceof HorizontalViewHolder) {
if (mHorizontalList != null) {
}
} else if (holder instanceof VerticalViewHolder) {
if (mVerticalList != null) {
}
}
1.3 滑动相关
- smoothScrollToPosition(int) 大量数据不理想,查看下文TopSmoothScroller案例,实践过程中TopSmoothScroller在下滑数据量很大的情况下置顶时间过长,滑动时间久会导致使用不舒适
- scrollToPosition(int) 滑动到指定位置
- scrollBy(int x,int y) 滑动指定像素
最终的置顶方案
int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();
//当可显示的item大于30时,直接置顶,否则丝滑滚动置顶
if (firstVisibleItemPosition > 30) {
mRecyclerView.scrollToPosition(0);
}else {
LinearSmoothScroller lss = new TopSmoothScroller(getActivity());
lss.setTargetPosition(0);
layoutManager.startSmoothScroll(lss);
}
第2节 OnScrollListener
2.1 三种滑动状态 newState
/**
* The RecyclerView is not currently scrolling.(静止没有滚动)
*/
public static final int SCROLL_STATE_IDLE = 0;
/**
* The RecyclerView is currently being dragged by outside input such as user touch input.
*(正在被外部拖拽,一般为用户正在用手指滚动)
*/
public static final int SCROLL_STATE_DRAGGING = 1;
/**
* The RecyclerView is currently animating to a final position while not under outside control.
*(自动滚动)
*/
public static final int SCROLL_STATE_SETTLING = 2;
2.2 onScrolled
onScrolled(RecyclerView recyclerView, int dx, int dy)
dx : 水平滚动距离
dy : 垂直滚动距离
第3节 LinearLayoutManager
2.1 常用API白话理解
- 位置数量相关
linearLayoutManager.getChildCount()
注解:得到显示屏幕内的list数量
mLinearLayoutManager.getItemCount()
注解:得到list的总数量
int position = linearLayoutManager.findFirstVisibleItemPosition();
注解: 得到显示屏内的第一个list的位置数position* 类似:findLastVisibleItemPosition
findFirstCompletelyVisibleItemPosition
注解:第一个完全显示的Item位置 类似findLastCompletelyVisibleItemPosition
View firstVisiableChildView = linearLayoutManager.findViewByPosition(position);
注解:根据position找到这个Item的View
public class TopSmoothScroller extends LinearSmoothScroller {
public TopSmoothScroller(Context context) {
super(context);
}
@Override protected int getHorizontalSnapPreference() {
return SNAP_TO_START;
}
@Override
protected int getVerticalSnapPreference() {
return SNAP_TO_START;//具体见源码注释
}
}
LinearSmoothScroller lss = new TopSmoothScroller(getActivity());
lss.setTargetPosition(0);
layoutManager.startSmoothScroll(lss);
注解:使滑动到RecyclerView指定位置
canScrollVertically和canScrollHorizontally
注解:是否能垂直/水平滑动
第4节 ItemDecoration
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
//根据itemView的位置设置边框大小
int position = parent.getChildAdapterPosition(view);
outRect.right = spaces;
}
参考:ItemDecoration解析(二) onDraw onDrawOver 画出Item之间的分割线
- RecyclerView系列二:RecyclerView.ItemDecoration的详解使用 【重点】图文结合讲得比较仔细
使用案例 RecyclerView分割线
第5 节 ItemTouchHelper
ItemTouchHelper.Callback callback = new DragItemTouchHelper(adapter);
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
touchHelper.attachToRecyclerView(recyclerView);
DragItemTouchHelper.java
public class DragItemTouchHelper extends ItemTouchHelper.Callback {
private DragAdapter mAdapter;
public DragItemTouchHelper(DragAdapter adapter) {
mAdapter = adapter;
}
/**
* 设置滑动类型标记
*
* @param recyclerView
* @param viewHolder
* @return 返回一个整数类型的标识,用于判断Item那种移动行为是允许的
*/
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
// dragFlags =0 禁止拖动
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; // 允许上下的拖动
//int swipeFlags = ItemTouchHelper.LEFT; // 只允许从右向左滑动
int swipeFlags = 0; // 不允许左右滑动
return makeMovementFlags(dragFlags, swipeFlags);
}
/**
* 拖拽切换 Item 的回调
*
* @param recyclerView
* @param viewHolder
* @param target
* @return true Item切换了位置,false Item没切换位置
*/
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}
/**
* Item 是否支持长按拖动
* @return true 支持长按操作,false 不支持长按操作
*/
@Override
public boolean isLongPressDragEnabled() {
return true;
}
/**
* Item 是否支持滑动
* @return true 支持滑动操作,false 不支持滑动操作
*/
@Override
public boolean isItemViewSwipeEnabled() {
return false;
}
/**
* Item被选中时候回调
*
* @param viewHolder
* @param actionState 当前Item的状态
* ItemTouchHelper.ACTION_STATE_IDLE 闲置状态
* ItemTouchHelper.ACTION_STATE_SWIPE 滑动中状态
* ItemTouchHelper#ACTION_STATE_DRAG 拖拽中状态
*/
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
// item 被选中的操作
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
viewHolder.itemView.setBackgroundResource(R.drawable.select_bg);
}
super.onSelectedChanged(viewHolder, actionState);
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
// 操作完毕后恢复颜色
viewHolder.itemView.setBackgroundResource(R.drawable.common_bg);
super.clearView(recyclerView, viewHolder);
}
/**
* 移动过程中重新绘制 Item,随着滑动的距离,设置 Item 的透明度
* @param isCurrentlyActive True if this view is currently being controlled by the user or
* false it is simply animating back to its original state.
*/
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
float x = Math.abs(dX) + 0.5f;
float width = viewHolder.itemView.getWidth();
float alpha = 1f - x / width;
viewHolder.itemView.setAlpha(alpha);
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
ViewHolder viewHolder,
float dX, float dY, int actionState, boolean isCurrentlyActive) {
}
}
Recylcerview 常用功能实现
水平滑动时不是最后一个Item, 都显示居中
左右联动 LinkActivity.java
滑动事件冲突
Android事件分发机制及滑动冲突解决方案【讲解比较详细】,提供两种方式
- 外部拦截法
- 内部拦截法
浅谈RecycleView嵌套RecycleView竖向滑动冲突解决
onInterceptTouchEvent == false; // 不向下分发,自己消费这次事件
onTouchEvent == true ;// 不向上分发,自己消费这次事件
parent.requestDisallowInterceptTouchEvent(true) // 请求父类true不拦截,false 请求父控件拦截
RecyclerView 源码解析
RecyclerView 优化
附录
参考博文
- 开发笔记-GridLayoutManager实现Item均匀分布
- Simple Android grid example using RecyclerView with GridLayoutManager (like the old GridView)
- RecyclerView滑动距离计算
开源库
BaseRecyclerViewAdapterHelper
集成配置allprojects { repositories { maven { url "https://jitpack.io" } } } dependencies { compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:VERSION_CODE' }
最新发布版本: release 截止2020-01-12最新 VERSION_CODE=3.0.0-beta11
RecyclerView 的使用方法