材料设计是 google 官方在 2014 年谷歌大会上提出的界面设计规范,力求通过对光效、表面质感、运动感的控制,来提升安卓界面交互体验。
虽然 Material Design 已经推出了三年,但是实际应用上,Toolbar 和 TabLayout 是使用最广泛的。由于需求,这段时间特意提取了 TabLayout 的代码,对于许多只需要 Tablayout 的需求,其实不需要把整个 Design 包导入,还能减小体积。
一、起因
项目现在用的是 HorizontalScrollView + ImageButton + ListView 的方式展示数据,根据点击来决定 ListView 显示的数据。但是由于代码陈旧,里面的弱标志又太多,所以希望能重构一下代码,让它的可读性更高一些,顺便优化一下交互。
二、起步
有了需求,需要先写个 demo 填坑。去年的时候 TabLayout + ViewPager + PtrListView 显示数据我是做过的,因此没有什么难度。但是到了工程里还是有了一些问题。这里记录一下。
三、问题
- 1.使用 TabLayout 一直有资源不能找到,或者编译后就报错( 有点尴尬,复现不出来了 )
需要使用向后兼容的 AppCompatTheme 和 AppCompatActivity。如果工程的 BaseActivity 是 Activity 的子类,BaseTheme 也不是 AppCompatTheme 的子类,并且因为一些特殊的原因不能改动的话,可以在清单文件中注册页面时,在 TabActivity 下添加一条属性:android:theme="@style/Theme.AppCompat.Light.NoActionBar"
- 2.自定义 TabLayout 中的 TabView 时,CusView 中的 ImageView 在第一次进入页面的时候,不会变为 select 状态
项目里我查看了 22.0.2 版本的源码,发现在 TabLayout.setSelectedTabView() 中并没有对 CusView 做 select 状态的修改。换一种方式,如果直接放入 Icon,发现除了第一次进入,后面的部分都是有正常的状态改变的。然而修改选中状态的方法的权限却不是公有,只能通过反射获取。或者,你可以通过 viewpager.setCurrentItem(1),viewpager.setCurrentItem(0),来达到目的。反正我是这么做的。= =
- 3.项目中需要 TabLayout 的 indicator比 TabView 短一些
不同版本的 Design 包,对于 SlidingTabStrip 的绘制方法不同,主要看当前版本下 SlidingTabStrip.setIndicatorPosition 和 SlidingTabStrip.onDraw 方法。onDraw 方法在 25.3.1 不知道为什么改名成 draw 方法了。如果需要修改这个效果请关注上面两个方法中对应 left 和 right 的值。如果是使用 25.3.1 的版本,不妨使用我上面的链接,属性等等都已经修改好了。
四、使用
Design 包的更新速度还算可以,但是每个包总是会改动一些方法的实现,起码 22.0.1 和 25.3.1 差别还是有的,在网络上,许许多多的使用教程都还是 2014 2015 年的教程,尝试了一下,许多方法的参数已经不同了,也有的权限变更,有的方法干脆就被干掉了,完全找不到存在过的痕迹,因此这里简单写一下 25.3.1 的使用。
1. 简单使用 TabLayout + ViewPager +Fragment
布局:
LinearLayout - vertical
==>TabLayout - main_tablayoutId
==>ViewPager - main_viewpagerId
MainActivity:
// find view
mTabLayout = ((TabLayout) findViewById(R.id.main_tablayoutId));
mViewPager = ((ViewPager) findViewById(R.id.main_viewpagerId));
// init data
final String[] titles = {"111","222","333","444","555"};// tab title
final List<Fragment> fragments = new ArrayList();// tab fragment
for (int i = 0; i < 5; i++) {
fragments.add(new BlankFragment());
}
// 设置 viewpager 适配器
mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {// 获取 tab 对应的 fragment
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
@Override
public CharSequence getPageTitle(int position) {// 获取 tab 对应的 title
return titles[position];
}
});
mTabLayout.setTabGravity(TabLayout.GRAVITY_FILL);// 设置排列模式 (充满 - 居中)
mTabLayout.setTabMode(TabLayout.MODE_FIXED);// 设置滚动模式 (固定 - 滚动)
mTabLayout.setupWithViewPager(mViewPager);// 需要在 viewpager 设置适配器之后
2.TabLayout 属性介绍
// 常用
// 指示器
tabIndicatorHeight
tabIndicatorColor
// 文字 - 在没有设置 CustomView 的时候有效
tabTextColor
tabSelectedTextColor
// 背景
tabBackground
// 模式
tabMode
tabGravity
// tabview 的 padding 值比较大时会填掉 tabview 的内容布局,tablayout 的高度并不会变化(内部有一个 defaultHeight 值,决定了 tablayout 的高度)
tabPadding
tabPaddingStart
tabPaddingTop
tabPaddingEnd
tabPaddingBottom
// text 的样式
tabTextAppearance
// 第一个 tab 距离左边的偏移距离
tabContentStart
// tab 最小宽度
tabMinWidth
五、关于自定义 TabView
链接:Android Design Support Library系列之一:TabLayout的使用
上面的文章我觉得写得总结得很到位了,我就不再班门弄斧。但是文章最后写的关于 indicator 宽度的设置部分提到了一个方法 setIndicator(tablayout, marginLeft, marginRight) ,这个方法在我现在使用的 25.3.1 版本中并没有,所以才做了上面的提取操作。有可能还会有其他方法的不同,各位看官望知悉。