自定义 BottomNavigationView

做个微信小程序的朋友都知道,要定义一个底部导航按钮非常简单,只需要配置一份json文件就行了,就会自动生成底部Tab.
Android在以前做法比较麻烦,RadioButton等自定义,要处理各种选中和默认的状态,后Android Material Design推出了BottomNavigationView,使得底部导航控件变得简单。本篇内容将说明BottomNavigationView的基本用法,和通过json文件配置自定义的BottomNavigationView。

  1. 在布局文件中引入

底部要显示的内容都在menu里面bottom_nav_menu,




    

    

    

    


menu里面有title显示的文字,icon图标。

在Activity中通过监听item的选中时间来实现导航。

  BottomNavigationView navView = findViewById(R.id.nav_view);
        final NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        navView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                navController.navigate(item.getItemId(), null);
                return true;
            }
        });

基本用法很简单,不进行深入讲解,下面来实现自动的BottomNavigationView,

  1. 配置json文件;
{
  "activeColor": "#333333",
  "inActiveColor": "#666666",
  "selectTab": 0,
  "tabs": [
    {
      "size": 24,
      "enable": true,
      "index": 0,
      "pageUrl": "main/tabs/home",
      "title": "首页"
    },
    {
      "size": 24,
      "enable": true,
      "index": 1,
      "pageUrl": "main/tabs/dash",
      "title": "沙发"
    },
    {
      "size": 40,
      "enable": true,
      "index": 2,
      "tintColor": "#ff678f",
      "pageUrl": "main/tabs/notification",
      "title": ""
    },
    {
      "size": 24,
      "enable": true,
      "index": 3,
      "pageUrl": "main/tabs/find",
      "title": "发现"
    },
    {
      "size": 24,
      "enable": true,
      "index": 4,
      "pageUrl": "main/tabs/my",
      "title": "我的"
    }
  ]
}

创建一个json解析的实体类Destination

package com.shitu.app.model;

public class Destination {

    public String pageUrl;
    public int id;
    public boolean needLogin;
    public boolean asStarter;
    public boolean isFragment;
    public String className;

    @Override
    public String toString() {
        return "Destination{" +
                "isFragment=" + isFragment +
                ", asStarter=" + asStarter +
                ", needLogin=" + needLogin +
                ", pageUrl='" + pageUrl + '\'' +
                ", clzName='" + className + '\'' +
                ", id=" + id +
                '}';
    }
}

自定义BottomNavigationView,新建一个AppBottomBar类,继承BottomNavigationView



import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MenuItem;

import com.google.android.material.bottomnavigation.BottomNavigationItemView;
import com.google.android.material.bottomnavigation.BottomNavigationMenuView;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.bottomnavigation.LabelVisibilityMode;
import com.shitu.app.R;
import com.shitu.app.model.BottomBar;
import com.shitu.app.model.Destination;
import com.shitu.app.util.AppConfig;

import java.util.List;

public class AppBottomBar extends BottomNavigationView {
    private static int[] sIcons = new int[]{R.drawable.icon_tab_home, R.drawable.icon_tab_sofa, R.drawable.icon_tab_publish, R.drawable.icon_tab_find, R.drawable.icon_tab_mine};
    private BottomBar config;

    public AppBottomBar(Context context) {
        this(context, null);
    }

    public AppBottomBar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    @SuppressLint("RestrictedApi")
    public AppBottomBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        config = AppConfig.getBottomBarConfig();

        int[][] state = new int[2][];
        state[0] = new int[]{android.R.attr.state_selected};
        state[1] = new int[]{};
        int[] colors = new int[]{Color.parseColor(config.activeColor), Color.parseColor(config.inActiveColor)};
        ColorStateList stateList = new ColorStateList(state, colors);
        setItemTextColor(stateList);
        setItemIconTintList(stateList);
        //LABEL_VISIBILITY_LABELED:设置按钮的文本为一直显示模式
        //LABEL_VISIBILITY_AUTO:当按钮个数小于三个时一直显示,或者当按钮个数大于3个且小于5个时,被选中的那个按钮文本才会显示
        //LABEL_VISIBILITY_SELECTED:只有被选中的那个按钮的文本才会显示
        //LABEL_VISIBILITY_UNLABELED:所有的按钮文本都不显示
        setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);
        List tabs = config.tabs;
        for (BottomBar.Tab tab : tabs) {
            if (!tab.enable) {
                continue;
            }
            int itemId = getItemId(tab.pageUrl);
            if (itemId < 0) {
                continue;
            }
            MenuItem menuItem = getMenu().add(0, itemId, tab.index, tab.title);
            menuItem.setIcon(sIcons[tab.index]);
        }

        //此处给按钮icon设置大小
        int index = 0;
        for (BottomBar.Tab tab : config.tabs) {
            if (!tab.enable) {
                continue;
            }

            int itemId = getItemId(tab.pageUrl);
            if (itemId < 0) {
                continue;
            }

            int iconSize = dp2Px(tab.size);
            BottomNavigationMenuView menuView = (BottomNavigationMenuView) getChildAt(0);
            BottomNavigationItemView itemView = (BottomNavigationItemView) menuView.getChildAt(index);
            itemView.setIconSize(iconSize);
            if (TextUtils.isEmpty(tab.title)) {
                int tintColor = TextUtils.isEmpty(tab.tintColor) ? Color.parseColor("#ff678f") : Color.parseColor(tab.tintColor);
                itemView.setIconTintList(ColorStateList.valueOf(tintColor));
                //禁止掉点按时 上下浮动的效果
                itemView.setShifting(false);

                /**
                 * 如果想要禁止掉所有按钮的点击浮动效果。
                 * 那么还需要给选中和未选中的按钮配置一样大小的字号。
                 *
                 *  在MainActivity布局的AppBottomBar标签增加如下配置,
                 *  @style/active,@style/inActive 在style.xml中
                 *  app:itemTextAppearanceActive="@style/active"
                 *  app:itemTextAppearanceInactive="@style/inActive"
                 */
            }
            index++;
        }

        //底部导航栏默认选中项
        if (config.selectTab != 0) {
            BottomBar.Tab selectTab = config.tabs.get(config.selectTab);
            if (selectTab.enable) {
                int itemId = getItemId(selectTab.pageUrl);
                //这里需要延迟一下 再定位到默认选中的tab
                //因为 咱们需要等待内容区域,也就NavGraphBuilder解析数据并初始化完成,
                //否则会出现 底部按钮切换过去了,但内容区域还没切换过去
                post(() -> setSelectedItemId(itemId));
            }
        }
    }

    private int dp2Px(int dpValue) {
        DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
        return (int) (metrics.density * dpValue + 0.5f);
    }

    private int getItemId(String pageUrl) {
        Destination destination = AppConfig.getDestConfig().get(pageUrl);
        if (destination == null)
            return -1;
        return destination.id;
    }
}

代码简单,没啥可说的,不懂的留言,哈哈!
将布局文件中的BottomNavigationView换成AppBottomBar

 

其他照旧,OK,改造完成!

你可能感兴趣的:(自定义 BottomNavigationView)