RecyclerView浅析
RecyclerView 和 ListView 异同点
作为ListView的升级版,RecyclerView和ListView的相同点包括:
都支持列表的展示,能够滚动(请原谅我的废话)
同样通过Adapter来实现数据与View的绑定
都支持通过ViewType来支持不同的显示样式
他们的区别点更多:
ViewHolder对于ListView来说,是最佳实践,但并非强制要求,而对RecyclerView来说,则是强制要求
ListView支持Item devider属性,而RecyclerView则需要通过设置ItemDecoration来实现
ListView支持Header,而RecyclerView并不支持
ListView支持ItemClickListener, 而RecyclerView则支持ItemTouchListener
RecyclerView可以通过匹配LayoutParamter来支持Grid,StaggeredGrid效果,并且支持横向滚动
AdsListView(ListView的基类).LayoutParameter不支持margin,而RecyclerView可以
RecyclerView的实现
类结构
与ListView相比,RecyclerView胜在分工明确:
Recycler负责实现ViewHolder的回收重用
LayoutManager负责实现itemview的布局,并且处理滚动动画效果
ItemDecoration负责在LayoutManager的基础上,微调itemview的布局
Adapter负责创建ViewHolder,以及ViewHolder和data数据之间的绑定关系
这样的设计,解耦了RecyclerView的内部模块,每个内部模块可以专心的实现自己的功能,而不必担心影响其他的部分,另外,提供了更加丰富有效的定制手段来自定义部分效果。
核心代码分析
以下拉滚动为例分析RecyclerView的实现逻辑:
1.0 onTouchEvent
public void onTouchEvent(MotionEvent e){
......
final boolean canScrollHorizontally = mLayout.canScrollHorizontally();
final boolean canScrollVertically = mLayout.canScrollVertically();
......
final MotionEvent vtev = MotionEvent.obtain(e);
......
switch (action) {
......
case MotionEvent.ACTION_MOVE:{
......
final int x = (int) (MotionEventCompat.getX(e, index) + 0.5f);
final int y = (int) (MotionEventCompat.getY(e, index) + 0.5f);
int dx = mLastTouchX - x;
int dy = mLastTouchY - y;
......
mLastTouchX = x - mScrollOffset[0];
mLastTouchY = y - mScrollOffset[1];
if (scrollByInternal(canScrollHorizontally ? dx : 0,
canScrollVertically ? dy : 0,
vtev)) {
getParent().requestDisallowInterceptTouchEvent(true);
}
}
}
}
计算与上一个touch消息相比,Y轴的位移,并调用scrollByInternal函数
1.1 scrollByInternal
boolean scrollByInternal(int x, int y, MotionEvent ev) {
int unconsumedX = 0, unconsumedY = 0; int consumedX = 0, consumedY = 0;
......
if (mAdapter != null) {
......
if (x != 0) {
consumedX = mLayout.scrollHorizontallyBy(x, mRecycler, mState);
unconsumedX = x - consumedX;
}
if (y != 0) {
consumedY = mLayout.scrollVerticallyBy(y, mRecycler, mState);
unconsumedY = y - consumedY;
}
......
}
......
}
调用LayoutManager.scrollVerticalBy函数
2.0 LinearLayoutManager.scrollVerticalBy
@Overridepublic int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
if (mOrientation == HORIZONTAL) {
return 0;
}
return scrollBy(dy, recycler, state);
}
简单的调用scrollBy函数
2.1 LinearLayoutManager.scrollBy
int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getChildCount() == 0 || dy == 0) {
return 0;
}
......
final int layoutDirection = dy > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
final int absDy = Math.abs(dy);
updateLayoutState(layoutDirection, absDy, true, state);
final int consumed =
mLayoutState.mScrollingOffset + fill(recycler, mLayoutState, state, false);
if (consumed < 0) {
return 0;
}
final int scrolled = absDy > consumed ? layoutDirection * consumed : dy;
mOrientationHelper.offsetChildren(-scrolled);
......
return scrolled;
}
主要调用了updateLayoutState, fill, mOrientationHelper.offsetChildren三个函数
2.2 LinearLayoutManager.updateLayoutState
private void updateLayoutState(int layoutDirection, int requiredSpace, boolean canUseExistingSpace, RecyclerView.State state) {
......