Tablayout
常用属性
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_behavior:coordinatorlayout可以协调子view之间的触动事件,每一个子view需要有各自的滑动处理方式。该属性就是用来指定处理自己滑动事件的Behavior对象。因此,该属性的值为自定义Behavior子类的全名(即包名+类名)。如下:
app:layout_behavior="com.example.demo.FooterBehavior"
其中的值为自定义的一个Behavior子类。
Behavior
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) tv.getLayoutParams();
lp.setBehavior(new YourBehavior());
常用方法
onStartNestedScroll:当CoordinatorLayout的某个子view开始滚动时。返回值表示child是否接受此次scroll事件,只有返回true时后继的scroll事件才会传递到child中。参数含义如下: 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往下移动,反之亦然。