1. 程式人生 > >Android底部導航欄的四種實現

Android底部導航欄的四種實現

現在大多數App都會用到底部導航欄,比如常見的聊天工具QQ、微信,購物App等等,有了底部導航欄,使用者可以隨時切換介面,檢視不同的內容。它的實現方式也很多,以前大多使用TabHost來實現,但是現在我們有很多更好的選擇。

使用LinearLayout + TextView實現了底部導航欄的效果

首先看看工程目錄:

這裡寫圖片描述

Step 1:實現底部選項的一些資原始檔

圖片Drawable資源:tab_menu_deal.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
>
<item android:drawable="@mipmap/ic_menu_deal_on" android:state_selected="true"/> <item android:drawable="@mipmap/ic_menu_deal_off"/> </selector>

不用做過多解釋了吧,點選圖片,變換圖片。
其他三個依葫蘆畫瓢。

文字資源:tab_menu_deal_text.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android
="http://schemas.android.com/apk/res/android">
<item android:color="@color/text_blue" android:state_selected="true"/> <item android:color="@color/text_gray" /> </selector>

背景資源 tab_menu_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
>
<item android:state_selected="true"> <shape> <solid android:color="#FFC4C4C4"/> </shape> </item> <item> <shape> <solid android:color="@color/transparent" /> </shape> </item> </selector>

Step 2:編寫我們的Activity佈局

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">

    <RelativeLayout
        android:id="@+id/tab_title"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:background="@color/transparent">
        <TextView
            android:id="@+id/txt_top"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:textSize="18sp"
            android:textColor="@color/text_gray"
            android:text= "@string/infomation" />

        <View
            android:layout_width="match_parent"
            android:layout_height="2px"
            android:background="@color/text_gray"
            android:layout_alignParentBottom="true"/>
        </RelativeLayout>

    <LinearLayout
        android:id="@+id/tab_menu"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:orientation="horizontal"
        android:layout_alignParentBottom="true">

        <TextView
            android:id="@+id/txt_deal"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/tab_menu_bg"
            android:drawablePadding="3dp"
            android:drawableTop="@drawable/tab_menu_deal"
            android:gravity="center"
            android:textColor="@drawable/tab_menu_deal_text"
            android:text="點餐"/>

        <TextView
            android:id="@+id/txt_poi"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/tab_menu_bg"
            android:drawablePadding="3dp"
            android:drawableTop="@drawable/tab_menu_poi"
            android:gravity="center"
            android:textColor="@drawable/tab_menu_poi_text"
            android:text="商鋪"/>

        <TextView
            android:id="@+id/txt_user"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/tab_menu_bg"
            android:drawablePadding="3dp"
            android:drawableTop="@drawable/tab_menu_user"
            android:gravity="center"
            android:textColor="@drawable/tab_menu_user_text"
            android:text="使用者"/>

        <TextView
            android:id="@+id/txt_more"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/tab_menu_bg"
            android:drawablePadding="3dp"
            android:drawableTop="@drawable/tab_menu_more"
            android:gravity="center"
            android:textColor="@drawable/tab_menu_more_text"
            android:text="更多"/>

        </LinearLayout>

    <View
        android:id="@+id/div_tab_bar"
        android:layout_width="match_parent"
        android:layout_height="2px"
        android:background="@color/text_gray"
        android:layout_above="@id/tab_menu"/>

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/tab_title"
        android:layout_above="@id/tab_menu"
        android:background="@color/transparent">
        </FrameLayout>

</RelativeLayout>

效果圖如下:

這裡寫圖片描述

Step 3:建立一個Fragment的簡單佈局與類:

first_fragment.xml:

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


    <TextView
        android:id="@+id/txt_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="呵呵"
        android:textColor="@color/text_blue"
        android:textSize="20sp"/>

</LinearLayout>

FirstFragment.java:

public class FirstFragment extends Fragment {
    private String context;
    private TextView mTextView;

    public  FirstFragment(String context){
        this.context = context;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.first_fragment,container,false);
        mTextView = (TextView)view.findViewById(R.id.txt_content);
        //mTextView = (TextView)getActivity().findViewById(R.id.txt_content);
        mTextView.setText(context);
        return view;
    }
}

