Material Design 中的 Tab 設(shè)計可以參考官方文檔 https://material.io/guidelines/components/tabs.html#tabs-usage ,其中的 Tab 部分 Support Library 提供了專門的控件 TabLayout。
TabLayout 的簡單使用
首先需要添加 design 庫
compile 'com.android.support:design:25.4.0'
布局文件的定義如下:
<?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" />
</LinearLayout>
Activity 中添加 Tab:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.addTab(tabLayout.newTab().setText("1"));
tabLayout.addTab(tabLayout.newTab().setText("2"));
tabLayout.addTab(tabLayout.newTab().setText("3"));
}
}
效果如下圖:
Tab 不僅可以在 Java 代碼中添加七冲,還可以在布局文件中添加:
<?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.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"/>
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2"/>
<android.support.design.widget.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3"/>
</android.support.design.widget.TabLayout>
</LinearLayout>
修改指示器的顏色和高度
app:tabIndicatorColor="@color/colorPrimary"
app:tabIndicatorHeight="5dp"
效果如下:
修改文本顏色和選中后顏色
app:tabTextColor="@color/colorPrimary"
app:tabSelectedTextColor="@color/colorAccent"
效果如下:
app:tabMode
app:tabMode 可以設(shè)置 fixed 和 scrollable。
fixed 是默認(rèn)值瀑梗,用于 Tab 較少的情況,每個 Tab 平分寬度吧黄。
scrollable 用于 Tab 較多的情況廓八,可以滑動。如果 Tab 較少的話,會擠到屏幕左邊冒冬,如下圖:
添加刪除 Tab
可以用 newTab 來創(chuàng)建標(biāo)簽横侦,還可以用 addTab 來添加標(biāo)簽,還可以用 removeTab()狂芋,removeTabAt()榨馁,removeAllTabs() 來刪除標(biāo)簽
監(jiān)聽
添加 Tab 的監(jiān)聽
Tablayout.addOnTabSelectedListener()
刪除 Tab 的監(jiān)聽
Tablayout.removeOnTabSelectedListener()
清除所有監(jiān)聽
Tablayout.clearOnTabSelectedListeners()
TabLayout 和 ViewPager 配合使用
布局方式有兩種
第一種,ViewPager 里面嵌套 TabLayout
<?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.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.v4.view.ViewPager>
</LinearLayout>
第二種银酗,不嵌套
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
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"
app:tabMode="scrollable" />
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
這邊要注意辆影,不能 TabLayout 里面嵌套 ViewPager锯蛀,TabLayout 下面只能是 TabItem。
Activity 中的代碼如下
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
viewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager(), getData()));
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(viewPager);
}
private List<String> getData() {
List<String> dataList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
dataList.add(String.valueOf(i));
}
return dataList;
}
}
這里我們采用的是不嵌套的布局箫章,所以需要把 TabLayout 和 ViewPager 關(guān)聯(lián)一下
tabLayout.setupWithViewPager(viewPager);
MyPagerAdapter 代碼如下
public class MyPagerAdapter extends FragmentStatePagerAdapter {
private List<String> dataList;
public MyPagerAdapter(FragmentManager fm, List<String> dataList) {
super(fm);
this.dataList = dataList;
}
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(dataList.get(position));
}
@Override
public int getCount() {
return dataList.size();
}
@Override
public CharSequence getPageTitle(int position) {
return dataList.get(position);
}
}
我們重寫了 getPageTitle,它的作用是設(shè)置對應(yīng)的 Tab 的文字吏廉。
這邊我們用了 FragmentStatePagerAdapter 而不是 FragmentPagerAdapter,它們有什么區(qū)別呢孤荣?
FragmentPagerAdapter 在切換的時候不會銷毀 Fragment 對象寥院,只會銷毀 View 并調(diào)用 detach 方法臭蚁。這種方法適用于 Fragment 數(shù)比較少的情況。
FragmentStatePagerAdapter 在切換的時候會銷毀 Fragment 對象割疾,但是保存狀態(tài)的 Bundle 會在 onSaveInstanceState(Bundle) 被保存下來。這種方法適用于 Fragment 數(shù)比較多的情況。
MyFragment 代碼如下
public class MyFragment extends Fragment {
public static MyFragment newInstance(String data) {
Bundle args = new Bundle();
args.putString("content", data);
MyFragment fragment = new MyFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.my_fragment, container, false);
TextView content = (TextView) view.findViewById(R.id.content);
content.setText(getArguments().getString("content"));
return view;
}
}
運行效果如下:
TabLayout 中添加 Icon
1倡勇、通過 SpannableString 來添加 Icon
MyPagerAdapter 中厅目,getPageTitle 修改為用 SpannableString 來添加文字和圖標(biāo)
private Context context;
private List<String> dataList;
private List<Integer> iconResList;
public MyPagerAdapter(Context context, FragmentManager fm, List<String> dataList, List<Integer> iconResList) {
super(fm);
this.context = context;
this.dataList = dataList;
this.iconResList = iconResList;
}
......
@Override
public CharSequence getPageTitle(int position) {
SpannableString sb = new SpannableString(" " + dataList.get(position));
Drawable image = ContextCompat.getDrawable(context, iconResList.get(position));
image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BOTTOM);
sb.setSpan(imageSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return sb;
}
Activity 中添加圖標(biāo)
@Override
protected void onCreate(Bundle savedInstanceState) {
......
viewPager.setAdapter(new MyPagerAdapter(this, getSupportFragmentManager(), getData(), getIcon()));
......
}
......
private List<Integer> getIcon() {
List<Integer> iconList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
iconList.add(R.drawable.ic_android_black);
}
return iconList;
}
但是運行后友绝,發(fā)現(xiàn)還是只有文字先朦,沒有圖標(biāo)十电。這是因為 ImageSpan 在 TabLayout 默認(rèn)的樣式 textAllCaps 為 true 的時候是沒有效果的栈虚。通過以下方法將它改為 false 即可。
<style name="MyTabTextAppearance" parent="TextAppearance.Design.Tab">
<item name="textAllCaps">false</item>
</style>
<android.support.design.widget.TabLayout
......
app:tabTextAppearance="@style/MyTabTextAppearance" />
運行效果如下:
2、通過 setCustomView() 來添加 Icon
先定義 Tab 的布局文件
<?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:gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
然后在 MyPagerAdapter 中添加 getView 方法
@Override
public CharSequence getPageTitle(int position) {
return null;
}
public View getView(int position) {
View view = LayoutInflater.from(context).inflate(R.layout.tab_item, null);
((ImageView) view.findViewById(R.id.image_view)).setImageResource(iconResList.get(position));
((TextView) view.findViewById(R.id.text_view)).setText(dataList.get(position));
return view;
}
最后在 Activity 中通過 setCustomView 來設(shè)置 Tab 的 CustomView
for (int i = 0; i < tabLayout.getTabCount(); i++) {
tabLayout.getTabAt(i).setCustomView(myPagerAdapter.getView(i));
}
效果如下:
3唯欣、通過 setIcon() 來添加 Icon
其實 Tab 自己有 setIcon 方法來設(shè)置 Icon预烙。
for (int i = 0; i < tabLayout.getTabCount(); i++) {
tabLayout.getTabAt(i).setIcon(R.drawable.ic_android_black);
}
配合 MyPagerAdapter 的 getPageTitle狗热,同時添加文字和圖標(biāo)。