如何去掉BottomNavigationView的Item大于3个时的动画效果

来源:互联网 发布:模拟地理位置的软件 编辑:程序博客网 时间:2024/05/20 05:25

前言

官方的导航栏BottomNavigationView出来已经有一段时间了,使用也非常简单,这里就不再说它的使用了!当我们底部导航为3个时,感觉体验还是很舒服的,但是一旦大于3个时,就只显示选中的item了,其他的变很小,而且没有显示标题,切换的时候,也十分夸张,显得很别扭!

为什么这样

在查看了源码之后,发现它的设计有点类似MVP模式,所涉及到的类有5个:
BottomNavigationView
BottomNavigationMenu
BottomNavigationItemView
BottomNavigationMenuView
BottomNavigationPresenter

具体全部的源码分析,可以参考这篇文章
BottomNavigationView

我们这里只说一下,item大于3个的显示奇怪的情况。
首先在BottomNavigationMenuView中,有一个全局变量:mShiftingMode,然后在创建Menu的时候buildMenuView()

public void buildMenuView() {    ...    mShiftingMode = mMenu.size() > 3;    ...}

当size>3时候,设为ture。

然后在BottomNavigationItemView,设置check的时候:

@Override    public void setChecked(boolean checked) {        ViewCompat.setPivotX(mLargeLabel, mLargeLabel.getWidth() / 2);        ViewCompat.setPivotY(mLargeLabel, mLargeLabel.getBaseline());        ViewCompat.setPivotX(mSmallLabel, mSmallLabel.getWidth() / 2);        ViewCompat.setPivotY(mSmallLabel, mSmallLabel.getBaseline());        if (mShiftingMode) {            if (checked) {                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();                iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;                iconParams.topMargin = mDefaultMargin;                mIcon.setLayoutParams(iconParams);                mLargeLabel.setVisibility(VISIBLE);                ViewCompat.setScaleX(mLargeLabel, 1f);                ViewCompat.setScaleY(mLargeLabel, 1f);            } else {                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();                iconParams.gravity = Gravity.CENTER;                iconParams.topMargin = mDefaultMargin;                mIcon.setLayoutParams(iconParams);                mLargeLabel.setVisibility(INVISIBLE);                ViewCompat.setScaleX(mLargeLabel, 0.5f);                ViewCompat.setScaleY(mLargeLabel, 0.5f);            }            mSmallLabel.setVisibility(INVISIBLE);        } else {            if (checked) {                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();                iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;                iconParams.topMargin = mDefaultMargin + mShiftAmount;                mIcon.setLayoutParams(iconParams);                mLargeLabel.setVisibility(VISIBLE);                mSmallLabel.setVisibility(INVISIBLE);                ViewCompat.setScaleX(mLargeLabel, 1f);                ViewCompat.setScaleY(mLargeLabel, 1f);                ViewCompat.setScaleX(mSmallLabel, mScaleUpFactor);                ViewCompat.setScaleY(mSmallLabel, mScaleUpFactor);            } else {                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();                iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;                iconParams.topMargin = mDefaultMargin;                mIcon.setLayoutParams(iconParams);                mLargeLabel.setVisibility(INVISIBLE);                mSmallLabel.setVisibility(VISIBLE);                ViewCompat.setScaleX(mLargeLabel, mScaleDownFactor);                ViewCompat.setScaleY(mLargeLabel, mScaleDownFactor);                ViewCompat.setScaleX(mSmallLabel, 1f);                ViewCompat.setScaleY(mSmallLabel, 1f);            }        }        refreshDrawableState();    }

根据是不是shiftMode执行不同的逻辑,所以产生了这样奇葩的效果!

解决方案

官方并没有暴露接口,来外部禁掉这种模式,然后在stackoverflow上面找到一个回答:
How to disable BottomNavigationView shift mode?

上代码:

public class BottomNavigationViewHelper {    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) {            Log.e("BNVHelper", "Unable to get shift mode field", e);        } catch (IllegalAccessException e) {            Log.e("BNVHelper", "Unable to change value of shift mode", e);        }    }}

然后使用:

BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation_bar);BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);

需要注意的一点:
就是我们打包混淆的时候,不能混淆这个成员变量!!!!

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

第三方控件

Github上面有很多类似的控件,使用更加的灵活,UI体验上面也有更多的效果可以使用!如star数最多的BottomNavigation

传送门:BottomNavigation

原创粉丝点击