BottomNavigationView解决三个限制记录

在查看lottie动画库的代码时发现它的底部是利用BottomNavigationView实现的底部导航栏,但是却不受3个的限制(控件超过三个就会进行处理,隐藏除选中外的文字并缩小),还保留了控件原本3个以内的效果,这里我就把它的代码贴出来

效果

  • BottomNavigationView的结构,清楚了控件的构成就容易解决问题了
1
2
3
4
//从上倒下包含
BottomNavigationView
BottomNavigationMenu
BottomNavigationItemView
  • lottie中代码使用kotlin写的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
private val TAG = NoShiftBottomNavigationView::class.java.name
class NoShiftBottomNavigationView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : BottomNavigationView(context, attrs, defStyleAttr) {
override fun onViewAdded(child: View?) {
super.onViewAdded(child)
removeShiftAnimation()
}
@SuppressLint("RestrictedApi")
private fun removeShiftAnimation() {
val menuView = getChildAt(0) as BottomNavigationMenuView
try {
menuView::class.java.getDeclaredField("mShiftingMode").apply {
isAccessible = true
setBoolean(menuView, false)
isAccessible = false
}
menuView.children
.map { it as BottomNavigationItemView }
.forEach {
it.setShiftingMode(false)
it.setChecked(it.itemData.isChecked)
}
} catch (e: NoSuchFieldException) {
Log.e(TAG, "Unable to get shift mode field", e)
} catch (e: IllegalAccessException) {
Log.e(TAG, "Unable to change value of shift mode", e)
}
}
}
  • 我也写了一份java的(最近正好在学koltin)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class NoShiftBottomNavigationView extends BottomNavigationView {
private String TAG = getClass().getSimpleName();
public NoShiftBottomNavigationView(Context context) {
this(context,null);
}
public NoShiftBottomNavigationView(Context context, AttributeSet attrs) {
super(context, attrs,0);
}
public NoShiftBottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void onViewAdded(View child) {
super.onViewAdded(child);
//当底部导航菜单被添加,去除系统的效果
removeShiftAnimation();
}
@SuppressLint("RestrictedApi")
private void removeShiftAnimation() {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) getChildAt(0);
try {
//利用反射获取到mShiftingMode属性,设置为false不需要shift动画效果(控制移动动画)
Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
//忽略该属性的访问显示
shiftingMode.setAccessible(true);
shiftingMode.setBoolean(menuView,false);
shiftingMode.setAccessible(false);
//取消每一个子菜单的shift动画效果(控制文字是否显示隐藏)
for (int i = 0; i < menuView.getChildCount(); i++) {
BottomNavigationItemView itemView = (BottomNavigationItemView) menuView.getChildAt(i);
itemView.setShiftingMode(false);
itemView.setChecked(itemView.getItemData().isChecked());
}
} catch (NoSuchFieldException e) {
Log.e(TAG, "Unable to get shift mode field", e);
} catch (IllegalAccessException e) {
Log.e(TAG, "Unable to change value of shift mode", e);
}
}
}
  • 注意

    如果混淆了design包记得忽略混淆该属性,防止混淆后属性名变化,反射无法找到该属性,导致异常

1
2
3
-keepclassmembers class android.support.design.internal.BottomNavigationMenuView {
boolean mShiftingMode;
}