Android頂部導航之TabLayout和ViewPager的組合,setupWithViewPager有點坑

TabLayout是Android Design Support Library的組件,可以很方便的寫出頂部導航欄比以前那個什麼TabHost好用多了,因爲是Design Support Library下的控件,所以使用它要引入相關依賴

   implementation 'com.android.support:design:26.1.0'

**注意**Android studio 3.0以後,引入依賴關鍵詞變成了implementation
在之前版本的關鍵詞是 compile

本文最終實現的最終效果如下圖所示:
這裏寫圖片描述

使用方法

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"

        app:tabMode="scrollable" />

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

</LinearLayout>

1.找到相應控件

mTabLayout = (TabLayout) findViewById(R.id.tabLayout);
mViewPager = (ViewPager) findViewById(R.id.viewPager);

2.創建tab項

        //使用Tablayout的newTab()創建tab
        TabLayout.Tab tab1 = mTabLayout.newTab()
                //設置tab項顯示的文字
                .setText("tab1");
        TabLayout.Tab tab2 = mTabLayout.newTab().setText("tab2");
        TabLayout.Tab tab3 = mTabLayout.newTab().setText("tab3");

說明: 創建Tab對象不能通過new 對象的方式,而是使用TabLayout裏面的newTab()的方式創建,查看源碼就可以知道Tab的構成方法是沒有修飾詞,也就是默認權限,它所在包以外都沒權限訪問。

3.將tab項添加到TabLayout中

    mTabLayout.addTab(tab1);
    mTabLayout.addTab(tab2);
    mTabLayout.addTab(tab3);

運行效果如下

這裏寫圖片描述

4.準備ViewPager數據

  • 使用ViewPager前先要有一個它的適配器
public class TabPageAdapter extends FragmentPagerAdapter {
    private List<Fragment> fragments;

    public TabPageAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);
        this.fragments = fragments;
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    @Override
    public int getCount() {
        return fragments.size();
    }
}
  • 向適配器中添加數據
        fragments=new ArrayList<>();
        //將提前寫好三個Fragment添加到集合中
        fragments.add(new FirstFragment());
        fragments.add(new SecondFragment());
        fragments.add(new ThirdFragment());
        //創建適配器
        TabPageAdapter pageAdapter = new TabPageAdapter(getSupportFragmentManager(), fragments);
        //設置ViewPager的適配器
        mViewPager.setAdapter(pageAdapter);
  • 把TabLayout和ViewPager組合,使用setupWithViewPager可以讓TabLayout和ViewPager聯動
 mTabLayout.setupWithViewPager(mViewPager);

寫到這感覺應可以了吧
這裏寫圖片描述

什麼情況,聯動效果出來了,但Tab項的字去哪了

查看setupWithViewPager源碼發現,在ViewPager適配器不爲空的情況下,最終會調用populateFromPagerAdapter()方法

 void populateFromPagerAdapter() {
        removeAllTabs();//移除tab添加的所有tab項

        if (mPagerAdapter != null) 
            final int adapterCount = mPagerAdapter.getCount();
            for (int i = 0; i < adapterCount; i++) {   
               //創建Tab項,把tab顯示的標題設置爲從獲取適配的getPageTitle的內容   
                addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);
            }

            // Make sure we reflect the currently set ViewPager item
            if (mViewPager != null && adapterCount > 0) {
                final int curItem = mViewPager.getCurrentItem();
                if (curItem != getSelectedTabPosition() && curItem < getTabCount()) {
                    selectTab(getTabAt(curItem));
                }
            }
        }
    }

從上面可以看出,我們之前向TabLayout添加的Tab項調用這個方法後都被移除了,它會重新創建新的Tab項,tab顯示的文字是從適配器getPageTitle()獲取的 。上面我們寫適配器的時候沒有重寫適配器的getPageTitle()方法 ,所以上面效果就是有Tab項但Tab項上沒有文字了,解決辦法就是重寫適配器的getPageTitle()方法

 public class TabPageAdapter extends FragmentPagerAdapter {
    private List<Fragment> fragments;
    private String[] tabNames;//tab選項名字


    public TabPageAdapter(FragmentManager fm, List<Fragment> fragments,String[] tabNames) {
        super(fm);
        this.fragments = fragments;
        this.tabNames=tabNames;
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    @Override
    public int getCount() {
        return fragments.size();
    }
//重寫getPageTitle()方法
    @Override
    public CharSequence getPageTitle(int position) {
    //返回tab選項的名字
        return tabNames[position];
    }
}
String[] mTabNames=new String[]{"tab1","tab2","tab3"};
TabPageAdapter pageAdapter = new TabPageAdapter(getSupportFragmentManager(), fragments,mTabNames);

這種方式tab選項不是我們自己創建的,如果想對tab項設置一下屬性,通過getTabAt(int index) 方法獲取tab對象進行一些設置就可以了

關於TabLayout的屬性設置

  • 設置指示器樣式(設置顏色和高度)
 app:tabIndicatorColor="#1565C0"
 app:tabIndicatorHeight="4dp" 

這裏寫圖片描述

  • 設置選擇時的字體顏色
app:tabSelectedTextColor="#9C27B0"

這裏寫圖片描述
- 設置TabLayout顯示的模式(fixed or scrollable)
TabLayout默認爲fixed模式,將所有tab項都顯示出來,佔滿它的寬度

app:tabMode="fixed"

這裏寫圖片描述
scrollable 模式,如果TabLayout不能將所有tab顯示,就可以滾動查看所有tab項

app:tabMode="scrollable"

這裏寫圖片描述

TabLayout的監聽事件

mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                //tab項選中狀態時執行
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                //tab項取消選中狀態時執行
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
               //tab項選中狀態再次點擊時執行

            }
        });

本文代碼下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章