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.pngpackage 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>
如有理解有误的地方,希望指正。
转载请注明来源,谢谢!