BottomNavigationView 控件去除放大缩小动画

BottomNavigationView 控件去除放大缩小动画

最近项目中有用到底部导航栏,最初的底部导航栏是使用的是‘com.android.support:design’包android.support.design.widget.BottomNavigationView 进行设置;按钮点击后的放大效果可以反射 BottomNavigationMenuView 下的mShiftingMode 属性进行取消。即可做到取消放大缩小动画效果。代码如下:

 @SuppressLint("RestrictedApi")
 public static void disableShiftMode(BottomNavigationView navigationView) {
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) navigationView.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 itemView = (BottomNavigationItemView) menuView.getChildAt(i);
                itemView.setShiftingMode(false);
                itemView.setChecked(itemView.getItemData().isChecked());
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
  }

但是在新版本中,当你引入design 依赖。当在布局文件中写入Button 后不再有android.support.design.widget.BottomNavigationView的提示。


image

出现的是com.google.android.material.bottomnavigation.BottomNavigationView
既然官方 推荐使用BottomNavigationView 那就抱着试试的心态去使用了 , 属性基本和design 包下的BottomNavigationView 使用一致。

使用如下:

<com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/bottom_navigation_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_gravity="bottom"
            app:itemBackground="@null"
            app:itemHorizontalTranslationEnabled="false"
            app:itemIconTint="@drawable/color_state_menu_navi"
            app:itemTextColor="@drawable/color_state_menu_navi"
            app:menu="@menu/bottom_navigation_main" />

运行后的效果却还是带有放大动画效果,这不是产品想要的效果。度娘了一番后部分博客给出了添加属性的方法。

app:labelVisibilityMode="labeled"

运行后动画效果,却还是存在。
运行后效果.gif

查看BottomNavigationView 源码:

image.png
package com.google.android.material.bottomnavigation;

public class BottomNavigationView extends FrameLayout {
    private static final int MENU_PRESENTER_ID = 1;
    private final MenuBuilder menu;
    private final BottomNavigationMenuView menuView;
    private final BottomNavigationPresenter presenter;
    private MenuInflater menuInflater;

在BottomNavigationView 类中搜索,没有找到mShiftingMode 延伸阅读 BottomNavigationMenuView 看看这个菜单类。
希望在 BottomNavigationMenuView源码中或许有 mShiftingMode 属性的调用。
直接搜索。。
还是没有!
无奈,就读下源码。
在BottomNavigationMenuView 中发现以下代码。

private final Pool<BottomNavigationItemView> itemPool;

由对象池管理BottomNavigation 每一个Item 的View。
点击 BottomNavigationItemView 查看源码。

public BottomNavigationItemView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.itemPosition = -1;
        Resources res = this.getResources();
        LayoutInflater.from(context).inflate(layout.design_bottom_navigation_item, this, true);
        this.setBackgroundResource(drawable.design_bottom_navigation_item_background);
        this.defaultMargin = res.getDimensionPixelSize(dimen.design_bottom_navigation_margin);
        this.icon = (ImageView)this.findViewById(id.icon);
        this.smallLabel = (TextView)this.findViewById(id.smallLabel);
        this.largeLabel = (TextView)this.findViewById(id.largeLabel);
        ViewCompat.setImportantForAccessibility(this.smallLabel, 2);
        ViewCompat.setImportantForAccessibility(this.largeLabel, 2);
        this.setFocusable(true);
        this.calculateTextScaleFactors(this.smallLabel.getTextSize(), this.largeLabel.getTextSize());
    }

在构造方法中有icon 和 文本标签,这就是每一个Item的实现类了。
开始梳理调用逻辑。--------------->>>>>>>>>
在构造方法中,有两个TextView smallLabel 和 largeLabel 的初始化。一个item 按钮有2个文本的显示,一个小标签,一个大标签,icon 忽略。并且调用了calculateTextScaleFactors 方法。

 private void calculateTextScaleFactors(float smallLabelSize, float largeLabelSize) {
        this.shiftAmount = smallLabelSize - largeLabelSize;
        this.scaleUpFactor = 1.0F * largeLabelSize / smallLabelSize;
        this.scaleDownFactor = 1.0F * smallLabelSize / largeLabelSize;
    }

