欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-24 20:41:40
...

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

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

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