Android源码分析之OrientationHelper详解

前言:在Android的日常开发中,经常会与RecycleView打交道,如果你只是进行简单的列表展示,可能你不会用到OrientationHelper工具类。但是,如果你有更深层次的需求,对OrientationHelper和LayoutManager的理解和应用就必不可少了。本文,将从源码的角度,对OrientationHelper各参数及方法进行剖析。

OrientationHelper源码分析
之所以RecycleVIew会取代ListView,成为Android开发者们的新宠。不仅因为它对内存的优化做得更好,效率更高;还因为它能随意变换布局样式(水平列表、垂直列表、网格和瀑布流),自由性更强。用过RecycleView的同学都知道,想要让列表项竖直展示还是水平展示,只需要在初始化LayoutManager的时候指定显示方向即可,代码如下:

//初始化水平LayoutManager
LinearLayoutManager horizontalManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
//初始化竖直LayoutManager
LinearLayoutManager verticalManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);

OrientationHelper其实就是对RecycleView中子View管理的工具类,并且它只是一个抽象类,类中定义了获取View布局信息的相关方法。看到这里,可能会有部分同学就会有疑惑了。。抽象类?? 难道还要让我们自己去实现这些方法?? 稍安勿躁,继续分析源码,你会发现createHorizontalHelper(对应水平的LayoutManager)和createVerticalHelper(对应竖直的LayoutManager)方法已经为我们实现了这些方法,并且返回了OrientationHelper供我们使用。接下来,我们就对上面出现的问题一一剖析。

OrientationHelper抽象类源码:

public abstract class OrientationHelper {

    private static final int INVALID_SIZE = Integer.MIN_VALUE;

    protected final RecyclerView.LayoutManager mLayoutManager;

    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;

    public static final int VERTICAL = LinearLayout.VERTICAL;

    private int mLastTotalSpace = INVALID_SIZE;

    final Rect mTmpRect = new Rect();

    private OrientationHelper(RecyclerView.LayoutManager layoutManager) {
        mLayoutManager = layoutManager;
    }
 }

OrientationHelper抽象类其实很简单,就是定义一些参数、构造方法和获取View数据的抽象方法。真正需要关注的是createHorizontalHelper和createVerticalHelper的方法中的实现。

createHorizontalHelper方法详解:

    public static OrientationHelper createHorizontalHelper(
            RecyclerView.LayoutManager layoutManager) {
        return new OrientationHelper(layoutManager) {
            @Override
            public int getEndAfterPadding() {
            //返回RecycleView内容右边界位置(RecycleView的宽度,出去右侧内边距)
                return mLayoutManager.getWidth() - mLayoutManager.getPaddingRight();
            }

            @Override
            public int getEnd() {
            //返回RecycleView的宽度
                return mLayoutManager.getWidth();
            }

            @Override
            public void offsetChildren(int amount) {
            //水平横移子View amount距离
                mLayoutManager.offsetChildrenHorizontal(amount);
            }

            @Override
            public int getStartAfterPadding() {
            //获取RecycleView左侧内边距(paddingLeft)
                return mLayoutManager.getPaddingLeft();
            }

            @Override
            public int getDecoratedMeasurement(View view) {
            //返回view在水平方向上所占位置的大小(包括view的左右外边距)
                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
                        view.getLayoutParams();
                return mLayoutManager.getDecoratedMeasuredWidth(view) + params.leftMargin
                        + params.rightMargin;
            }

            @Override
            public int getDecoratedMeasurementInOther(View view) {
            //返回view在竖直方向上所占位置的大小(包括view的上下外边距)
                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
                        view.getLayoutParams();
                return mLayoutManager.getDecoratedMeasuredHeight(view) + params.topMargin
                        + params.bottomMargin;
            }

            @Override
            public int getDecoratedEnd(View view) {
            //返回view右边界点(包含右内边距和右外边距)在父View中的位置(以父View的(0,0)点位坐标系)
            //通俗地讲:子View右边界点到父View的(0,0)点的水平间距
                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
                        view.getLayoutParams();
                return mLayoutManager.getDecoratedRight(view) + params.rightMargin;
            }

            @Override
            public int getDecoratedStart(View view) {
            //返回view左边界点(包含左内边距和左外边距)在父View中的位置(以父View的(0,0)点位坐标系)
            //通俗地讲:子View左边界点到父View的(0,0)点的水平间距
                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
                        view.getLayoutParams();
                return mLayoutManager.getDecoratedLeft(view) - params.leftMargin;
            }

            @Override
            public int getTransformedEndWithDecoration(View view) {
            //返回view水平方向的结束位置(包含右侧的装饰,如你自定义了分割线(ItemDecoration),这个是带分割线宽度的结束位置),相对父容器
                mLayoutManager.getTransformedBoundingBox(view, true, mTmpRect);
                return mTmpRect.right;
            }

            @Override
            public int getTransformedStartWithDecoration(View view) {
            //返回view水平方向的开始位置(包含左侧的装饰,如你自定义了分割线(ItemDecoration),这个是减去分割线宽度的开始位置),相对父容器
                mLayoutManager.getTransformedBoundingBox(view, true, mTmpRect);
                return mTmpRect.left;
            }

            @Override
            public int getTotalSpace() {
            //返回Recycleview水平内容区空间大小(宽度,除去左右内边距)
                return mLayoutManager.getWidth() - mLayoutManager.getPaddingLeft()
                        - mLayoutManager.getPaddingRight();
            }

            @Override
            public void offsetChild(View view, int offset) {
            //相当于layout效果(在layout基础上偏移offset像素)
                view.offsetLeftAndRight(offset);
            }

            @Override
            public int getEndPadding() {
            //返回Recycleview右侧内边距大小
                return mLayoutManager.getPaddingRight();
            }

            @Override
            public int getMode() {
            //获取Recycleview宽度测量模式
                return mLayoutManager.getWidthMode();
            }

            @Override
            public int getModeInOther() {
           //获取Recycleview高度测量模式
                return mLayoutManager.getHeightMode();
            }
        };
    }

这即是createHorizontalHelper方法中创建的OrientationHelper帮助类,它主要用于对水平LayoutManager提供帮助。具体方法的返回值含义,在代码中已经进行了详细的注解,这里就不再一一解释了。除此之外,还有针对竖直LayoutManager而提供的OrientationHelper工具类,由createVerticalHelper方法提供。它的返回值含义和createHorizontalHelper方法中各返回值含义类似,大家可以一一对应,这里就不过多赘述。

Ps:上面提到了ItemDecoration,这个类是为RecycleView的Item提供装饰的类。用它添加Item的装饰,我们需要实现它里面的两个重要方法,分别是:getItemOffsets(设置View在左,上、右和下方的留白空间大小)和onDraw(绘制留白空间)。特别注意:getItemOffsets方法中的outRect很有意思,如下:

 public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        //outRect设置view在几个方向上的留白大小。类似如下对应关系
        //outRect.left marginLeft
       //outRect.top marginTop
       //outRect.right marginRight
       //outRect.bottom marginBottom
       //但实际上并不是设置margin,只是在在这几个方位上留白,方便用户绘制view间的装饰
        }
    原文作者:legendCoder
    原文地址: https://blog.csdn.net/chenbaige/article/details/80524508
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