TabLayout高端用法(一)

TabLayout提供了一個(gè)水平的布局用來(lái)展示Tabs,很多應(yīng)用都有這樣的設(shè)計(jì),典型的有網(wǎng)易新聞,簡(jiǎn)書(shū),知乎等。TabLayout就可以很好的完成這一職責(zé),當(dāng)然也或許各家應(yīng)用的實(shí)現(xiàn)方式不盡相同,這里介紹下TabLayout的用法。

首先TabLayout一般都是配合Viewpager使用的,Viewpager里的Fragment隨著頂部的Tab一起聯(lián)動(dòng),這種場(chǎng)景再熟悉不過(guò)了。在沒(méi)有TabLayout的日子里關(guān)于這種設(shè)計(jì)一般都是自己實(shí)現(xiàn)的。

  • 先來(lái)個(gè)簡(jiǎn)單通俗的代碼:
<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/toolbar_tab"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:layout_gravity="bottom"
        android:background="#ffffff"
        android:fillViewport="false"
        app:tabMode="fixed"
        app:layout_scrollFlags="scroll"
        app:tabIndicatorColor="#057523"
        app:tabIndicatorHeight="2.0dp"
        app:tabSelectedTextColor="#057523"
        app:tabTextColor="#ced0d3">

        <android.support.design.widget.TabItem
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="a" />

        <android.support.design.widget.TabItem
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="b" />

        <android.support.design.widget.TabItem
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="c" />

    </android.support.design.widget.TabLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

上面代碼的運(yùn)行效果如下:

E7C96D0A-4692-40B3-B1D7-08361A7793E7-75356-000684F41CA2CA41.gif
  • 為了使用TabLayout,我們要讓Activity繼承自AppCompatActivity,但有時(shí)候你項(xiàng)目里的BaseActivity卻是繼承自FragmentActivity的,這就尷尬了。其實(shí)沒(méi)關(guān)系的, AppCompatActivity 也是extends FragmentActivity的??梢园袯aseActivity extends AppCompatActivity。如果不想這么做也可以,可以指定當(dāng)前Activity的theme為

android:theme="@style/Theme.AppCompat"

然后build.gradle文件在dependencies里加上

compile 'com.android.support:design:25.0.0'

然后基本上就不會(huì)有什么問(wèn)題了。

下面來(lái)解析下TabLayout的一些基本屬性:

app:tabIndicatorColor :指示條的顏色
app:tabIndicatorHeight :指示條的高度
app:tabSelectedTextColor : tab被選中時(shí)的字體顏色
app:tabTextColor : tab未被選中時(shí)的字體顏色
app:tabMode="scrollable" : 默認(rèn)是fixed:固定的,標(biāo)簽很多時(shí)候會(huì)被擠壓,不能滑動(dòng)。

重要的屬性基本就這些,其他簡(jiǎn)單的屬性可以自己去摸索,這里選中和未選中的字體顏色,可以根據(jù)自己的設(shè)計(jì)自行修改,同樣指示條的高度顏色也可以隨意修改。

  • 但假如我的設(shè)計(jì)里不需要指示條怎么辦,好像沒(méi)發(fā)現(xiàn)隱藏的API,那也很簡(jiǎn)單。有兩個(gè)思路:
    1:把指示條高度設(shè)為0:

app:tabIndicatorHeight="0dp"

2:把指示條的顏色設(shè)為透明:

app:tabIndicatorColor="@color/transparent"

效果如下:

40FAEFFF-FF76-43D1-8DD9-98177B630AE4-75356-00068525B87F337E.gif
  • TabItem

    在高版本的design庫(kù)里已經(jīng)有了TabItem,TabItem是作為T(mén)abLayout的子View而配合使用的,點(diǎn)進(jìn)去發(fā)現(xiàn)其實(shí)代碼很簡(jiǎn)單,就是個(gè)自定義View。

public final class TabItem extends View {
    final CharSequence mText;
    final Drawable mIcon;
    final int mCustomLayout;

    public TabItem(Context context) {
        this(context, null);
    }

    public TabItem(Context context, AttributeSet attrs) {
        super(context, attrs);

        final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
                R.styleable.TabItem);
        mText = a.getText(R.styleable.TabItem_android_text);
        mIcon = a.getDrawable(R.styleable.TabItem_android_icon);
        mCustomLayout = a.getResourceId(R.styleable.TabItem_android_layout, 0);
        a.recycle();
    }
}

所以當(dāng)我們的需求能夠明確知道Tab的個(gè)數(shù)時(shí),可以在xml里直接添加TabItem。但是但是,心細(xì)的你不知道有沒(méi)有發(fā)現(xiàn)問(wèn)題,我在上面的代碼中,tab明明設(shè)置的小寫(xiě),但是運(yùn)行出來(lái)確是大寫(xiě):

 <android.support.design.widget.TabItem
       android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="a" />

事先申明我可沒(méi)在代碼里重新設(shè)置文本,就是這么操蛋。好在天無(wú)絕人之路,找到了一個(gè)屬性叫app:tabTextAppearance,這是Tablayout的屬性。TabItem代碼簡(jiǎn)單到幾乎沒(méi)有什么屬性可供設(shè)置,什么字體大小,顏色貌似都設(shè)置不了。
所以我們自己寫(xiě)了個(gè)樣式,然后醬寫(xiě):

app:tabTextAppearance="@style/MyTabLayoutTextAppearance"

MyTabLayoutTextAppearance里的代碼如下:

<style name="MyTabLayoutTextAppearance"parent="TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse">
<item name="android:textSize">16sp</item>
<item name="android:textAllCaps">false</item>
</style>

