Tablayout,CoordinatorLayout与Behavior

Tablayout

        页签。通常与ViewPager联合使用。其各个部件如下:

常用属性

        tabIndicatorHeight:indicator的高度。

        tabIndicatorColor:indicator的颜色。

        tabTextAppearance:tab中文字的样式。注:textColor的选择器会无效,但最好设置上textColor属性,不然有可能报错。

        tabTextColor:未选中时tab中text的颜色。即上图中除tab2外所有tab中文字的颜色。
        tabSelectedTextColor:选中的tab的text颜色,即上图中tab2中文字颜色。
        tabBackground:每一个tab的背景,可以设置成选择器。

        tabMode:tablayout中tab模式。

        tabGravity:只有当tabMode为fixed时才有效,用于设置当tab的宽度没有tablayout宽时,tab页的宽该如何设置。对比图如下:

        tabPaddingStart及几个类似的属性:从第一图中可以看出,每一个tab view有一个padding,该属性就是这用设置这个padding的。

tabMode

        fixed:所有的tabs同时展示,各tabs的宽度相同,其值为tablayout的宽度除以tabs的个数。因此,该值一般常用于tabs个数比较少,并且要展示的内容较少的情况下。

        scrollable:tablayout可以左右滑动,并且各tabs的宽度也不相同(根据自己内容决定自己的宽度)。因此,它常用于tabs个数较多,或者内容较多的情况。

        两者对比图如下:


常用方法

        setupWithViewPager():将Tablayout与Viewpager关联。tab中显示的文字由viewpager的adapter中的getPageTitle()返回

        addTab()在代码中动态地为Tablayout添加tab。

        newTab():创建新的tab,addTab()的参数通常为该方法的返回值。

分析

        addTab(Tab)方法最终会走到addTabView(Tab tab, int pos,boolean setSelected)。源码如下:

    private void addTabView(Tab tab, int position, boolean setSelected) {
        final TabView tabView = createTabView(tab);
        mTabStrip.addView(tabView, position, createLayoutParamsForTabs());
        if (setSelected) {
            tabView.setSelected(true);
        }
    }

        createLayoutParamsForTabs()又调用了如下方法:

    private void updateTabViewLayoutParams(LinearLayout.LayoutParams lp) {
        if (mMode == MODE_FIXED && mTabGravity == GRAVITY_FILL) {
            lp.width = 0;
            lp.weight = 1;
        } else {
            lp.width = LinearLayout.LayoutParams.WRAP_CONTENT;
            lp.weight = 0;
        }
    }
        一般情况下,各个tab对应的view的宽度都是wrap_content,除非tabMode=fixed并且tabGravity=fill。

        当tabMode=fixed并且tabGravity=fill时,每一个tab对应的view的weight都是1,这也是为什么每一个tab宽度相同,并且为tablayout宽度除了tabs个数的原因。

CoordinatorLayout

        类似于一个增强型的framelayout。它主要用于两种情况:(1)做为整个布局有根布局;(2)为子视图之间进行手势协调的协调容器。

        比如在弹出snackbar时,可能会将处于屏幕底部的fab给覆盖住。如果fab放在coordinator中,那么snackbar弹起时fab会被顶上去,snackbar消失时fab又会回到原来的位置(注有些手机可能无法回到原来的位置,但可忽略)。

常用属性

        CoordinatorLayout自身并没有多少属性,其子View可以定义如下属性。

        layout_gravity:与普通的layout_gravity一样,用于决定自己所处的位置。

        layout_anchor:当前view定位时所依赖的的锚View(类似于坐标原点)。类似于相对布局中的layout_toRightOf等几个属性。

        layout_anchorGravity:与layout_gravity一起作用,确定当前view(child)相对于锚view(target)所处的位置。两个属性的作用结果分为两步进行:第一步layout_anchorGravity决定了child的左上角与target的什么位置重合,如layout_anchorGravity="bottom|right",那么child的左上角就与target的右下角重合。第二步,在第一步确定的基准点基础上,进行相应的移动。left(top)则向左(上)移动child的宽(高);center_vertical(center_horizontal)则向上(左)移动半个child的高(宽),bottom(right)不进行任何移动;默认layout_gravity的值为left|top

        layout_behavior:coordinatorlayout可以协调子view之间的触动事件,每一个子view需要有各自的滑动处理方式。该属性就是用来指定处理自己滑动事件的Behavior对象。因此,该属性的值为自定义Behavior子类的全名(即包名+类名)。如下:

app:layout_behavior="com.example.demo.FooterBehavior"
其中的值为自定义的一个Behavior子类。

Behavior

        CoordinatorLayout的一个内部类,用于子view指定自己的滑动处理方法。设置方式有两种:
        一、在xml布局文件中通过layout_behavior指定自己Behavior的全名。
        二、在代码中如下:
        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) tv.getLayoutParams();
        lp.setBehavior(new YourBehavior());

常用方法

        onStartNestedScroll:当CoordinatorLayout的某个子view开始滚动时。返回值表示child是否接受此次scroll事件,只有返回true时后继的scroll事件才会传递到child中。参数含义如下:
        第一个参数coordinatorLayout:当前的CoordinatorLayout对象;
        第二个参数child:关联该behavior的view对象;
        第四个参数target:将要滚动的view;
        第三个参数directTargetChild:包含target并且是CoordinatorLayout的直系子View(即该View的父布局就是CoordinatorLayout)的view,或者就是target(如果target本身是CoordinatorLayout的直系子View);
        第五个参数nestedScrollAxes:target的滚动方向。
        onNestedPreScroll:在本次滚动之前调用。系统会将手指的连续滑动分解成一个个ACTION_MOVE事件,在每一个move事件时都可得出与上一个move事件的距离,根据该距离对相应的view进行移动,从而实现滚动效果(类似于积分)。该方法就是在进行本次move移动之前调用。dx,dy分别表示本次move事件中滑动的距离,负数表示从左往右或者从上往下
        最后一个参数看CoordinatoryLayout#onNestedPreScroll的方法的一部分源码如下:
				mTempIntPair[0] = mTempIntPair[1] = 0;
                viewBehavior.onNestedPreScroll(this, view, target, dx, dy, mTempIntPair);
				
				xConsumed = dx > 0 ? Math.max(xConsumed, mTempIntPair[0])
                        : Math.min(xConsumed, mTempIntPair[0]);
                yConsumed = dy > 0 ? Math.max(yConsumed, mTempIntPair[1])
                        : Math.min(yConsumed, mTempIntPair[1]);

                consumed[0] = xConsumed;
                consumed[1] = yConsumed;
        从中可以看出第四个参数的所有元素一开始时肯定为0,并且对第四个参数的赋值最终会影响到consumed数组的值。而dx-counsumed[0]为target新的需要移动的距离,dy-consumed[1]为target新的需要移动距离。所以,最后一个参数在一定情况下可以影响target的移动距离。比如将最后一个参数的第两个元素置为2*dy,那么target的移动将与手指滑动方向相反:手指往上滑动时target往下移动,反之亦然。
        onStopNestedScroll:当nested scroll停止时(并不代表target停止滑动了,scroll停止后,target会进入fling阶段)调用,简单点可以认为是MotionAction.ACTION_UP时。
        onNestedScroll():在每一个move片段中,target移动完后的回调。第二个参数dyConsumed表示在本次move片段中target移动的距离(即target已经消费掉的距离),第四个参数dyUnconsumed表示在本次move事件中target未消费完而剩余的距离。第一、三个参数与此类似。例如本次move的距离是50(即onNestPreScroll中dy为50),而target只消费了30(可能滑动30后target便触底滑不动了),那么在该方法中dyConsumed便为30,而dyUnconsumed便为50-30=20。
        示例
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值