ScrollingViewBehavior 源码分析

代码路径位于:com.google.android.material.appbar.AppBarLayout
首先看下构造方法:分为无参和有参两种类型。
有参方法主要是设置了behavior_overlapTop这个值。暂时不看这个值。

      public ScrollingViewBehavior() {
        }

        public ScrollingViewBehavior(Context context, AttributeSet attrs) {
            super(context, attrs);
            TypedArray a = context.obtainStyledAttributes(attrs, styleable.ScrollingViewBehavior_Layout);
            this.setOverlayTop(a.getDimensionPixelSize(styleable.ScrollingViewBehavior_Layout_behavior_overlapTop, 0));
            a.recycle();
        }

来看看依赖,解释一下,第一个不用说,就是当前的CoordinatorLayout,第二个参数是我们设置这个Behavior的View,第三个是我们关心的那个View。这里意思是我要依赖AppBarLayout。依赖完了如何监听依赖变化呢,那是另外一个方法。

   public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
            return dependency instanceof AppBarLayout;
        }

这里调用了offsetChildAsNeeded。接着看。

    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
            this.offsetChildAsNeeded(child, dependency);
            this.updateLiftedStateIfNeeded(child, dependency);
            return false;
        }
     private void offsetChildAsNeeded(View child, View dependency) {
     //获取到Depency的设置的Behavior,这里就是AppBarLayout 上设置的Behavior。
            androidx.coordinatorlayout.widget.CoordinatorLayout.Behavior behavior = ((androidx.coordinatorlayout.widget.CoordinatorLayout.LayoutParams)dependency.getLayoutParams()).getBehavior();
            //强转
            if (behavior instanceof AppBarLayout.BaseBehavior) {
                AppBarLayout.BaseBehavior ablBehavior = (AppBarLayout.BaseBehavior)behavior;
           //代表如果AppBarLayout移动了多少,那么被依赖的View也要移动多少。     
                ViewCompat.offsetTopAndBottom(child, dependency.getBottom() - child.getTop() + ablBehavior.offsetDelta + this.getVerticalLayoutGap() - this.getOverlapPixelsForOffset(dependency));
            }

        }

现在来看下AppBarLayout经常用到的Behavior。BaseBehavior 继承了HeaderBehvior。
现在来看下HeaderBehavior。
在这里插入图片描述
HeaderBehavior重写了onInterceptTouchEvent,onTouchEvent,并且创建了FlingRunnable类,这里不具体分析细节了,作为AppBarLayout的默认Behavior,主要实现的是Header的一些行为,注意这里的Header实际是AppBarLayout包裹的第一个View。
BaseBehavior 实现了NestScrollingParent的一些默认方法。这里来重点分析下。
canScrollChildren,因为此方法就判定了是否能够滚动子View。

        private boolean canScrollChildren(CoordinatorLayout parent, T child, View directTargetChild) {
            return child.hasScrollableChildren() && parent.getHeight() - directTargetChild.getHeight() <= child.getHeight();
        }

关键是判断getTotalScrollRange的滚动距离。默认totalScrollRange为-1.走else方法。

    public final int getTotalScrollRange() {
        if (this.totalScrollRange != -1) {
            return this.totalScrollRange;
        } else {
            int range = 0;
            int i = 0;

            for(int z = this.getChildCount(); i < z; ++i) {
                View child = this.getChildAt(i);
                AppBarLayout.LayoutParams lp = (AppBarLayout.LayoutParams)child.getLayoutParams();
                int childHeight = child.getMeasuredHeight();
                //这里获取子类的scrollFlags。如果不具备scroll 标识,那么滚动距离为0,不能滚动。直接brak,然后return 0.
                int flags = lp.scrollFlags;
                if ((flags & 1) == 0) {
                    break;
                }

                range += childHeight + lp.topMargin + lp.bottomMargin;
                if ((flags & 2) != 0) {
                    range -= ViewCompat.getMinimumHeight(child);
                    break;
                }
            }

            return this.totalScrollRange = Math.max(0, range - this.getTopInset());
        }
    }

好了,上文从ScrollingViewBahavior出发,来分析AppBarLayout的行为,Behavior作为一个比较新的类,主要配合CoordinatorLayout 来使用。CoordinatorLayout 通过dependence来协调各个设置Behavior View的行为。具体细节后续有机会再深入一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值