对于移动应用来说,导航栏是非常重要的一个组件。合适的导航栏可以帮助用户快速准确地找到自己所需的功能,从而提高用户体验。而TabLayout和ViewPager的结合使用可以大大提升移动应用导航栏的用户体验。
一、 TabLayout和ViewPager的基本使用
首先,我们需要知道TabLayout和ViewPager是什么。TabLayout是Google在Design Support库中提供的一种新的导航栏控件,它可以方便地实现标签页布局。ViewPager是一个可滑动的容器视图,通常它用来存放Fragment,使得应用可以在不同的Fragment之间进行切换。
在使用TabLayout和ViewPager之前,首先需要在项目的build.gradle文件中添加以下依赖:
<dependency>
<groupId>com.android.support</groupId>
<artifactId>design</artifactId>
<version>23.1.1</version>
</dependency>
接下来,我们需要创建一个布局文件,以添加TabLayout和ViewPager:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:tabMode="scrollable"
android:tabTextColor="@android:color/white"
android:textColorSecondary="@android:color/white"
android:scrollbars="none" />
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
在这个布局中,我们首先添加了一个TabLayout控件,并且在其中定义了一些属性。其中,tabMode用于设置标签的模式,可以是fixed(固定标签宽度)或者scrollable(可滑动);tabTextColor用于设置标签字体的颜色;textColorSecondary用于设置选中标签的颜色;scrollbars用于设置标签中的卷轴是否显示。
接下来,我们添加了一个ViewPager控件,用于存放Fragment。我们在这个ViewPager中添加了一个FragmentPagerAdapter对象,并在其中实现了getItem()和getCount()方法,用于获取每个Fragment和Fragment的总数。
public class SampleFragmentPagerAdapter extends FragmentPagerAdapter {
final int PAGE_COUNT = 3;
private String tabTitles[] = new String[] { "Tab1", "Tab2", "Tab3" };
public SampleFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return PAGE_COUNT;
}
@Override
public Fragment getItem(int position) {
return PageFragment.newInstance(position + 1);
}
@Override
public CharSequence getPageTitle(int position) {
return tabTitles[position];
}
}
在这个FragmentPagerAdapter中,我们创建了三个Fragment,每一个Fragment都可以使用PageFragment.newInstance()方法来创建,这里我们传入了一个代表页面位置的参数。
最后,在我们的Activity中,我们需要做以下几个操作:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 设置ViewPager
ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
viewPager.setAdapter(new SampleFragmentPagerAdapter(getSupportFragmentManager()));
// 设置TabLayout
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(viewPager);
}
在这个Activity中,我们先获取了ViewPager和TabLayout的实例,并且在ViewPager中设置了我们刚才创建的FragmentPagerAdapter。接着,我们调用了TabLayout的setupWithViewPager()方法,使得TabLayout和ViewPager进行了绑定。
二、 使用自定义布局和样式
虽然TabLayout已经提供了默认的布局样式,但是我们也可以使用自定义的布局和样式。下面是一个简单的自定义TabLayout布局样式的例子:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.TabLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tab_layout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:tabIndicatorColor="@android:color/white"
android:tabSelectedTextColor="@android:color/white"
android:tabTextColor="@color/tab_text_color"
app:tabIndicatorHeight="4dp"
app:tabMode="scrollable"
app:tabPaddingEnd="16dp"
app:tabPaddingStart="16dp"
app:tabTextAppearance="@style/MyTabLayoutTextAppearance"
app:tabSelectedBackground="@drawable/tab_selector"
app:tabBackground="@drawable/tab_selector" />
在这个布局样式中,我们定义了一些新的属性,例如tabIndicatorColor用于设置标签指示器的颜色,tabSelectedTextColor用于设置选中标签字体的颜色。我们还可以在TabLayout里面设置tabPaddingEnd、tabPaddingStart等属性,用于设置标签的边距。如果我们想在标签中添加图片或者自定义样式,我们可以通过app:tabTextAppearance属性来实现。例如下面这个定义了自定义样式的TabLayout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.TabLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tab_layout3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
app:tabIndicatorColor="@android:color/white"
app:tabSelectedTextColor="@android:color/white"
app:tabTextColor="@color/tab_text_color"
app:tabIndicatorHeight="4dp"
app:tabMode="scrollable"
app:tabPaddingEnd="16dp"
app:tabPaddingStart="16dp"
app:tabTextAppearance="@style/MyTabLayoutTextAppearance"
app:tabSelectedBackground="@drawable/tab_selector"
app:tabBackground="@drawable/tab_selector" />
在这个自定义样式布局中,我们定义了一个样式文件——MyTabLayoutTextAppearance,用于定义标签的样式。
<style name="MyTabLayoutTextAppearance" parent="TextAppearance.Design.Tab">
<item name="android:textSize">14sp</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">?attr/colorPrimary</item>
</style>
在这个样式文件中,我们定义了标签字体的大小(textSize)、粗细(textStyle)和颜色(textColor)。
三、 TabLayout和ViewPager的进阶用法
除了基本的使用方法外,TabLayout和ViewPager还有一些很有用的进阶用法,例如TabLayout中添加图标、重复点击标签的处理和联动标题栏等。下面我们来看一下这些用法具体是怎么实现的。
1. TabLayout中添加图标
我们可以在TabLayout中添加图标,可以让我们的导航栏变得更加美观。使用方法也很简单,只需要在创建FragmentPagerAdapter的时候,重写getPageIcon()方法即可。下面是实现代码:
@Override
public Fragment getItem(int position) {
return PageFragment.newInstance(position + 1);
}
@Override
public int getCount() {
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
Drawable drawable = null;
switch (position) {
case 0:
drawable = getResources().getDrawable(R.drawable.tab_home_selector);
break;
case 1:
drawable = getResources().getDrawable(R.drawable.tab_discovery_selector);
break;
case 2:
drawable = getResources().getDrawable(R.drawable.tab_me_selector);
break;
default:
break;
}
drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
SpannableString spannableString = new SpannableString(" " + tabTitles[position]);
ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM);
spannableString.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannableString;
}
public Drawable getDrawable(int position) {
Drawable drawable = null;
switch (position) {
case 0:
drawable = getResources().getDrawable(R.drawable.tab_home_selector);
break;
case 1:
drawable = getResources().getDrawable(R.drawable.tab_discovery_selector);
break;
case 2:
drawable = getResources().getDrawable(R.drawable.tab_me_selector);
break;
default:
break;
}
return drawable;
}
在这个例子中,我们在getPageTitle()方法中获取了每个标签页所对应的图片,并通过ImageSpan将图片和文字整合在了一起。
2. 重复点击标签的处理
在默认情况下,如果我们重复点击同一个标签,ViewPager是不会响应的。但是在某些情况下,我们需要重复点击同一个标签时也能够响应,这时候我们可以使用addOnTabSelectedListener()和setOnTouchListener()方法来实现。下面是实现代码:
tabLayout.addOnTabSelectedListener(new TabLayout.BaseOnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
if (tabLayout.getSelectedTabPosition() == tab.getPosition()) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.view_pager + ":" + viewPager.getCurrentItem());
if (fragment != null && fragment instanceof PageFragment) {
((PageFragment) fragment).scrollToTop();
}
}
}
});
for (int i = 0; i < tabLayout.getTabCount(); i++) {
View tab = ((ViewGroup) tabLayout.getChildAt(0)).getChildAt(i);
tab.setTag(i);
tab.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mLastPos = (Integer) v.getTag();
} else if (event.getAction() == MotionEvent.ACTION_UP
&& mLastPos == (Integer) v.getTag()
&& tabLayout.getSelectedTabPosition() == (Integer) v.getTag()) {
onDoubleClick((Integer) v.getTag());
}
return false;
}
});
}
private void onDoubleClick(int position) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.view_pager + ":" + viewPager.getCurrentItem());
if (fragment != null && fragment instanceof PageFragment) {
((PageFragment) fragment).scrollToTop();
}
}
在这个代码片段中,我们首先使用addOnTabSelectedListener()方法来监听选中的标签,并在onTabReselected()方法里面判断是否为第一次点击标签。如果是第一次点击标签,我们就不做任何处理,否则我们可以在这个方法里面处理重复点击标签的事件。
接着,我们使用了setOnTouchListener()方法来监听标签的点击事件。在这个方法中,我们首先获取了当前点击的标签位置,并且判断是否为重复点击。如果是重复点击,就会调用onDoubleClick()方法,处理我们需要处理的事件。