BottomNavigationView实现页面底部导航栏

  • BottomNavigationView基本使用(静态配置)

    在Activity的xml布局中添加BottomNavigationView引用

    <!--导航菜单-->
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nav_main_bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:itemBackground="@android:color/transparent"
        app:itemTextAppearanceActive="@style/bottom_nav_text_selected"
        app:itemTextAppearanceInactive="@style/bottom_nav_text_normal"
        app:itemTextColor="@drawable/selector_tab_menu_text"
        app:menu="@menu/bottom_nav" />
    

    以上相关属性介绍:

    itemBackground:为BottomNavigationView布局指定背景色,优先级高于background属性

    itemRippleColor:设置条目点击时水波纹颜色,设置itemBackground属性时,该属性无效

    itemTextAppearanceActive:设置条目选中时text样式

    itemTextAppearanceInactive:设置条目未选中时text样式

    itemTextColor:条目text颜色,可以使用选择器

    itemIconTint:为条目图标着色,需要在代码中设置setItemIconTintList(null)去掉默认着色

    menu:指定条目菜单

    <!--底部导航栏文字样式-->
    <style name="bottom_nav_text_normal">
        <item name="android:textSize">@dimen/font_13</item>
        <item name="android:paddingTop">10dp</item>
    </style>
    <style name="bottom_nav_text_selected">
        <item name="android:textSize">@dimen/font_15</item>
        <item name="android:paddingTop">15dp</item>
    </style>
    
    <!--selector_tab_menu_text.xml-->
    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:color="@color/tab_menu_text_selected" android:state_selected="true" />
        <item android:color="@color/tab_menu_text_normal" />
    </selector>
    
    <!--bottom_nav.xml-->
    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item
            android:id="@+id/nav_main"
            android:icon="@drawable/selector_tab_menu_icon_main"
            android:title="@string/nav_tab_main" />
        <item
            android:id="@+id/nav_find"
            android:icon="@drawable/selector_tab_menu_icon_find"
            android:title="@string/nav_tab_find" />
        <item
            android:id="@+id/nav_mine"
            android:icon="@drawable/selector_tab_menu_icon_mine"
            android:title="@string/nav_tab_mine" />
    </menu>
    

    bottom_nav中静态指定了三个item,id为每个item独有的标志,点击事件的时候会用到,title属性指定item的名称,例如“我的”、“发现”等,icon属性为item指定图标,这里使用了selector选择器,如下:

    <!--selector_tab_menu_icon_main.xml-->
    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@mipmap/ic_main_selected" android:state_selected="true" />
        <item android:drawable="@mipmap/ic_main_normal" />
    </selector>
    
    <!--selector_tab_menu_icon_find.xml-->
    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@mipmap/ic_find_selected" android:state_selected="true" />
        <item android:drawable="@mipmap/ic_find_normal" />
    </selector>
    
    <!--selector_tab_menu_icon_mine.xml-->
    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@mipmap/ic_mine_selected" android:state_selected="true" />
        <item android:drawable="@mipmap/ic_mine_normal" />
    </selector>
    

    至此静态创建方式完成。

  • BottomNavigationView基本使用(动态添加和删除)

    在Activity的xml布局中同样需要添加BottomNavigationView引用

    <!--导航菜单-->
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nav_main_bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:itemBackground="@android:color/white"
        app:itemTextAppearanceActive="@style/bottom_nav_text_selected"
        app:itemTextAppearanceInactive="@style/bottom_nav_text_normal"
        app:itemTextColor="@drawable/selector_tab_menu_text"/>
    

    注意:这里没有添加menu属性

    代码实现初始化添加:

    private void addMenu() {
        Menu menu = navView.getMenu();
        //添加首页
        menu.add(0, 1, 0, "首页").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        menu.getItem(0).setIcon(R.drawable.selector_tab_menu_icon_main);
        //添加我的模块
        menu.add(0, 3, 2, "我的").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        menu.getItem(1).setIcon(R.drawable.selector_tab_menu_icon_mine);
    }
    

    现在再添加一个“发现”板块,放到中间位置:

    public void addNewMenu(View view) {
        Menu menu = navView.getMenu();
        menu.add(0, 2, 1, "发现").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        menu.getItem(1).setIcon(R.drawable.selector_tab_menu_icon_find);
    }
    

    上面添加方法中使用了Menu的构造函数:add(int groupId, int itemId, int order, CharSequence title);

    第一个参数指定组id,第二个参数致命条目id(点击事件的时候要用),第三个参数指定条目顺序,第四个为条目标签名称。

    上面我把“首页”放到了第一个位置,“我的”放到了第三个位置,添加的“发现”放到了第二个位置。设置icon时有一个细节需要注意,在初始化条目完成后,BottomNavigationView只有两个item,因此getItem(0)和getItem(1)分别是首页和我的板块item实例,但是添加“发现”板块之后就变成了三个,而且发现板块放到了第二个位置,因此设置icon时候我们是通过menu.getItem(1)拿到发现item的实例,而不是getItem(2)。

    删除条目:

    public void removeMenu(View view) {
        Menu menu = navView.getMenu();
        menu.removeItem(2);
    }
    

    removeItem(2)方法中的参数“2”指的是itemId并不是条目索引。

    注意:BottomNavigationView对添加的menu个数有限制,最多不能超过5个,如果超过5个会报以下错误:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rJkEsgYS-1606187401040)(H:\Android知识体系\知识架构图片\第一部分\第一章\1.1\1.1.5\BottomNavigationView添加超过5个.png)]

  • 后台分发动态加载方案简述

    上面一小节中虽然实现了Menu的动态添加和删除,但是还无法满足后台分发动态加载的要求,底部导航的动态需要做到以下几个方面动态配置:

    选择状态下icon

    正常状态下icon

    选择状态下label颜色

    正常状态下label颜色

    label文案

    menu个数

    因此,上一小节中icon的加载方案还需要优化。

    换一种drawable加载方式实现,如下:

    private static final int[] STATE_NORMAL = {-android.R.attr.state_selected};//-代表此属性为false
    private static final int[] STATE_SELECTED = {android.R.attr.state_selected};
    
    private void addMenu() {
        Menu menu = navView.getMenu();
        //添加首页
        menu.add(0, 1, 0, "首页").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        //设置首页icon
        StateListDrawable mainDrawable = new StateListDrawable();
        Bitmap mainSelectedBitmap = BitmapFactory.decodeResource(getResources(), 			R.mipmap.ic_main_selected);
        BitmapDrawable mainSelectedIcon = new BitmapDrawable(mainSelectedBitmap);
        mainDrawable.addState(STATE_SELECTED, mainSelectedIcon);
        Bitmap mainNormalBitmap = BitmapFactory.decodeResource(getResources(), 				R.mipmap.ic_main_normal);
        BitmapDrawable mainNormalIcon = new BitmapDrawable(mainNormalBitmap);
        mainDrawable.addState(STATE_NORMAL, mainNormalIcon);
        menu.getItem(0).setIcon(mainDrawable);
        //添加我的模块
        menu.add(0, 3, 2, "我的").setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
        //设置我的模块icon
        StateListDrawable mineDrawable = new StateListDrawable();
        Bitmap mineSelectedBitmap = BitmapFactory.decodeResource(getResources(), 			R.mipmap.ic_mine_selected);
        BitmapDrawable mineSelectedIcon = new BitmapDrawable(mineSelectedBitmap);
        mineDrawable.addState(STATE_SELECTED, mineSelectedIcon);
        Bitmap mineNormalBitmap = BitmapFactory.decodeResource(getResources(), 				R.mipmap.ic_mine_normal);
        BitmapDrawable mineNormalIcon = new BitmapDrawable(mineNormalBitmap);
        mineDrawable.addState(STATE_NORMAL, mineNormalIcon);
        menu.getItem(1).setIcon(mineDrawable);
    }
    

    使用menuItem的setIcon(Drawable icon)重载方法设置,需要设置选择状态下和非选择状态下的icon,这里用StateListDrawable就可以解决。另一个问题,一般后台都是通过url的形式分发icon的,因此我们还需要将对应状态的图片异步下载下来,然后存放至对应的文件夹下,待下载并保存成功后通过BitmapFactory.decodeFile()方法获取对应的Bitmap,然后对应的BitmapDrawable实例也就能获取到了。具体实现代码这里不再多做介绍,大体思路就是如此,有兴趣的小伙伴们可以详细研究一下。

  • 整体页面框架搭建(静态化配置方案)

    静态化配置底部导航栏上文中已经介绍过,这里不再赘述。接下来直接创建对应的Fragment:

    /**
     * 初始化底部导航选择
     */
    private void initNav() {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction transaction = fm.beginTransaction();
        if (mMainFrag == null) {
            mMainFrag = new MainFragment();
            mFragList.add(mMainFrag);
            transaction.add(R.id.fl_container, mMainFrag);
        }
        transaction.commit();
    }
    

    BottomNavigationView添加item点击点听:

    @SuppressLint("NonConstantResourceId")
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction transaction = fm.beginTransaction();
        switch (item.getItemId()) {
            case R.id.nav_main: //首页
                if (mMainFrag == null) {
                    mMainFrag = new MainFragment();
                    mFragList.add(mMainFrag);
                    transaction.add(R.id.fl_container, mMainFrag);
                }
                for (Fragment frag : mFragList) {
                    transaction.hide(frag);
                }
                transaction.show(mMainFrag);
                break;
            case R.id.nav_find: //发现
                if (mFindFrag == null) {
                    mFindFrag = new FindFragment();
                    mFragList.add(mFindFrag);
                    transaction.add(R.id.fl_container, mFindFrag);
                }
                for (Fragment frag : mFragList) {
                    transaction.hide(frag);
                }
                transaction.show(mFindFrag);
                break;
            case R.id.nav_mine: //我的
                if (mMineFrag == null) {
                    mMineFrag = new MineFragment();
                    mFragList.add(mMineFrag);
                    transaction.add(R.id.fl_container, mMineFrag);
                }
                for (Fragment frag : mFragList) {
                    transaction.hide(frag);
                }
                transaction.show(mMineFrag);
                break;
        }
        transaction.commit();
        return true;
    }
    

    很容易就实现了底部导航菜单切换展示对应模块Fragment的页面框架。
    附上效果图:
    在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值