BottomNavigationView取消动画

2,700 阅读1分钟

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