Android:BottomNavigationView的使用和去掉动画效果

我使用的BottomNavigationView的包: ‘com.android.support:design:28.0.0-rc01’。
当底部导航为3个时,感觉体验还是很舒服的,但是一旦大于3个时,就只显示选中的item了,其他的变很小,而且没有显示标题,切换的时候,也十分夸张,显得很别扭!但是现在很少有底部导航栏只有三个的情况,基本上都是四五个。
这完全不是我想要的效果啊

为什么会造成这种情况呢?在网上也找了很多,看了很多大神写的博客。也有很多写到如何去除BottomNavigationView的动画效果的文章,本来想直接复制到工程里面就完事了。 但是 可能是google更新了BottomNavigationView源码的原因,并不管用。没办法。只能自己去读源码了。研究了大半天 ,终于是弄出来了。
最终效果图
这里写图片描述

主要涉及到BottomNavigationItemView和BottomNavigationMenuView,BottomNavigationView的子view是BottomNavigationMenuView,它包含菜单项构成菜单。每一个菜单项是BottomNavigationItemView。BottomNavigationMenuView和BottomNavigationItemView的关系类似于常见的RadioGroup和RadioButton,动画效果是在itemTab上面,所以我首先想到,这个动画可能在BottomNavigationItemView设置的。但是源码这么多,我不想一步一步看。通过单步执行,定位到,设置显示方式主要是这个setChecked方法,


public void setChecked(boolean checked) {
        this.largeLabel.setPivotX((float)(this.largeLabel.getWidth() / 2));
        this.largeLabel.setPivotY((float)this.largeLabel.getBaseline());
        this.smallLabel.setPivotX((float)(this.smallLabel.getWidth() / 2));
        this.smallLabel.setPivotY((float)this.smallLabel.getBaseline());
        switch(this.labelVisibilityMode) {
        case -1:
            if (this.isShifting) {
                if (checked) {
                    this.setViewLayoutParams(this.icon, this.defaultMargin, 49);
                    this.setViewValues(this.largeLabel, 1.0F, 1.0F, 0);
                } else {
                    this.setViewLayoutParams(this.icon, this.defaultMargin, 17);
                    this.setViewValues(this.largeLabel, 0.5F, 0.5F, 4);
                }

                this.smallLabel.setVisibility(4);
            } else if (checked) {
                this.setViewLayoutParams(this.icon, (int)((float)this.defaultMargin + this.shiftAmount), 49);
                this.setViewValues(this.largeLabel, 1.0F, 1.0F, 0);
                this.setViewValues(this.smallLabel, this.scaleUpFactor, this.scaleUpFactor, 4);
            } else {
                this.setViewLayoutParams(this.icon, this.defaultMargin, 49);
                this.setViewValues(this.largeLabel, this.scaleDownFactor, this.scaleDownFactor, 4);
                this.setViewValues(this.smallLabel, 1.0F, 1.0F, 0);
            }
            break;
        case 0:
            if (checked) {
                this.setViewLayoutParams(this.icon, this.defaultMargin, 49);
                this.setViewValues(this.largeLabel, 1.0F, 1.0F, 0);
            } else {
                this.setViewLayoutParams(this.icon, this.defaultMargin, 17);
                this.setViewValues(this.largeLabel, 0.5F, 0.5F, 4);
            }

            this.smallLabel.setVisibility(4);
            break;
        case 1:
            if (checked) {
                this.setViewLayoutParams(this.icon, (int)((float)this.defaultMargin + this.shiftAmount), 49);
                this.setViewValues(this.largeLabel, 1.0F, 1.0F, 0);
                this.setViewValues(this.smallLabel, this.scaleUpFactor, this.scaleUpFactor, 4);
            } else {
                this.setViewLayoutParams(this.icon, this.defaultMargin, 49);
                this.setViewValues(this.largeLabel, this.scaleDownFactor, this.scaleDownFactor, 4);
                this.setViewValues(this.smallLabel, 1.0F, 1.0F, 0);
            }
            break;
        case 2:
            this.setViewLayoutParams(this.icon, this.defaultMargin, 17);
            this.largeLabel.setVisibility(8);
            this.smallLabel.setVisibility(8);
        }

        this.refreshDrawableState();
        this.setSelected(checked);
    }

通过这个方法,得到了控制itemVIew的显示方式 : 除了是否被选中意外。还有两个变量:labelVisibilityMode = -1 和 isShifting:isShifting三个以上的时候为true
通常情况下,调用setShifting方法,将isShifting设置为false的话,第一次初始化的时候就能够正常的显示文字和图片了 ,但是 一点击其他的tab,未被选中的tab又只显示图标了。我猜多半是点击的时候,进行了某个操作,修改了我的设置,又去找源码中关于tab点击的部分,
因为BottomNavigationItemView类中,并没有关于点击事件的处理,所以 ,我找到了它的父类BottomNavigationMenuView。在父类中,有这么一句:
private final Pool itemPool;
this.itemPool = new SynchronizedPool(5); 知道了最多只支持5个ItemTab。然后,找到了点击事件的方法

  this.onClickListener = new OnClickListener() {
            public void onClick(View v) {
                BottomNavigationItemView itemView = (BottomNavigationItemView)v;
                MenuItem item = itemView.getItemData();
                if (!BottomNavigationMenuView.this.menu.performItemAction(item, BottomNavigationMenuView.this.presenter, 0)) {
                    item.setChecked(true);
                }

            }
        };

方法里面除了一个MenuItem设置为选中状态,并没有发现有其他更新操作。但是用到了一个presenter对象,是属于BottomNavigationPresenter,所以我又去看这个类里面干了什么事情


    public void updateMenuView(boolean cleared) {
        if (!this.updateSuspended) {
            if (cleared) {
                this.menuView.buildMenuView();
            } else {
                this.menuView.updateMenuView();
            }

        }
    }

