ViewPager實現頁卡的最新方法--簡潔的TabLayout(AndroidSupportDesign)

Google在2015年的Google IO大會上更新了Design Support Library,里面提供了幾個封裝好的MeterDesign風格控件,其中包括:

  1. TextInputLayout : 使用TextInputLayout將EditText進行了封裝,提示信息會變成一個顯示在EditText之上的floating label,這樣用戶就始終知道他們現在輸入的是什么,而且過度動畫是平滑的。還可以在下方通過setError設置Error提示


    這里寫圖片描述
  2. FloatingActionButton : 負責顯示界面基本操作的圓形按鈕


    這里寫圖片描述
  3. Snackbar : 為一個操作提供輕量級、快速的反饋


    這里寫圖片描述
  4. TabLayout : 既實現了固定的選項卡(View的寬度平均分配),也實現了可滾動的選項卡(View寬度不固定同時可以橫向滾動)


    這里寫圖片描述
  5. NavigationView : 通過提供抽屜導航所需的框架讓實現更簡單

具體的介紹可以看看:http://android-developers.blogspot.com/2015/05/android-design-support-library.html
這篇文章里面,記錄一下TabLayout 的使用,還有幾個不得不說的坑!

先看效果:


這里寫圖片描述

上面是TabLayout ,下面是ViewPager,最簡單的一個demo。下面介紹一些如何實現。
首先是導入,在build.gradle 文件中加上這段代碼

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

然后Activity的布局文件內容如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.design.widget.TabLayout
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/tabs"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        app:tabSelectedTextColor="@color/com_bg_black"
        app:tabTextColor="@color/light_gray"/>

    <android.support.v4.view.ViewPager
        android:id="@+id/vp_view"
        android:layout_below="@id/tabs"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

簡單吧!使用TabLayout中定義的屬性時需要聲明

xmlns:app="http://schemas.android.com/apk/res-auto"

上面使用到的app:tabSelectedTextColor 和 app:tabTextColor 分別是tab里選中和非選中的字體顏色,也可以在Java代碼里設置。
在activity代碼如下

public class TabLayoutActivity extends Activity {
    @BindView(R.id.tabs) TabLayout mTabLayout;
    @BindView(R.id.vp_view) ViewPager mViewPager;

    private TextView view1, view2, view3;//頁卡視圖
    private List<View> mViewList = new ArrayList<>();//頁卡視圖集合

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tabview);
        ButterKnife.bind(this);

        mViewPager = (ViewPager) findViewById(R.id.vp_view);
        mTabLayout = (TabLayout) findViewById(R.id.tabs);
        view1 = getTextView("view1");
        view2 = getTextView("view2");
        view3 = getTextView("view3");

        //添加頁卡視圖
        mViewList.add(view1);
        mViewList.add(view2);
        mViewList.add(view3);

        mTabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);//設置tab模式,當前為系統默認模式
//        mTabLayout.addTab(mTabLayout.newTab().setText(mTitleList.get(0)));//添加tab選項卡

        SimplePagerAdapter mAdapter = new SimplePagerAdapter(mViewList);
        mViewPager.setAdapter(mAdapter);//給ViewPager設置適配器
        mTabLayout.setupWithViewPager(mViewPager);//將TabLayout和ViewPager關聯起來。
//        mTabLayout.setTabsFromPagerAdapter(mAdapter);//給Tabs設置適配器
    }

    private TextView getTextView(String text) {
        TextView textView = new TextView(this);
        textView.setText(text);
        textView.setGravity(Gravity.CENTER);
        textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        return textView;
    }


    //ViewPager適配器
    class SimplePagerAdapter extends PagerAdapter {
        private List<View> mViewList;

        public SimplePagerAdapter(List<View> mViewList) {
            this.mViewList = mViewList;
        }

        @Override
        public int getCount() {
            return mViewList.size();//頁卡數
        }
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;//官方推薦寫法
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            container.addView(mViewList.get(position));//添加頁卡
            return mViewList.get(position);
        }
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView(mViewList.get(position));//刪除頁卡
        }
        @Override
        public CharSequence getPageTitle(int position) {
            return "Tab_" + position;//頁卡標題
        }
    }

}

