介绍
基本上每个应用都有这样的需求,之前通过RadioGroup加RadioButton配合来实现,现在采用design包下的BottomNavigationView来完成.
写在前面
他只能支持3到5个按钮的操作,如果再多,请选择其他替代品.
在xml文件中直接使用
对于关键属性进行解答:
app:itemIconTint="@color/testc"
表示icon的颜色,其并不是单一 的color,而是一个selector,表示选中与不选中时候的图标的颜色,比如下面的方式:
app:itemTextColor="@color/testc"
表示text的颜色,其也不是单一的颜色,也是selector,表示文字按下与抬起的颜色.
app:itemBackground="@color/colorWrite"
表示正哥底部导航栏的颜色
app:menu="@menu/navigation"
需要你在res/创建menu文件夹,然后创建xml文件
这里有四个item.表明,你想让底部展示四个按钮用于切换.
每一个item包含:
id : 表示当前item的id,为以后的点击事件作准备
icon : 表示的是每一个item上的图,这里可不是单纯的图片如果你使用一般的图片,那么运行完程序,
你会发现,这个icon地方变成圆形的按钮,然后用户选中与不选中颜色就是上面xml中设置的颜色.
这个icon必须是vector 的Drawable.
title:就是每一个条目展示的名字
一般设计成这个样子,是为了上面完成切换页面的任务,那么就有了下面的监听
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
//如果用户已经选择了当前item,那么用户再点击次item,这个方法不会调用.
return false;
}
});
在这个接口回调中,可以同item.getItemId来区分用户选中的是哪一个item
另外他还提供了如下几个比较好的方法:
(1) bottomNavigationView.setSelectedItemId();
此方法可以直接使得哪一个item被选中,需要注意的是,当你调用这个之后,仍会走setOnNavigationItemSelectedListener的回调.
(2) 具体如下:
bottomNavigationView.setOnNavigationItemReselectedListener(new BottomNavigationView.OnNavigationItemReselectedListener() {
@Override
public void onNavigationItemReselected(@NonNull MenuItem item) {
//用户选中了当前item,再点击当前item时候的回调.
}
});
问题
如果你设置的底部的item数量超过三个,如果不做处理的话,你会发现,他们并不均分底部空间,这样效果很不好,所以利用反射去除掉:
public class BottomNavigationViewHelper {
@SuppressLint("RestrictedApi")
public static void disableShiftMode(BottomNavigationView view) {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
try {
Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
shiftingMode.setAccessible(true);
shiftingMode.setBoolean(menuView, false);
shiftingMode.setAccessible(false);
for (int i = 0; i < menuView.getChildCount(); i++) {
BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
//noinspection RestrictedApi
item.setShiftingMode(false);
// set once again checked value, so view will be updated
//noinspection RestrictedApi
item.setChecked(item.getItemData().isChecked());
}
} catch (NoSuchFieldException e) {
} catch (IllegalAccessException e) {
}
}
//调整底部导航栏图标大小
public static void adjustNavigationButtonView(BottomNavigationView bottomNavigationView, Context context) {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) bottomNavigationView.getChildAt(0);
for (int i = 0; i < menuView.getChildCount(); i++) {
View iconView = menuView.getChildAt(i).findViewById(android.support.design.R.id.icon);
ViewGroup.LayoutParams layoutParams = iconView.getLayoutParams();
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
layoutParams.height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, displayMetrics);
layoutParams.width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, displayMetrics);
iconView.setLayoutParams(layoutParams);
}
}
}
在28以上,google提供了方法的支持,再通过上述放射的方式实现,就不可以了,具体如下:
app:labelVisibilityMode="[labeled, unlabeled, selected, auto]"
labeled : 保持所有文字便签显示
unlabeled :只显示图标
selected :在选中的时候显示文字标签,有动画效果
auto : 在 1-3 个按钮时使用 labeled ,大于 3 个按钮使用 selected
或者
navigation.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);
我在28api的模拟器上运行,并未发现问题问题,可能是当前应用未兼容到28以上的原因.
取消导航栏图标着色
navigation.setItemIconTintList(null);
补充:如果你打包的时候要开启不混淆如下:
-keep public class android.support.design.** {*;}
//为了省事,直接开启design包不混淆
特别感谢:
BottomNavigationView 的使用及遇到的坑
BottomNavigationView图标大小和颜色设置