BottomNavigationView有两种动画:
1. 超过3个时的图片,非选中状态,会隐藏文字标题,且将图片居中,造成图片偏移的效果。源码中判断是否可以偏移:
private boolean isShifting(@LabelVisibilityMode int labelVisibilityMode, int childCount) {
return labelVisibilityMode == LabelVisibilityMode.LABEL_VISIBILITY_AUTO
? childCount > 3
: labelVisibilityMode == LabelVisibilityMode.LABEL_VISIBILITY_SELECTED;
}
所以再xml中设置labelVisibilityMode为labeled来禁止这个动效
app:labelVisibilityMode="labeled"
2. 选中和非选中状态变化时的动画
BottomNavigationItemView有两个标题的TextView:smallLabel和largeLabel。且在设置某一项选中时会修改样式:
@Override
public void setChecked(boolean checked) {
largeLabel.setPivotX(largeLabel.getWidth() / 2);
largeLabel.setPivotY(largeLabel.getBaseline());
smallLabel.setPivotX(smallLabel.getWidth() / 2);
smallLabel.setPivotY(smallLabel.getBaseline());
switch (labelVisibilityMode) {
case LabelVisibilityMode.LABEL_VISIBILITY_AUTO:
if (isShifting) {
if (checked) {
setViewLayoutParams(icon, defaultMargin, Gravity.CENTER_HORIZONTAL | Gravity.TOP);
setViewValues(largeLabel, 1f, 1f, VISIBLE);
} else {
setViewLayoutParams(icon, defaultMargin, Gravity.CENTER);
setViewValues(largeLabel, 0.5f, 0.5f, INVISIBLE);
}
smallLabel.setVisibility(INVISIBLE);
} else {
if (checked) {
setViewLayoutParams(
icon, (int) (defaultMargin + shiftAmount), Gravity.CENTER_HORIZONTAL | Gravity.TOP);
setViewValues(largeLabel, 1f, 1f, VISIBLE);
setViewValues(smallLabel, scaleUpFactor, scaleUpFactor, INVISIBLE);
} else {
setViewLayoutParams(icon, defaultMargin, Gravity.CENTER_HORIZONTAL | Gravity.TOP);
setViewValues(largeLabel, scaleDownFactor, scaleDownFactor, INVISIBLE);
setViewValues(smallLabel, 1f, 1f, VISIBLE);
}
}
break;
case LabelVisibilityMode.LABEL_VISIBILITY_SELECTED:
if (checked) {
setViewLayoutParams(icon, defaultMargin, Gravity.CENTER_HORIZONTAL | Gravity.TOP);
setViewValues(largeLabel, 1f, 1f, VISIBLE);
} else {
setViewLayoutParams(icon, defaultMargin, Gravity.CENTER);
setViewValues(largeLabel, 0.5f, 0.5f, INVISIBLE);
}
smallLabel.setVisibility(INVISIBLE);
break;
case LabelVisibilityMode.LABEL_VISIBILITY_LABELED:
if (checked) {
setViewLayoutParams(
icon, (int) (defaultMargin + shiftAmount), Gravity.CENTER_HORIZONTAL | Gravity.TOP);
setViewValues(largeLabel, 1f, 1f, VISIBLE);
setViewValues(smallLabel, scaleUpFactor, scaleUpFactor, INVISIBLE);
} else {
setViewLayoutParams(icon, defaultMargin, Gravity.CENTER_HORIZONTAL | Gravity.TOP);
setViewValues(largeLabel, scaleDownFactor, scaleDownFactor, INVISIBLE);
setViewValues(smallLabel, 1f, 1f, VISIBLE);
}
break;
case LabelVisibilityMode.LABEL_VISIBILITY_UNLABELED:
setViewLayoutParams(icon, defaultMargin, Gravity.CENTER);
largeLabel.setVisibility(GONE);
smallLabel.setVisibility(GONE);
break;
default:
break;
}
所以当labelVisibilityMode是labeled时,会改变largeLabel的大小,系数scaleDownFactor是smallLabel和largeLabel的字体大小比值(可见calculateTextScaleFactors()方法)。
修改这个文字变大和变小的动效:
设置itemTextAppearanceActive和itemTextAppearanceInactive,将smallLabel和largeLabel的字体大小设置一样
设置方法:
app:itemTextAppearanceActive="@style/navigation_tab_active"
app:itemTextAppearanceInactive="@style/navigation_tab_inactive"
样式:styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="navigation_tab_inactive">
<item name="android:textSize">12sp</item>
</style>
<style name="navigation_tab_active">
<item name="android:textSize">12sp</item>
</style>
</resources>
源码:
public void setTextAppearanceInactive(@StyleRes int inactiveTextAppearance) {
TextViewCompat.setTextAppearance(smallLabel, inactiveTextAppearance);
calculateTextScaleFactors(smallLabel.getTextSize(), largeLabel.getTextSize());
}
public void setTextAppearanceActive(@StyleRes int activeTextAppearance) {
TextViewCompat.setTextAppearance(largeLabel, activeTextAppearance);
calculateTextScaleFactors(smallLabel.getTextSize(), largeLabel.getTextSize());
}