RecyclerView浅析

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) {

  ......

  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值