搜索 shiftAmount 、scaleUpFactor、scaleDownFactor 调用位置。

         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;

在上述代码 else if (checked) 及 else 处有对三个属性进行调用。

private void setViewLayoutParams(@NonNull View view, int topMargin, int gravity) {
        LayoutParams viewParams = (LayoutParams)view.getLayoutParams();
        viewParams.topMargin = topMargin;
        viewParams.gravity = gravity;
        view.setLayoutParams(viewParams);
    }
  private void setViewValues(@NonNull View view, float scaleX, float scaleY, int visibility) {
        view.setScaleX(scaleX);
        view.setScaleY(scaleY);
        view.setVisibility(visibility);
    }

通过上述的两个方法,可以得知
shiftAmount 为icon设置上边距的偏移量
scaleUpFactor 为 largeLabel 的缩放值,默认为1.0F
scaleDownFactor 为smallLabel 的缩放值 ,默认为 1.0F

找到了调用逻辑,接下来就对shiftAmount,scaleUpFactor,scaleDownFactor 属性进行反射处理,让点击和非点击状态的大小一致。
设置 shiftAmount 的偏移量为0,使icon 不上下移动。
设置 scaleUpFactor scaleDownFactor 为默认状态下的值 1。
使BottomNavigationItemView 处于默认状态,不发生位置偏移。

代码如下:

 @SuppressLint("RestrictedApi")
 public void closeAnimation(BottomNavigationView view) {
        BottomNavigationMenuView mMenuView = (BottomNavigationMenuView) view.getChildAt(0);
        for (int i = 0; i < mMenuView.getChildCount(); i++) {
            BottomNavigationItemView button = (BottomNavigationItemView) mMenuView.getChildAt(i);
            TextView mLargeLabel = getField(button.getClass(), button, "largeLabel");
            TextView mSmallLabel = getField(button.getClass(), button, "smallLabel");
            float mSmallLabelSize = mSmallLabel.getTextSize();
            setField(button.getClass(), button, "shiftAmount", 0F);
            setField(button.getClass(), button, "scaleUpFactor", 1F);
            setField(button.getClass(), button, "scaleDownFactor", 1F);
            mLargeLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, mSmallLabelSize);
        }
        mMenuView.updateMenuView();
    }


 private <T> T getField(Class targetClass, Object instance, String fieldName) {
        try {
            Field field = targetClass.getDeclaredField(fieldName);
            field.setAccessible(true);
            return (T) field.get(instance);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }


    private void setField(Class targetClass, Object instance, String fieldName, Object value) {
        try {
            Field field = targetClass.getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(instance, value);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

运行后得到想要的效果。


运行后效果.gif

延伸阅读layout布局
layout.design_bottom_navigation_item

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
  <ImageView
      android:id="@+id/icon"
      android:layout_width="24dp"
      android:layout_height="24dp"
      android:layout_marginTop="@dimen/design_bottom_navigation_margin"
      android:layout_marginBottom="@dimen/design_bottom_navigation_margin"
      android:layout_gravity="center_horizontal"
      android:contentDescription="@null"
      android:duplicateParentState="true"/>
  <com.google.android.material.internal.BaselineLayout
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="bottom|center_horizontal"
      android:paddingBottom="10dp"
      android:clipToPadding="false"
      android:duplicateParentState="true">
    <TextView
        android:id="@+id/smallLabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:duplicateParentState="true"
        android:maxLines="1"
        android:textSize="@dimen/design_bottom_navigation_text_size"/>
    <TextView
        android:id="@+id/largeLabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="8dp"
        android:paddingRight="8dp"
        android:duplicateParentState="true"
        android:maxLines="1"
        android:textSize="@dimen/design_bottom_navigation_active_text_size"
        android:visibility="invisible"/>
  </com.google.android.material.internal.BaselineLayout>
</merge>

<dimen name="design_bottom_navigation_text_size">12sp</dimen>
<dimen name="design_bottom_navigation_active_text_size">14sp</dimen>

如有理解有误的地方,希望指正。
转载请注明来源,谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268