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的提示。

f1465bdb73c2

image

出现的是com.google.android.material.bottomnavigation.BottomNavigationView

既然官方 推荐使用BottomNavigationView 那就抱着试试的心态去使用了 , 属性基本和design 包下的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"

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

f1465bdb73c2

运行后效果.gif

查看BottomNavigationView 源码:

f1465bdb73c2

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 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 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();

}

}

运行后得到想要的效果。

f1465bdb73c2

运行后效果.gif

延伸阅读layout布局

layout.design_bottom_navigation_item

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"/>

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">

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"/>

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"/>

12sp

14sp

如有理解有误的地方,希望指正。

转载请注明来源,谢谢!

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