這里的android:textAllCaps屬性就是控制字體大小寫(xiě)的,TabLayout里默認(rèn)是true,我們手動(dòng)改成false即可,我們順便設(shè)置了下字體。

但是但是,問(wèn)題又來(lái)了,我設(shè)置的字體大小貌似沒(méi)什么卵用,無(wú)論我怎么調(diào)節(jié)字體大小就是不變。呵呵,還是要從tabTextAppearance這個(gè)屬性來(lái)著手。
下面我們把代碼改成這樣:

app:tabTextAppearance="@android:style/TextAppearance.Holo.Large"

這下好了,字體的大小寫(xiě)解決了,字體大小也解決了。這樣的屬性我們找到了3組,

<style name="TextAppearance.Holo.Large" parent="TextAppearance.Large" />
<style name="TextAppearance.Holo.Medium"parent="TextAppearance.Medium"/>
<style name="TextAppearance.Holo.Small" parent="TextAppearance.Small" />

大.jpg

分別設(shè)置字體為大中小,說(shuō)實(shí)話,這玩意真的不太好用,跟其他控件比起來(lái),這個(gè)屬性設(shè)置有點(diǎn)繞。

  • 不要用文本了,改成icon吧,wtf,TabItem根本沒(méi)有這樣的屬性啊,TabLayout貌似也沒(méi)有啊。怎么搞?TabLayout沒(méi)有明確地提供向Tab中設(shè)置圖標(biāo)的途徑,但是很多事情總可以另辟蹊徑。我們知道,Tab是使用adapter中的getPageTitle()方法做其顯示的內(nèi)容,這個(gè)方法返回類(lèi)型為CharSequence。于是,我們可以在PagerAdapter中重寫(xiě)getPageTitle()方法,創(chuàng)建一個(gè)SpannableString,而將圖標(biāo)放置在ImageSpan中,設(shè)置在SpannableString中:
    private int[] imageResId = {       
           R.mipmap.ic_0,       
           R.mipmap.ic_1,       
           R.mipmap.ic_2
        };

    @Override
        public CharSequence getPageTitle(int position){
            Drawable image = ContextCompat.getDrawable(MainActivity.this, imageResId[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;

        }

好了,運(yùn)行起來(lái),效果有了。

1B73B273D717C65EA0D26E63FEBB9C40.jpg
  • 要不改成icon+文本吧?呵呵。。。又改???
    還好還好,還是上面的方案,稍微修改下代碼。在SpannableString中添加文本就可以了:
        @Override
        public CharSequence getPageTitle(int position){
            Drawable drawable = null;
            String title=null;
            switch (position) {
                case 0:
                    drawable = ContextCompat.getDrawable(MainActivity.this,R.mipmap.ic_qq_pre);
                    title = "a";
                    break;
                case 1:
                    drawable = ContextCompat.getDrawable(MainActivity.this, R.mipmap.ic_weibo_pre);
                    title = "b";
                    break;
                case 2:
                    drawable = ContextCompat.getDrawable(MainActivity.this, R.mipmap.login_weixin_icon);
                    title = "c";
                    break;
                default:
                    break;
            }
            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());

            ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM);
            SpannableString spannableString = new SpannableString("   " + title);
            spannableString.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

            return spannableString;

        }

還好還好,至于圖片的select效果應(yīng)該很easy了,就不演示了,效果如下。

C9E196F7ABD7AED92B5047DFA767E1E2.jpg
  • 圖片在左邊?要不放右邊吧,不不不,放上面,算了算了,放下面吧。到底放哪???
    如果需求太奇葩,常規(guī)手段或者奇技淫巧都無(wú)法滿(mǎn)足需求的話,就只有最后一招了:自定義。前面說(shuō)過(guò)了TabItem本質(zhì)上也是View,我們可以根據(jù)自己的實(shí)際需求來(lái)重寫(xiě)這個(gè)View。

icon在右邊:


右.jpg

icon在上邊:


上.jpg

可以發(fā)現(xiàn)通過(guò)自定義View的方式我們可以隨意擺放文本和icon的位置,無(wú)所謂上下左右,處理起來(lái)都是一樣的。甚至一個(gè)tab想放兩個(gè)icon或者兩個(gè)文本什么的都不在話下。一不下心展開(kāi)講,說(shuō)的有點(diǎn)多了,這里就不再介紹如何自定義TabItem了,放在下篇講,說(shuō)了這么多好像也沒(méi)上Tablayout和ViewPager的代碼,也放在下一篇??傮w來(lái)講Tablayout的坑還是蠻多的,很多API都沒(méi)提供,或者提供了但留了很多坑,這很google,一方面給你一個(gè)很常用的控件,一方面這個(gè)控件又留了很多坑,最后這個(gè)控件帶給你無(wú)限想象和發(fā)揮,根據(jù)自己的想法,動(dòng)手去實(shí)現(xiàn)吧。

完整代碼:GitHub

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,251評(píng)論 25 708
  • ¥開(kāi)啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開(kāi)一個(gè)線程,因...
    小菜c閱讀 7,369評(píng)論 0 17
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點(diǎn)贊按鈕進(jìn)度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 47,175評(píng)論 22 665
  • 原文地址:http://www.android100.org/html/201606/06/241682.html...
    AFinalStone閱讀 1,316評(píng)論 0 1
  • 前面介紹過(guò)JS中的namespace, 看起來(lái)好像我們已經(jīng)成功解決了全局空間沖突的問(wèn)題了。 但前面提到的方法有一個(gè)...
    ifcode閱讀 494評(píng)論 0 2

友情鏈接更多精彩內(nèi)容