同樣的簡潔,最終實現的效果是滑動切換viewpager時,TabLayout同步滑動切換;點擊選中TabLayout項時,viewpager自動滑動切換到對應頁面。
在xml里面,除了上面用到的兩個自定義屬性,還有一些其他的屬性,下面羅列出來:

        public static final int TabLayout_tabBackground = 3;
        public static final int TabLayout_tabContentStart = 2;
        public static final int TabLayout_tabGravity = 5;
        public static final int TabLayout_tabIndicatorColor = 0;// 設置為透明即為隱藏
        public static final int TabLayout_tabIndicatorHeight = 1;
        public static final int TabLayout_tabMaxWidth = 7;
        public static final int TabLayout_tabMinWidth = 6;
        public static final int TabLayout_tabMode = 4;
        public static final int TabLayout_tabPadding = 15;
        public static final int TabLayout_tabPaddingBottom = 14;
        public static final int TabLayout_tabPaddingEnd = 13;
        public static final int TabLayout_tabPaddingStart = 11;
        public static final int TabLayout_tabPaddingTop = 12;
        public static final int TabLayout_tabSelectedTextColor = 10;// 選中的文字顏色
        public static final int TabLayout_tabTextAppearance = 8;// 可以設置文字大小和顏色
        public static final int TabLayout_tabTextColor = 9;// 非選中狀態的文字顏色

從上面的屬性里可以看到需要設置文字大小需要通過tabTextAppearance屬性來定義,從TabLayout源碼發現,只有這一種方式設置字體大小。


這里寫圖片描述

并且設置文字顏色時,tabTextColor的優先級高于tabTextAppearance。

第一坑:

Caused by: java.lang.IllegalArgumentException: You need to use a Theme.AppCompat theme (or descendant) with the design library.
at android.support.design.widget.ThemeUtils.checkAppCompatTheme(ThemeUtils.java:34)

從提示上看,是說我們使用這個library里的控件時,需要把activity的style設置為Theme.AppCompat的衍生主題。我的設置如下:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
</style>

探其所以然:


這里寫圖片描述

ThemeUtils.java內容較少,就直接貼出來:

class ThemeUtils {
    private static final int[] APPCOMPAT_CHECK_ATTRS = { R.attr.colorPrimary };
    static void checkAppCompatTheme(Context context) {
        TypedArray a = context.obtainStyledAttributes(APPCOMPAT_CHECK_ATTRS);
        final boolean failed = !a.hasValue(0);
        if (a != null) {
            a.recycle();
        }
        if (failed) {
            throw new IllegalArgumentException("You need to use a Theme.AppCompat theme "
                    + "(or descendant) with the design library.");
        }
    }
}

看到這里,仿佛僅僅校驗R.attr.colorPrimary屬性是否存在。于是把BaseTheme改為android:Theme.Light,并添加R.attr.colorPrimary屬性(要求minSdk>=21),但是結果還是閃退,log都木有。估計是后面用到了Theme.AppCompat下面的其他屬性,不然校驗一個無用屬性也是太無厘頭了。最終,還是乖乖使用Theme.AppCompat.Light.DarkActionBar。

第二坑

這里寫圖片描述

上圖中的tab不見了,但是下面的指示條還在,并且點擊事件也都有。原因是沒有覆寫PagerAdapter.getPageTitle(position).
查看TabLayout的源碼發現這個:
這里寫圖片描述

天地良心啊,直接把我手動添加的tab全部移除了,然后自己調用PagerAdapter.getPageTitle(position)獲得標題tab。這封裝果然實用,但是不看源碼還得是被坑的團團轉!
所以:不用自己添加tab,只需要覆寫PagerAdapter.getPageTitle(position)。

第三坑

這里寫圖片描述

標題欄的英文字符全部轉大寫了。。。這就好尷尬了,在網上找了好幾天資料(PS:百度出來的結果都差不多),都是說要設置textAllCaps屬性:

    <!--TAB文字樣式-->
    <style name="MyCustomTabTextAppearance" parent="TextAppearance.Design.Tab">
        <item name="textAllCaps">false</item>
    </style>

然而并沒有用!查看TextAppearance.Design.Tab,發現textAllCaps默認為true,也就是全部轉大寫


這里寫圖片描述

最后找到解決方案后,才發現是自己看源碼時太關注屬性值了,也是眼瞎,竟沒看出來textAllCaps是自定義的一個屬性,Android內定義的屬性都是以android:開頭的,握草!

    <style name="TabLayoutTextAppearance" parent="TextAppearance.Design.Tab">
        <item name="textAllCaps">false</item>
        <item name="android:textAllCaps">false</item>
    </style>

最終是醬紫的!


這里寫圖片描述

好了,大坑目前就發現這幾個,總得來說TabLayout還是很好用的,如果這個效果如果夠用的話,還是用Google自家的!


再說一點:

這里寫圖片描述

第一個紅框標識,此處只是移除之前額外添加的滑動監聽,因為Adapter已經更換,所以PageChangeListener也需要更換。
下面的第二個紅框標出來,是想說,里面已經封裝好了不需要重復調用TabLayout.setTabsFromPagerAdapter(mAdapter),也就是我上面注釋掉的一行代碼。

源碼鏈接:https://github.com/brian512/AndroidDemo


CodeBlog是我做的一個編程技術學習客戶端,集成了很多技術網站上的博客,應用寶詳情頁

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容