天天看點

Android 底部導航欄 (底部 Tab) 最佳實踐

效果

Android 底部導航欄 (底部 Tab) 最佳實踐

Android 底部導航欄 (底部 Tab) 最佳實踐

要實作這樣一個底部導航欄,大家最容易想到的當然就是TabLayout,Tab 切換嘛,TabLayout 就是專門幹這個事的,不過TabLayout 預設是帶有Indicator的,我們是不需要的,是以需要把它去掉,看一下布局檔案:

<?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"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/home_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        >
    </FrameLayout>

    <View android:layout_width="match_parent"
          android:layout_height="0.5dp"
          android:alpha="0.6"
          android:background="@android:color/darker_gray"
        />
    <android.support.design.widget.TabLayout
        android:id="@+id/bottom_tab_layout"
        android:layout_width="match_parent"
        app:tabIndicatorHeight="0dp"
        app:tabSelectedTextColor="@android:color/black"
        app:tabTextColor="@android:color/darker_gray"
        android:layout_height="50dp">

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

</LinearLayout>
           

整個布局分為三個部分,最上面是一個Framelayout 用做裝Fragment 的容器,接着有一根分割線,最下面就是我們的TabLayout,去掉預設的Indicator直接設定app:tabIndicatorHeight屬性的值為0就行了。

布局檔案寫好之後,接下來看一下Activity的代碼:

public class BottomTabLayoutActivity extends AppCompatActivity {
    private TabLayout mTabLayout;
    private Fragment []mFragmensts;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.bottom_tab_layout_ac);
        mFragmensts = DataGenerator.getFragments("TabLayout Tab");

        initView();

    }

    private void initView() {
        mTabLayout = (TabLayout) findViewById(R.id.bottom_tab_layout);

        mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                onTabItemSelected(tab.getPosition());

                //改變Tab 狀态
                for(int i=;i< mTabLayout.getTabCount();i++){
                    if(i == tab.getPosition()){
                        mTabLayout.getTabAt(i).setIcon(getResources().getDrawable(DataGenerator.mTabResPressed[i]));
                    }else{
                        mTabLayout.getTabAt(i).setIcon(getResources().getDrawable(DataGenerator.mTabRes[i]));
                    }
                }

            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });

        mTabLayout.addTab(mTabLayout.newTab().setIcon(getResources().getDrawable(R.drawable.tab_home_selector)).setText(DataGenerator.mTabTitle[]));
        mTabLayout.addTab(mTabLayout.newTab().setIcon(getResources().getDrawable(R.drawable.tab_discovery_selector)).setText(DataGenerator.mTabTitle[]));
        mTabLayout.addTab(mTabLayout.newTab().setIcon(getResources().getDrawable(R.drawable.tab_attention_selector)).setText(DataGenerator.mTabTitle[]));
        mTabLayout.addTab(mTabLayout.newTab().setIcon(getResources().getDrawable(R.drawable.tab_profile_selector)).setText(DataGenerator.mTabTitle[]));

    }

    private void onTabItemSelected(int position){
        Fragment fragment = null;
        switch (position){
            case :
                fragment = mFragmensts[];
                break;
            case :
                fragment = mFragmensts[];
                break;

            case :
                fragment = mFragmensts[];
                break;
            case :
                fragment = mFragmensts[];
                break;
        }
        if(fragment!=null) {
            getSupportFragmentManager().beginTransaction().replace(R.id.home_container,fragment).commit();
        }
    }
}
           

Activity的代碼如上,很簡單,就是一個TabLayout,添加監聽器,然後向TabLayout中添加4個Tab,在addOnTabSelectedListener 中切換各個Tab對應的Fragment 。其中用到的一些資料放在了一個單獨的類中, DataGenerator,代碼如下:

public class DataGenerator {

    public static final int []mTabRes = new int[]{R.drawable.tab_home_selector,R.drawable.tab_discovery_selector,R.drawable.tab_attention_selector,R.drawable.tab_profile_selector};
    public static final int []mTabResPressed = new int[]{R.drawable.ic_tab_strip_icon_feed_selected,R.drawable.ic_tab_strip_icon_category_selected,R.drawable.ic_tab_strip_icon_pgc_selected,R.drawable.ic_tab_strip_icon_profile_selected};
    public static final String []mTabTitle = new String[]{"首頁","發現","關注","我的"};