Step 4:編寫MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private TextView topBar;
    private TextView tabDeal;
    private TextView tabPoi;
    private TextView tabMore;
    private TextView tabUser;

    private FrameLayout ly_content;

    private FirstFragment f1,f2,f3,f4;
    private FragmentManager fragmentManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        bindView();

    }

    //UI元件初始化與事件繫結
    private void bindView() {
        topBar = (TextView)this.findViewById(R.id.txt_top);
        tabDeal = (TextView)this.findViewById(R.id.txt_deal);
        tabPoi = (TextView)this.findViewById(R.id.txt_poi);
        tabUser = (TextView)this.findViewById(R.id.txt_user);
        tabMore = (TextView)this.findViewById(R.id.txt_more);
        ly_content = (FrameLayout) findViewById(R.id.fragment_container);

        tabDeal.setOnClickListener(this);
        tabMore.setOnClickListener(this);
        tabUser.setOnClickListener(this);
        tabPoi.setOnClickListener(this);

    }

     //重置所有文字的選中狀態
    public void selected(){
        tabDeal.setSelected(false);
        tabMore.setSelected(false);
        tabPoi.setSelected(false);
        tabUser.setSelected(false);
    }

     //隱藏所有Fragment
    public void hideAllFragment(FragmentTransaction transaction){
        if(f1!=null){
            transaction.hide(f1);
        }
        if(f2!=null){
            transaction.hide(f2);
        }
        if(f3!=null){
            transaction.hide(f3);
        }
        if(f4!=null){
            transaction.hide(f4);
        }
    }

    @Override
    public void onClick(View v) {
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        hideAllFragment(transaction);
        switch(v.getId()){
            case R.id.txt_deal:
                selected();
                tabDeal.setSelected(true);
                if(f1==null){
                    f1 = new FirstFragment("第一個Fragment");
                    transaction.add(R.id.fragment_container,f1);
                }else{
                    transaction.show(f1);
                }
                break;

            case R.id.txt_more:
                selected();
                tabMore.setSelected(true);
                if(f2==null){
                    f2 = new FirstFragment("第二個Fragment");
                    transaction.add(R.id.fragment_container,f2);
                }else{
                    transaction.show(f2);
                }
                break;

            case R.id.txt_poi:
                selected();
                tabPoi.setSelected(true);
                if(f3==null){
                    f3 = new FirstFragment("第三個Fragment");
                    transaction.add(R.id.fragment_container,f3);
                }else{
                    transaction.show(f3);
                }
                break;

            case R.id.txt_user:
                selected();
                tabUser.setSelected(true);
                if(f4==null){
                    f4 = new FirstFragment("第四個Fragment");
                    transaction.add(R.id.fragment_container,f4);
                }else{
                    transaction.show(f4);
                }
                break;
        }

        transaction.commit();
    }
}

實現效果圖如下:

這裡寫圖片描述

使用RadioGroup + RadioButton實現了底部導航欄的效果

這一次的資原始檔和上一次是一樣的,只需要把外drawable類的資源的selected 狀態修改成checked狀態:

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

    <item android:drawable="@mipmap/ic_menu_deal_on" android:state_checked="true"/>
    <item android:drawable="@mipmap/ic_menu_deal_off"/>

</selector>

其他文字資源及背景資源不變

這裡我們首先從主佈局檔案開始:

Step 2:編寫我們的Activity佈局

由於佈局中的RadioButton的屬性大部分是一樣的,因此我們可以將這一部分一樣的程式碼抽取出來,寫到style.xml檔案中:

style.xml:

<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_menu_item">
        <item name="android:layout_width">0dp</item>
        <item name="android:layout_weight">1</item>
        <item name="android:layout_height">match_parent</item>
        <item name="android:background">@drawable/tab_menu_bg</item>
        <item name="android:button">@null</item>
        <item name="android:gravity">center</item>
        <item name="android:paddingTop">3dp</item>
        <item name="android:textColor">@drawable/tab_menu_text</item>
        <item name="android:textSize">18sp</item>
    </style>

</resources>

然後我們的activity_main.xml中的RadioButton就用不著次次都寫相同的程式碼了, 只需讓RadioButton的style=”@style/tab_menu_item”就可以了!

activity_main.xml :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">

    <RelativeLayout
        android:id="@+id/ly_top_bar"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:background="@color/transparent">

        <TextView
            android:id="@+id/txt_topbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerInParent="true"
            android:gravity="center"
            android:text="資訊"
            android:textColor="@color/text_gray"
            android:textSize="18sp" />

        <View
            android:layout_width="match_parent"
            android:layout_height="2px"
            android:layout_alignParentBottom="true"
            android:background="@color/text_gray" />

    </RelativeLayout>

    <RadioGroup
        android:id="@+id/rd_group"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:layout_alignParentBottom="true"
        android:background="@color/transparent"
        android:orientation="horizontal">
        <RadioButton
            android:id="@+id/rd_menu_deal"
            style="@style/tab_menu_item"
            android:drawableTop="@drawable/tab_menu_deal"
            android:text="點餐"/>

        <RadioButton
            android:id="@+id/rd_menu_poi"
            style="@style/tab_menu_item"
            android:drawableTop="@drawable/tab_menu_poi"
            android:text="商鋪"/>

        <RadioButton
            android:id="@+id/rd_menu_more"
            style="@style/tab_menu_item"
            android:drawableTop="@drawable/tab_menu_more"
            android:text="更多"/>

        <RadioButton
            android:id="@+id/rd_menu_user"
            style="@style/tab_menu_item"
            android:drawableTop="@drawable/tab_menu_user"
            android:text="使用者"/>
        </RadioGroup>

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/rd_group"
        android:layout_below="@id/ly_top_bar"
        android:background="@color/transparent">
        </FrameLayout>
