1. 程式人生 > >Material Design:TabLayout的使用

Material Design:TabLayout的使用

ase 現在 omv follow 滿足 script sta ont cti

轉:https://www.jianshu.com/p/9c072bc99ebe

谷歌在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的使用