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