</RelativeLayout>

效果圖如下:

這裡寫圖片描述

Step 3:建立一個Fragment的簡單佈局與類:

my_fragment.xml :

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

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textSize="20sp"
        android:textColor="@color/text_blue"
        android:gravity="center"
        android:text="呵呵"/>

</LinearLayout>

MyFragment.java :

public class MyFragment extends Fragment{
    private String context;
    private TextView mTextView;

    public MyFragment(String context){
       this.context = context;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.my_fragment,container,false);
        mTextView = (TextView)view.findViewById(R.id.textView);
        mTextView.setText(context);
        return view;
    }
}

Step 4:編寫MainActivity.java

public class MainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener{

    private RadioGroup rpTab;
    private RadioButton rbDeal,rbPoi,rbMore,rbUser;
    private MyFragment fg1,fg2,fg3,fg4;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bindView();
    }

    private void bindView() {
        rpTab = (RadioGroup)findViewById(R.id.rd_group);
        rpTab.setOnCheckedChangeListener(this);

        rbDeal = (RadioButton)findViewById(R.id.rd_menu_deal);
        rbPoi = (RadioButton)findViewById(R.id.rd_menu_poi);
        rbMore = (RadioButton)findViewById(R.id.rd_menu_more);
        rbUser = (RadioButton)findViewById(R.id.rd_menu_user);

        rbDeal.setChecked(true);
    }

    public void hideAllFragment(FragmentTransaction transaction){
        if(fg1!=null){
            transaction.hide(fg1);
        }
        if(fg2!=null){
            transaction.hide(fg2);
        }
        if(fg3!=null){
            transaction.hide(fg3);
        }
        if(fg4!=null){
            transaction.hide(fg4);
        }
    }

    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        hideAllFragment(transaction);
        switch (checkedId){
            case R.id.rd_menu_deal:
                if(fg1==null){
                    fg1 = new MyFragment("第一個Fragment");
                    transaction.add(R.id.fragment_container,fg1);
                }else{
                    transaction.show(fg1);
                }
                break;
            case R.id.rd_menu_poi:
                if(fg2==null){
                    fg2 = new MyFragment("第二個Fragment");
                    transaction.add(R.id.fragment_container,fg2);
                }else{
                    transaction.show(fg2);
                }
                break;
            case R.id.rd_menu_more:
                if(fg3==null){
                    fg3 = new MyFragment("第三個Fragment");
                    transaction.add(R.id.fragment_container,fg3);
                }else{
                    transaction.show(fg3);
                }
                break;
            case R.id.rd_menu_user:
                if(fg4==null){
                    fg4 = new MyFragment("第四個Fragment");
                    transaction.add(R.id.fragment_container,fg4);
                }else{
                    transaction.show(fg4);
                }
                break;
        }
        transaction.commit();
    }
}

效果圖和上面一樣:

這裡寫圖片描述

實現類似新浪微博的底部導航欄

前面我們已經跟大家講解了實現底部導航欄的兩種方案,但是這兩種方案只適合普通的情況,如果 是像新浪微博那樣的,想在底部導航欄上的item帶有一個紅色的小點,然後加上一個訊息數目這樣, 前面兩種方案就顯得無力了,我們來看看別人的APP是怎麼做的,開啟手機的開發者選項,勾選裡面的: 顯示佈局邊界,然後開啟我們參考的那個App,可以看到底部導航欄是這樣的:

這裡寫圖片描述
上面這個圖我們就可以看出,這種底部導航欄不是簡單的TextView或者RadioGroup構成的, 大概佈局方案可能是:外層一個LinearLayout,中間一個RelativeLayout,而在中間有一個TextView, 然後再在TextView的右上角有一個紅色圓圈背景的TextView或者一個紅色的小點; 大概就這樣,而這些小點平時的時候應該設定的不可見,當收到資訊推送,即有相關類別資訊的 時候再可見,並且顯示對應的資訊數目!那麼下面我們就來實現下這種底部導航欄的效果,!

