Material Design:TabLayout的使用

谷歌在Material Design中推出TabLayout以替代開源庫PagerSlidingTabStrip和ViewPagerIndicator的使用。事實上,這類indicator指示器的布局可謂是Android中最常見的布局設計了破讨,TabLayout的出現(xiàn)給我們帶來一定便利砂蔽,它的使用對開發(fā)者更加友好碑定,并且和Toolbar一樣流码,配合material design的其他控件使用能輕易創(chuàng)造出酷炫的效果,下面我們快來學習它延刘。

一漫试、創(chuàng)建布局

使用TabLayout時,常與ViewPager一起關聯(lián)使用碘赖,布局如下:

<?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可以滑動驾荣,向左對齊,如今日頭條普泡,網(wǎng)易新聞就是scrollable播掷,但是在Tab選項卡較少時會無法填滿TabLayout欄。
  • fixed則無法滑動劫哼,每個選項卡平均分配空間叮趴,適合較少Tab選項卡的情況割笙,當選項卡較多時权烧,會出現(xiàn)每個選項卡內容無法顯示完整的情況,請大家大家根據(jù)情況選擇伤溉。
    也可在代碼中使用以下方法設置般码。
tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
或
tabLayout.setTabMode(TabLayout.MODE_FIXED);
還有另一個比較類似的屬性是app:tabGravity可選fill或centre:
  • 當選項卡很少需要置于中心時,就需要用到centre乱顾,可以參考簡書手機App首頁標題欄“文章”板祝,“專題”兩個選項卡的居中效果。
  • 當選項卡需要填滿TabLayout布局時走净,則用到fill券时。

二孤里、創(chuàng)建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傳遞參數(shù)捌袜。

三、創(chuàng)建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樣式
你應該不會滿足于現(xiàn)在的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創(chuàng)建的Tab默認的是true息尺,如果設置圖標的話要設置成false携兵。

這時再運行看下效果:

自定義style的TabLayout

六、添加icon到tab

當前的TabLayout沒有方法讓我們去添加icon搂誉,我們可以使用SpannableString結合ImageSpan來實現(xiàn)徐紧,在SimpleFragmentPagerAdapter中:

//自己隨便從官網(wǎng)找?guī)讉€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

八嘲碧、處理配置改變

當屏幕旋轉或者配置改變的時候,我們需要保存當前的狀態(tài)父阻。

@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 淺顯總結

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末已烤,一起剝皮案震驚了整個濱河市鸠窗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌胯究,老刑警劉巖塌鸯,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異唐片,居然都是意外死亡丙猬,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門费韭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茧球,“玉大人,你說我怎么就攤上這事星持∏缆瘢” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵督暂,是天一觀的道長揪垄。 經(jīng)常有香客問我,道長逻翁,這世上最難降的妖魔是什么饥努? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮八回,結果婚禮上酷愧,老公的妹妹穿的比我還像新娘。我一直安慰自己缠诅,他們只是感情好溶浴,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著管引,像睡著了一般士败。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上褥伴,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天谅将,我揣著相機與錄音,去河邊找鬼噩翠。 笑死戏自,一個胖子當著我的面吹牛邦投,可吹牛的內容都是我干的伤锚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼屯援!你這毒婦竟也來了猛们?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤狞洋,失蹤者是張志新(化名)和其女友劉穎弯淘,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吉懊,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡庐橙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了借嗽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片态鳖。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖恶导,靈堂內的尸體忽然破棺而出浆竭,到底是詐尸還是另有隱情,我是刑警寧澤惨寿,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布邦泄,位于F島的核電站,受9級特大地震影響裂垦,放射性物質發(fā)生泄漏顺囊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一蕉拢、第九天 我趴在偏房一處隱蔽的房頂上張望包蓝。 院中可真熱鬧,春花似錦企量、人聲如沸测萎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽硅瞧。三九已至,卻和暖如春恕汇,著一層夾襖步出監(jiān)牢的瞬間腕唧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工瘾英, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留枣接,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓缺谴,卻偏偏與公主長得像但惶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容