    public static Fragment[] getFragments(String from){
        Fragment fragments[] = new Fragment[];
        fragments[] = HomeFragment.newInstance(from);
        fragments[] = DiscoveryFragment.newInstance(from);
        fragments[] = AttentionFragment.newInstance(from);
        fragments[] = ProfileFragment.newInstance(from);
        return fragments;
    }

    /**
     * 擷取Tab 顯示的内容
     * @param context
     * @param position
     * @return
     */
    public static View getTabView(Context context,int position){
        View view = LayoutInflater.from(context).inflate(R.layout.home_tab_content,null);
        ImageView tabIcon = (ImageView) view.findViewById(R.id.tab_content_image);
        tabIcon.setImageResource(DataGenerator.mTabRes[position]);
        TextView tabText = (TextView) view.findViewById(R.id.tab_content_text);
        tabText.setText(mTabTitle[position]);
        return view;
    }
}
           

運作之後,效果如上圖,What ? 圖示這麼小?圖示和文字之間的間距這麼寬?這當然不是我們想要的,試着用TabLayout的屬性調整呢?TabLayout 提供了設定Tab 圖示、tab 文字顔色,選中顔色,文字大小的屬性,但是很遺憾,圖示Icon和圖示與文字之間的間距是沒辦法調整的。

那麼就沒有辦法了嗎?在仔細查了一下TabLayout的API 後,找到了一個方法,Tab 中有一個setCustomView(View view)方法,也就是我們不用正常的方式建立Tab,我們可以提供一個自己定義的View 來建立Tab,這不就行了嘛,既然可以自定義,那麼icon的大小,icon和文字之間的間距,我們想怎樣就怎樣拉。于是我們自定義一個布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:gravity="center"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <ImageView
        android:id="@+id/tab_content_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:scaleType="centerCrop"
        />
    <TextView
        android:id="@+id/tab_content_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="10sp"
        android:textColor="@android:color/darker_gray"
        />
</LinearLayout>
           

添加tab 的時候,用這個自定義的布局,改造後的Activity中的代碼如下這樣:

public class BottomTabLayoutActivity extends AppCompatActivity {
    private TabLayout mTabLayout;
    private Fragment []mFragmensts;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.bottom_tab_layout_ac);
        mFragmensts = DataGenerator.getFragments("TabLayout Tab");

        initView();

    }

    private void initView() {
        mTabLayout = (TabLayout) findViewById(R.id.bottom_tab_layout);

        mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                onTabItemSelected(tab.getPosition());
                // Tab 選中之後,改變各個Tab的狀态
               for (int i=;i<mTabLayout.getTabCount();i++){
                   View view = mTabLayout.getTabAt(i).getCustomView();
                   ImageView icon = (ImageView) view.findViewById(R.id.tab_content_image);
                   TextView text = (TextView) view.findViewById(R.id.tab_content_text);
                   if(i == tab.getPosition()){ // 選中狀态
                       icon.setImageResource(DataGenerator.mTabResPressed[i]);
                       text.setTextColor(getResources().getColor(android.R.color.black));
                   }else{// 未選中狀态
                       icon.setImageResource(DataGenerator.mTabRes[i]);
                       text.setTextColor(getResources().getColor(android.R.color.darker_gray));
                   }
               }


            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });
        // 提供自定義的布局添加Tab
         for(int i=;i<;i++){
             mTabLayout.addTab(mTabLayout.newTab().setCustomView(DataGenerator.getTabView(this,i)));
         }

    }

    private void onTabItemSelected(int position){
        Fragment fragment = null;
        switch (position){
            case :
                fragment = mFragmensts[];
                break;
            case :
                fragment = mFragmensts[];
                break;

            case :
                fragment = mFragmensts[];
                break;
            case :
                fragment = mFragmensts[];
                break;
        }
        if(fragment!=null) {
            getSupportFragmentManager().beginTransaction().replace(R.id.home_container,fragment).commit();
        }
    }
}
           

總結:TayoutLayout 實作底部導航欄較為簡單,隻需幾步就能實作,能配合Viewpager使用。但是,就像上文說的,不能設定Icon大小和調整Icon和文字之間的間距。但是可以通過設定自定義布局的方式來實作我們想要的效果。需要我們自己來改變Tab切換的狀态。還有一點需要注意:設定OnTabChangeListener 需要在添加Tab之前,不然第一次不會回調onTabSelected()方法

demohttp://download.csdn.net/detail/qq_35549248/9920237

繼續閱讀