實現效果:
為了方便理解,這裡通過點選按鈕的形式,模擬收到推送資訊,然後顯示紅色點!

Step 1:相關資原始檔的準備:
和前面一樣,準備好drawable系列的資源:

文字資源:tab_menu_text.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:color="@color/text_blue" android:state_selected="true"/>
    <item android:color="@color/text_gray" />

</selector>

圖示資源:tab_menu_better.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@mipmap/ic_menu_deal_on" android:state_selected="true"/>
    <item android:drawable="@mipmap/ic_menu_deal_off"/>

</selector>

其他三個依葫蘆畫瓢!

Step 2:編寫activity的佈局程式碼:

因為四個選項的TextView以及右上角的紅點數字屬性都差不多,如下:

 <TextView
                    android:id="@+id/tab_menu_channel"
                    android:layout_marginTop="5dp"
                    android:layout_width="wrap_content"
                    android:layout_height="48dp"
                    android:layout_centerInParent="true"
                    android:textColor="@drawable/tab_menu_text"
                    android:drawableTop="@drawable/tab_menu_channel"
                    android:text="@string/tab_menu_alert"/>
                <TextView
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:background="@mipmap/bg_num"
                    android:layout_toRightOf="@+id/tab_menu_channel"
                    android:layout_marginLeft="-10dp"
                    android:text="99+"
                    android:textSize="12sp"
                    android:gravity="center"
                    android:textColor="@color/text_white"/>

我們將他們抽取出來,寫到style.xml裡:

<style name="tab_menu_text">
    <item name="android:layout_marginTop">5dp</item>
    <item name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">48dp</item>
    <item name="android:layout_centerInParent">true</item>
    <item name="android:textColor">@drawable/tab_menu_text</item>
</style>


<style name="tab_menu_bgnum">
    <item name="android:layout_width">20dp</item>
    <item name="android:layout_height">20dp</item>
    <item name="android:background">@mipmap/bg_num</item>
    <item name="android:layout_marginLeft">-10dp</item>
    <item name="android:textSize">12sp</item>
    <item name="android:gravity">center</item>
    <item name="android:textColor">@color/text_white</item>
</style>

然後開始編寫我們的activity.xml佈局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">

    <RelativeLayout
        android:id="@+id/ly_top_bar"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:background="@color/transparent">

        <TextView
            android:id="@+id/txt_topbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerInParent="true"
            android:gravity="center"
            android:text="資訊"
            android:textColor="@color/text_gray"
            android:textSize="18sp" />

        <View
            android:layout_width="match_parent"
            android:layout_height="2px"
            android:layout_alignParentBottom="true"
            android:background="@color/text_gray" />

    </RelativeLayout>

    <LinearLayout
        android:id="@+id/ly_tab_menu"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:layout_alignParentBottom="true"
        android:background="@color/transparent"
        android:orientation="horizontal">

    <LinearLayout
        android:id="@+id/ly_tab_menu_deal"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center">

        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:padding="5dp">

            <TextView
                android:id="@+id/tab_menu_deal"
                style="@style/tab_menu_text"
                android:drawableTop="@drawable/tab_menu_deal"
                android:text="點餐" />

            <TextView
                android:id="@+id/tab_menu_deal_num"
                style="@style/tab_menu_bgnum"
                android:layout_toRightOf="@+id/tab_menu_deal"
                android:text="99+"
                android:visibility="gone" />
        </RelativeLayout>
    </LinearLayout>

        <LinearLayout
            android:id="@+id/ly_tab_menu_poi"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center">

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:padding="5dp">

                <TextView
                    android:id="@+id/tab_menu_poi"
                    style="@style/tab_menu_text"
                    android:drawableTop="@drawable/tab_menu_poi"
                    android:text="商鋪" />

                <TextView
                    android:id="@+id/tab_menu_poi_num"
                    style="@style/tab_menu_bgnum"
                    android:layout_toRightOf="@+id/tab_menu_poi"
                    android:text="99+"
                    android:visibility="gone" />
            </RelativeLayout>
        </LinearLayout>

        <LinearLayout
            android:id="@+id/ly_tab_menu_more"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center">

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:padding="5dp">

                <TextView
                    android:id="@+id/tab_menu_more"
                    style="@style/tab_menu_text"
                    android:drawableTop="@drawable/tab_menu_more"
                    android:text="更多" />

                <TextView
                    android:id="@+id/tab_menu_more_num"
                    style="@style/tab_menu_bgnum"
                    android:layout_toRightOf="@+id/tab_menu_more"
                    android:text="99+"
                    android:visibility="gone" />
            </RelativeLayout>
        </LinearLayout>

        <LinearLayout
            android:id="@+id/ly_tab_menu_user"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center">

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="mat