之前项目使用的底部导航按钮都是用 RadioGroup 包裹 RadioButton 配合状态选择器实现的。这种实现方式布局是很灵活的,实现虽然也简单,但是要做复杂点的效果还是比较麻烦。
Google 官方推荐的是 BottomNavigationView + menu :
常用的方法有:
setOnItemSelectedListener 获取选择监听进行对应的界面显示也可以配合 NavController 本质也是通过 setOnItemSelectedListener
getOrCreateBadge 可以轻松实现数字红点
高级点可以通过 navView.getChildAt(0).getChildAt(0..itemcount) 获取 NavigationBarItemView,
对单个 item 的图标及颜色自定义大小,代码示例:
NavigationBarMenuView menuView = (NavigationBarMenuView) binding.navView.getChildAt(0);
NavigationBarItemView itemView = (NavigationBarItemView) menuView.getChildAt(1);
itemView.setIconSize(100);
itemView.setTextColor(new ColorStateList(new int[][]{}, new int[]{}));
配合 setOnItemSelectedListener 就可以轻松实现某个item选中放大,取消选中还原的效果,
代码如下:
binding.navView.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
NavigationBarMenuView menuView = (NavigationBarMenuView) binding.navView.getChildAt(0);
if (item.getItemId() == R.id.navigation_dashboard) {
NavigationBarItemView itemView = (NavigationBarItemView) menuView.getChildAt(1);
itemView.setIconSize(100);
itemView.setTextColor(new ColorStateList(new int[][]{}, new int[]{}));
} else {
NavigationBarItemView itemView = (NavigationBarItemView) menuView.getChildAt(1);
itemView.setIconSize(menuView.getItemIconSize());
itemView.setTextColor(menuView.getItemTextColor());
}
return true;
}
});
setOnItemSelectedListener 配合 Lottie 可以轻松实现选中动画,代码示例:
Context mContext;
NavLottieUtils(BottomNavigationView navView) {
mContext = navView.getContext().getApplicationContext();
navView.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
itemSelected(item, mLottieMapping.get(item.getItemId()));
return true;
}
});
}
/**
* 如果之前有item,则还原其图标
*/
private MenuItem mLastItem;
public void itemSelected(MenuItem item, String path) {
if (mLastItem != null) {
//还原之前的图标
restoreIcon(mLastItem);
}
mLastItem = item;
if (TextUtils.isEmpty(path)) {
new Exception("path is empty").printStackTrace();
return;
}
if (item == null) {
new Exception("MenuItem is null").printStackTrace();
return;
}
saveNavIcon(item);
LottieDrawable drawable = new LottieDrawable();
LottieTask<LottieComposition> task = LottieCompositionFactory
.fromAsset(mContext, path);
task.addListener(new LottieListener<LottieComposition>() {
@Override
public void onResult(LottieComposition result) {
drawable.setComposition(result);
item.setIcon(drawable);
drawable.start();
task.removeListener(this);
}
});
task.addFailureListener(new LottieListener<Throwable>() {
@Override
public void onResult(Throwable result) {
result.printStackTrace();
}
});
}
private void saveNavIcon(MenuItem item) {
//保存之前的图标
if (mIconMapping.get(item.getItemId()) == null) {
mIconMapping.put(item.getItemId(), item.getIcon());
}
}
/**
* 未选中的icon
*/
private Map<Integer, Drawable> mIconMapping = new HashMap<>();
/**
* 还原其之前的图标
*
* @param menuItem
*/
private void restoreIcon(MenuItem menuItem) {
Drawable drawable = mIconMapping.get(menuItem.getItemId());
menuItem.setIcon(drawable);
}
private Map<Integer, String> mLottieMapping = new HashMap<>();
/**
* 添加资源映射
*
* @param navId
* @param lottiePath
*/
public void addLottieAssetMapping(int navId, String lottiePath) {
mLottieMapping.put(navId, lottiePath);
}