Material Design:TabLayout的使用
谷歌在Material Design中推出TabLayout以替代開源庫PagerSlidingTabStrip和ViewPagerIndicator的使用。事實上,這類indicator指示器的布局可謂是Android中最常見的布局設計了,TabLayout的出現給我們帶來一定便利,它的使用對開發者更加友好,並且和Toolbar一樣,配合material design的其他控件使用能輕易創造出酷炫的效果,下面我們快來學習它。
一、創建布局
使用TabLayout時,常與ViewPager一起關聯使用,布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"/>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"/>
</LinearLayout>
註意TabLayout中的tabMode屬性可選scrollable或fixed:
- scrollable可以滑動,向左對齊,如今日頭條,網易新聞就是scrollable,但是在Tab選項卡較少時會無法填滿TabLayout欄。
- fixed則無法滑動,每個選項卡平均分配空間,適合較少Tab選項卡的情況,當選項卡較多時,會出現每個選項卡內容無法顯示完整的情況,請大家大家根據情況選擇。
也可在代碼中使用以下方法設置。
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
或
tabLayout.setTabMode(TabLayout.MODE_FIXED);
還有另一個比較類似的屬性是app:tabGravity可選fill或centre:
- 當選項卡很少需要置於中心時,就需要用到centre,可以參考簡書手機App首頁標題欄“文章”,“專題”兩個選項卡的居中效果。
- 當選項卡需要填滿TabLayout布局時,則用到fill。
二、創建Fragment
public class PageFragment extends android.support.v4.app.Fragment {
public static final String ARG_PAGE = "ARG_PAGE";
private int mPage;
public static PageFragment newInstance(int page) {
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
PageFragment pageFragment = new PageFragment();
pageFragment.setArguments(args);
return pageFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPage = getArguments().getInt(ARG_PAGE);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_page, container, false);
TextView textView = (TextView) view;
textView.setText("Fragment #" + mPage);
return view;
}
}
Fragment的布局為
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
</TextView>
沒什麽說的,布局是一個簡單的TextView,通過實例化Fragment傳遞參數。
三、創建ViewPager的適配器
public class SimpleFragmentPagerAdapter extends FragmentPagerAdapter {
private Context context;
private static final String[] mTitles = {"tab1", "tab2", "tab3"};
public SimpleFragmentPagerAdapter(FragmentManager fm,Context context) {
super(fm);
this.context = context;
}
@Override
public android.support.v4.app.Fragment getItem(int position) {
return PageFragment.newInstance(position + 1);
}
@Override
public int getCount() {
return mTitles.length;
}
@Override
public CharSequence getPageTitle(int position) {
return mTitles[position];
}
}
四、在MainActivity中設置TabLayout
public class ThirdActivity extends FragmentActivity {
private SimpleFragmentPagerAdapter pagerAdapter;
private ViewPager viewPager;
private TabLayout tabLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
pagerAdapter = new SimpleFragmentPagerAdapter(getSupportFragmentManager(), this);
viewPager = (ViewPager) findViewById(R.id.viewpager);
tabLayout = (TabLayout) findViewById(R.id.tabs);
pagerAdapter = new SimpleFragmentPagerAdapter(getSupportFragmentManager(),this);
viewPager.setAdapter(pagerAdapter);
tabLayout.setupWithViewPager(viewPager);
}
}
TabLayout
五、自定義TabLayout樣式
你應該不會滿足於現在的TabLayout,實際應用中,往往會改變TabLayout的背景,字體大小和顏色,指示標的寬度和顏色等等。
在MainActivity布局下給TabLayout添加一個style如下:
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
style="@style/tab_style"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"/>
並且在styles中添加一個樣式:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="tab_style" parent="Widget.Design.TabLayout">
<!--<item name="tabMaxWidth">@dimen/tab_max_width</item>-->
<item name="tabPaddingStart">12dp</item>
<item name="tabPaddingEnd">12dp</item>
<item name="tabIndicatorColor">@color/colorAccent</item>
<item name="tabIndicatorHeight">4dp</item>
<item name="tabTextAppearance">@style/CustomTabTextAppearance</item>
<item name="tabBackground">@color/colorPrimary</item>
<item name="tabSelectedTextColor">@color/colorAccent</item>
</style>
<style name="CustomTabTextAppearance" parent="TextAppearance.Design.Tab">
<item name="android:textSize">18sp</item>
<item name="android:textColor">#FFFFFF</item>
<item name="textAllCaps">false</item>
</style>
</resources>
註意這裏的@color/colorAccent是粉色,@color/colorPrimary是藍色。
各個屬性所代表的含義:
1.tabMaxWidth:tab item的最大寬度,當app:tabMode="fixed"時不起作用,當app:tabMode="fixed"時才起作用。其中:
2.tabIndicatorColor:TabLayout指示器的顏色
3.tabIndicatorHeight:TabLayout指示器高度
4.tabPaddingStart:距離開始的長度
5.tabPaddingEnd:距離結束的長度
6.tabBackground:TabLayout背景
7.tabTextAppearance:TabLayout title字體屬性
8.tabSelectedTextColor:當前選擇的tab的字體顏色
9.textAllCaps:TabLayout創建的Tab默認的是true,如果設置圖標的話要設置成false。
這時再運行看下效果:
自定義style的TabLayout六、添加icon到tab
當前的TabLayout沒有方法讓我們去添加icon,我們可以使用SpannableString結合ImageSpan來實現,在SimpleFragmentPagerAdapter中:
//自己隨便從官網找幾個icon吧
private static final int[] mImgIds = {R.drawable.ic_stars_black_18dp,
R.drawable.ic_supervisor_account_black_24dp,
R.drawable.ic_today_black_24dp
};
//...
@Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
// return tabTitles[position];
Drawable image = context.getResources().getDrawable(mImgIds[position]);
image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
SpannableString sb = new SpannableString(" ");
ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BOTTOM);
sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return sb;
}
再運行可以看到:
添加icon的TabLayout
如果要同時把icon和text添加到tab同理,把getPageTitle()方法改為:
@Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
Drawable image = context.getResources().getDrawable(mImgIds[position]);
image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
// Replace blank spaces with image icon
SpannableString sb = new SpannableString(" " + mTitles[position]);
ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BOTTOM);
sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return sb;
}
七、添加自定義的view到tab
1、自定義一個簡單的tab布局tab_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_tab"
android:layout_width="30dp"
android:scaleType="fitXY"
android:layout_height="30dp"/>
<TextView
android:id="@+id/tv_tab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center" />
</LinearLayout>
2、在適配器中增加getTabView(...)方法:
public class SimpleFragmentPagerAdapter extends FragmentPagerAdapter {
private Context context;
private static final String[] mTitles = {"tab1", "tab2", "tab3"};
private static final int[] mImgIds = {
R.drawable.ic_today_black_24dp,
R.drawable.ic_supervisor_account_black_24dp,
R.drawable.ic_stars_black_18dp
};
public SimpleFragmentPagerAdapter(FragmentManager fm,Context context) {
super(fm);
this.context = context;
}
@Override
public android.support.v4.app.Fragment getItem(int position) {
return PageFragment.newInstance(position + 1);
}
@Override
public int getCount() {
return mTitles.length;
}
@Override
public CharSequence getPageTitle(int position) {
// return mTitles[position];
return null;
}
public View getTabView(int position) {
View view = LayoutInflater.from(context).inflate(R.layout.tab_layout, null);
ImageView iv_tab = (ImageView) view.findViewById(R.id.iv_tab);
TextView tv_tab = (TextView) view.findViewById(R.id.tv_tab);
iv_tab.setImageResource(mImgIds[position]);
tv_tab.setText(mTitles[position]);
return view;
}
}
3、在MainActivity中使用
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.viewpager);
tabLayout = (TabLayout) findViewById(R.id.tabs);
pagerAdapter = new SimpleFragmentPagerAdapter(getSupportFragmentManager(),this);
viewPager.setAdapter(pagerAdapter);
tabLayout.setupWithViewPager(viewPager);
for (int i = 0; i < tabLayout.getTabCount(); i++) {
//獲得到對應位置的Tab
TabLayout.Tab tab = tabLayout.getTabAt(i);
//設置自定義的標題
if (tab != null) {
tab.setCustomView(pagerAdapter.getTabView(i));
}
}
}
效果如下圖:
自定義view的TabLayout八、處理配置改變
當屏幕旋轉或者配置改變的時候,我們需要保存當前的狀態。
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(POSITION,tabLayout.getSelectedTabPosition());
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
viewPager.setCurrentItem(savedInstanceState.getInt(POSITION));
}
關於TabLayout的講解到此結束,當AppBar包裹Toolbar和TabLayout時,會有更好的效果。另外,設置自定義view後,自定義的style中tabSelectedTextColor就失效了,只找到了用selector使tab切換時圖片改變顏色的方法,沒找到改變文字顏色的方法,請各位有識之士不吝賜教。
本文參考文章:
android design library提供的TabLayout的用法
Android TabLayout 淺顯總結
Material Design:TabLayout的使用