看到有个这个方法,调用了BottomNavigationMenuView的updateMenuView或者buildMenuView。 所以 ,又回去找到这两个方法

 public void buildMenuView() {
        this.removeAllViews();
        int i;
        if (this.buttons != null) {
            BottomNavigationItemView[] var1 = this.buttons;
            i = var1.length;

            for(int var3 = 0; var3 < i; ++var3) {
                BottomNavigationItemView item = var1[var3];
                if (item != null) {
                    this.itemPool.release(item);
                }
            }
        }

        if (this.menu.size() == 0) {
            this.selectedItemId = 0;
            this.selectedItemPosition = 0;
            this.buttons = null;
        } else {
            this.buttons = new BottomNavigationItemView[this.menu.size()];
            boolean shifting = this.isShifting(this.labelVisibilityMode, this.menu.getVisibleItems().size());

            for(i = 0; i < this.menu.size(); ++i) {
                this.presenter.setUpdateSuspended(true);
                this.menu.getItem(i).setCheckable(true);
                this.presenter.setUpdateSuspended(false);
                BottomNavigationItemView child = this.getNewItem();
                this.buttons[i] = child;
                child.setIconTintList(this.itemIconTint);
                child.setIconSize(this.itemIconSize);
                child.setTextColor(this.itemTextColorDefault);
                child.setTextAppearanceInactive(this.itemTextAppearanceInactive);
                child.setTextAppearanceActive(this.itemTextAppearanceActive);
                child.setTextColor(this.itemTextColorFromUser);
                if (this.itemBackground != null) {
                    child.setItemBackground(this.itemBackground);
                } else {
                    child.setItemBackground(this.itemBackgroundRes);
                }

                child.setShifting(shifting);
                child.setLabelVisibilityMode(this.labelVisibilityMode);
                child.initialize((MenuItemImpl)this.menu.getItem(i), 0);
                child.setItemPosition(i);
                child.setOnClickListener(this.onClickListener);
                this.addView(child);
            }

            this.selectedItemPosition = Math.min(this.menu.size() - 1, this.selectedItemPosition);
            this.menu.getItem(this.selectedItemPosition).setChecked(true);
        }
    }

 public void updateMenuView() {
        if (this.menu != null && this.buttons != null) {
            int menuSize = this.menu.size();
            if (menuSize != this.buttons.length) {
                this.buildMenuView();
            } else {
                int previousSelectedId = this.selectedItemId;

                for(int i = 0; i < menuSize; ++i) {
                    MenuItem item = this.menu.getItem(i);
                    if (item.isChecked()) {
                        this.selectedItemId = item.getItemId();
                        this.selectedItemPosition = i;
                    }
                }

                if (previousSelectedId != this.selectedItemId) {
                    TransitionManager.beginDelayedTransition(this, this.set);
                }

                boolean shifting = this.isShifting(this.labelVisibilityMode, this.menu.getVisibleItems().size());

                for(int i = 0; i < menuSize; ++i) {
                    this.presenter.setUpdateSuspended(true);
                    this.buttons[i].setLabelVisibilityMode(this.labelVisibilityMode);
                    this.buttons[i].setShifting(shifting);
                    this.buttons[i].initialize((MenuItemImpl)this.menu.getItem(i), 0);
                    this.presenter.setUpdateSuspended(false);
                }

            }
        }
    }

这两个方法里面都看到这么一句

 boolean shifting = this.isShifting(this.labelVisibilityMode, this.menu.getVisibleItems().size());
    private boolean isShifting(int labelVisibilityMode, int childCount) {
        return labelVisibilityMode == -1 ? childCount > 3 : labelVisibilityMode == 0;
    }

这句话,又把我们设置为false的shifting 给改成true了(因为labelVisibilityMode = -1)。所以,我想应该是要修改labelVisibilityMode 的值,让它不能把isshifting改成true 。查看BottomNavigationItemView类中的setChecked方法
当labelVisibilityMode = 1的时候,就能够完美的正常显示文字和图片了

  switch(this.labelVisibilityMode)
    case 1:
            if (checked) {
                this.setViewLayoutParams(this.icon, (int)((float)this.defaultMargin + this.shiftAmount), 49);
                this.setViewValues(this.largeLabel, 1.0F, 1.0F, 0);
                this.setViewValues(this.smallLabel, this.scaleUpFactor, this.scaleUpFactor, 4);
            } else {
                this.setViewLayoutParams(this.icon, this.defaultMargin, 49);
                this.setViewValues(this.largeLabel, this.scaleDownFactor, this.scaleDownFactor, 4);
                this.setViewValues(this.smallLabel, 1.0F, 1.0F, 0);
            }

结论来了 :将BottomNavigationMenuView类的labelVisibilityMode改成1,这样就满足同时显示文字和图片的条件了。整个过程就结束了,贴上使用代码

//创建帮助类BottomNavigationViewHelper 
public class BottomNavigationViewHelper {

@SuppressLint("RestrictedApi")
public static void disableShiftMode(BottomNavigationView view) {

    BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
    try {
        menuView.setLabelVisibilityMode(1);
        for (int i = 0; i < menuView.getChildCount(); i++) {
            BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
            item.setShifting(false);
        }
    } catch (Exception e) {

    }
}
}

//Activity中使用:
        BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.home_bar);
        BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);
        bottomNavigationView.setOnNavigationItemSelectedListener(new 

这个地方也只是把这种效果做出来了,具体还有很多不足之处 ,有一些地方自己也没理解的很清楚,望各位见谅。
其他的属性使用 可以参考网络上大神的文章

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值