最近手头上正在写的一个Android项目正好要用到底部导航栏,虽然受Android studio官方已经有一个底部导航栏的模板,但还是用自己熟悉的看着更舒服。接下来就记录一下用BottomNavigationBar实现底部导航栏的方法


添加依赖

在build.gradle文件的dependencies中增加如下代码,然后点击右上方sync,等待依赖文件添加完成

implementation 'com.ashokvarma.android:bottom-navigation-bar:2.0.4'
布局中引入BottomNavigationBar
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/main_activity">

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

    <com.ashokvarma.bottomnavigation.BottomNavigationBar
        android:id="@+id/bottom_navigation_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"/>

</LinearLayout>

如上,我们首先添加一个Framelayout,之后我们将以它为容器装载切换的页面。当用户切换底部的tab时,导航至该tab对应的fragment。

创建每个TAB对应的fragment

比如我需要Home,Bluetooth,Hotspot三个页面,那就分别创建三个fragment以及相应的布局文件。取Home界面为例

public class HomeFragment extends Fragment {
    private View view;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saveInstanceState){
        view = inflater.inflate(R.layout.fragment_home, container, false);
        return view;
    }
}

布局文件

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
    tools:context=".fragment.HomeFragment">
    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="主页" />

</FrameLayout>

这里只放了一个TextView用来指示是哪一个Fragment。

初始化BottomNavigationbar

在这里先放上MainActivity的完整源码

public class MainActivity extends AppCompatActivity implements BottomNavigationBar.OnTabSelectedListener{

    /**
     *初始化
     */
    private Fragment mFragment;
    private HomeFragment homeFragment;
    private BlutoothFragment blutoothFragment;
    private HotspotFragment hotspotFragment;
    private FragmentTransaction transaction;
    BottomNavigationBar bottomNavigationBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initFragment();
        bottomNavigationBar = (BottomNavigationBar) findViewById(R.id.bottom_navigation_bar);
        BottomNavigationBar();
        bottomNavigationBar.setTabSelectedListener(this);
    }

    /**
     * 初始化三个fragment,并将主页fragment加入事务中
     */
    private void initFragment() {
        homeFragment = new HomeFragment();
        blutoothFragment = new BlutoothFragment();
        hotspotFragment = new HotspotFragment();
        transaction = getSupportFragmentManager().beginTransaction();
        transaction.add(R.id.fragment_container,homeFragment).commit();
        mFragment = homeFragment;
    }

    /**
     * 初始化底部导航栏样式
     */
    private void BottomNavigationBar(){
        bottomNavigationBar.setActiveColor(R.color.colorAccent)
                .setInActiveColor(R.color.colorPrimary)
                .setBarBackgroundColor("#FFFFFF");
        bottomNavigationBar.setMode(BottomNavigationBar.MODE_FIXED);
        //背景样式
        bottomNavigationBar.addItem(new BottomNavigationItem(R.drawable.ic_home, "主页").setActiveColorResource(R.color.blue))
                .addItem(new BottomNavigationItem(R.drawable.ic_bluetooth, "蓝牙模式").setActiveColorResource(R.color.blue))
                .addItem(new BottomNavigationItem(R.drawable.ic_hotspot, "热点模式").setActiveColorResource(R.color.blue))
                .setFirstSelectedPosition(0)
                .initialise();
    }

    /**
     * TAB被点击时的切换fragment
     * @param position
     */
    @Override
    public void onTabSelected(int position) {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction transaction = fm.beginTransaction();
        switch(position){
            case 0:
                switchFragment(homeFragment);
                break;
            case 1:
                switchFragment(blutoothFragment);
                break;
            case 2:
                switchFragment(homeFragment);
                break;
            default:
                switchFragment(homeFragment);
                break;
        }
        transaction.commit();
    }


    @Override
    public void onTabUnselected(int position) { }

    @Override
    public void onTabReselected(int position) { }

    /**
     * 切换fragment的方法
     * @param fragment
     */
    private void switchFragment(Fragment fragment) {
        //判断当前显示的Fragment是不是切换的Fragment
        if(mFragment != fragment) {
            //判断切换的Fragment是否已经添加过
            if (!fragment.isAdded()) {
                //如果没有,则先把当前的Fragment隐藏,把切换的Fragment添加上
                getSupportFragmentManager().beginTransaction().hide(mFragment)
                        .add(R.id.fragment_container,fragment).commit();
            } else {
                //如果已经添加过,则先把当前的Fragment隐藏,把切换的Fragment显示出来
                getSupportFragmentManager().beginTransaction().hide(mFragment).show(fragment).commit();
            }
            mFragment = fragment;
        }
    }
}

解释一下上述代码。

在initFragment()方法中,首先初始化各个fragment,然后用一个FragmentTransaction来对这些fragment进行管理。其中mFragment是用来指示当前TAB所指向的fragment。我们将主页HomeFragment的实例作为提交的第一个事务。

在BottomNavigationBar()中我们设置底部导航栏的样式,被选中时的颜色,未选中时的颜色,背景。通过addItem添加底部的TAB,设置对应的每个TAB的背景图片和文字。

实现BottomNavigationBar.OnTabSelectedListener接口,重写其onTabSelected方法,用以点击不同TAB时切换到不同fragment。

switchFragment()方法中,为了防止fragment 被重复创建,所以用isAdded方法做一个判断,若添加过,切换时只需将其隐藏,然后展示需要的fragment即可。若没有,则先将所需fragment增加到事务中提交。