我们知道,Google在Android Design Supprot Library增加了很多Material Design控件,使我们能够更加轻松地开发出很多美观又灵活的UI。
其中新增的Tabs就是一个很实用的控件,我们可以使用Tabs+ViewPager+Fragment写出很多实用的控件,如图一所示,关于Tabs控件的更多信息,大家可以阅读官方文档:点击这里
但是,有些时候我们的需求可能不是正好会和官方提供的控件相吻合,受限于这些官方Material Design控件都是遵循固定的设计标准,有些时候我们不得不自己重写控件,或者寻求其它实现方式,比如如图二所示的UI:
因为官方的Tabs控件每个Tab是有最小宽度的(看源码好像是56dp),也就是说无论你字体设置多小,每个Tab的最小宽度都不会变,而且图二在Tab的右边还要添加一些单个的控件,这个时候显然我们自己定义Tab布局,然后结合ViewPager和Fragment使用起来更方便,图二中的每个Tab项的宽度我们可以随便调,在右边可以随意添加单独控件
下面讲一下图二的实现过程,其实主要就是在上方加入一个Tab布局,然后通过给ViewPager设置OnPageChangeListener监听器来动态改变Tab下面的Indicator Line的leftMargin来实现滑动效果,全部源码链接在文章末尾,下面列出主要实现代码:
首先是主界面上方的Tab布局
这个布局中主要就是上方的三个tab和最右边的一个imageView已经tab下方的indicatorLine,布局很简单,源代码就不再列出,感兴趣的可以参考文章最后的源码链接,不再赘述FragmentPagerAdapter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class BeautifyFragmentAdapter extends FragmentPagerAdapter {
private final List mFragments = new ArrayList<>();
public BeautifyFragmentAdapter(FragmentManager fm) {
super(fm);
}
public void addFragment(Fragment fragment) {
mFragments.add(fragment);
}
public Fragment getItem(int position) {
return mFragments.get(position);
}
public int getCount() {
return mFragments.size();
}
}定义Fragment用来展示数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public class BeautifyMainFragment extends Fragment {
public static final String PAGES_TYPE = "pages_type";
public static final int TYPE_WALLPAPER = 0;
public static final int TYPE_THEME = 1;
public static final int TYPE_FONT = 2;
private int mPageType;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPageType = getArguments().getInt(PAGES_TYPE);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.layout_beautify_fragment_list,
container, false);
textView.setText("第" + mPageType + "页");
return view;
}
}为ViewPager设置Adapter,关键代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28private void setupViews() {
mAdapter = new BeautifyFragmentAdapter(getSupportFragmentManager());
Bundle wallpaperData = new Bundle();
wallpaperData.putInt(BeautifyMainFragment.PAGES_TYPE,
BeautifyMainFragment.TYPE_WALLPAPER);
BeautifyMainFragment wallpaper = new BeautifyMainFragment();
wallpaper.setArguments(wallpaperData);
mAdapter.addFragment(wallpaper);
Bundle themeData = new Bundle();
themeData.putInt(BeautifyMainFragment.PAGES_TYPE,
BeautifyMainFragment.TYPE_THEME);
BeautifyMainFragment theme = new BeautifyMainFragment();
theme.setArguments(themeData);
mAdapter.addFragment(theme);
Bundle fontData = new Bundle();
fontData.putInt(BeautifyMainFragment.PAGES_TYPE,
BeautifyMainFragment.TYPE_FONT);
BeautifyMainFragment font = new BeautifyMainFragment();
font.setArguments(fontData);
mAdapter.addFragment(font);
viewPager.setAdapter(mAdapter);
viewPager.setCurrentItem(0);
viewPager.addOnPageChangeListener(onPageChangeListener);
}
这里只使用了一个Fragment文件,然后通过添加不同的参数来区分属于不同的page,当然也可以使用三个不同的Fragment文件针对不同的Tab,看个人习惯了
- 重写onPageScrolled方法实现indicatorLine的滑动
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74ViewPager.OnPageChangeListener onPageChangeListener = new ViewPager.OnPageChangeListener() {
/**
* position:当前页面,以及你点击滑动的页面
* offset:当前页面偏移的百分比
* offsetPixels:当前页面偏移的像素位置
*/
public void onPageScrolled(int position, float offset, int offsetPixels) {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams)
indicatorLine.getLayoutParams();
/**
* 利用currentIndex(当前所在页面)和position以及offset来
* 设置indicatorLine的左边距,这里有3个页面 滑动场景:
* 从左到右分别为0,1,2
* 0->1; 1->2; 2->1; 1->0
*/
if (currentIndex == 0 && position == 0) { // 0->1
lp.leftMargin = (int) (offset * tabWidthPx
+ currentIndex * tabWidthPx);
} else if (currentIndex == 1 && position == 0) { // 1->0
lp.leftMargin = (int) (-(1 - offset) * tabWidthPx
+ currentIndex * tabWidthPx);
} else if (currentIndex == 1 && position == 1) { // 1->2
lp.leftMargin = (int) (offset * tabWidthPx
+ currentIndex * tabWidthPx);
} else if (currentIndex == 2 && position == 1) { // 2->1
lp.leftMargin = (int) (-(1 - offset) * tabWidthPx
+ currentIndex * tabWidthPx);
}
indicatorLine.setLayoutParams(lp);
}
public void onPageSelected(int position) {
resetTextView();
switch (position) {
case 0:
wallpaperTitle.setTextColor(ContextCompat.getColor(
BeautifyMainActivity.this, R.color.bm_tab_text_selected));
break;
case 1:
themeTitle.setTextColor(ContextCompat.getColor(
BeautifyMainActivity.this, R.color.bm_tab_text_selected));
break;
case 2:
fontTitle.setTextColor(ContextCompat.getColor(
BeautifyMainActivity.this, R.color.bm_tab_text_selected));
break;
}
currentIndex = position;
}
/**
* state:滑动中的状态 有三种状态(0,1,2) 0:什么都没做 1:正在滑动 2:滑动完毕
*/
public void onPageScrollStateChanged(int state) {
}
};
/**
* 重置颜色
*/
private void resetTextView() {
wallpaperTitle.setTextColor(ContextCompat.getColor(
this, R.color.bm_tab_text));
themeTitle.setTextColor(ContextCompat.getColor(
this, R.color.bm_tab_text));
fontTitle.setTextColor(ContextCompat.getColor(
this, R.color.bm_tab_text));
}
Ok,到这里自定义的Tab+ViewPager+Fragment基本就实现了
源码地址:https://github.com/picksomething/ViewPagerWithTab