BottomNavigationView扩展

作者: foolchen | 来源:发表于2018-08-12 11:51 被阅读7次

最近开展新的项目,首当其中的问题就是首页导航。

虽然之前就已经知道BottomNavigationView的存在,但是一直没有使用。原因也很明显,BottomNavigationView存在两个非常严重的问题:

  1. 使用png格式的图标时无法显示原本的图案;
  2. 默认有位移动画,且无法通过配置进行取消。


    禁用位移动画.gif

    统一所有条目中图标边距和文本的大小

    在禁用了位移动画后,我们发现在选中一个条目的时候,条目的图标和文本框还是有轻微的位移。我们继续向下分析:

    @Override
        public void setChecked(boolean checked) {
            // ... 省略无关代码
            if (mShiftingMode) {
                // 当mShiftingMode=true时,该分支生效
                if (checked) {
                    // ... 省略无关代码
                    mLargeLabel.setVisibility(VISIBLE);
                    mLargeLabel.setScaleX(1f);
                    mLargeLabel.setScaleY(1f);
                } else {
                    // ... 省略无关代码
                    mLargeLabel.setVisibility(INVISIBLE);
                    mLargeLabel.setScaleX(0.5f);
                    mLargeLabel.setScaleY(0.5f);
                }
                mSmallLabel.setVisibility(INVISIBLE);
            } else {
                // 当mShiftingMode=false时,该分支生效
                if (checked) {
                    LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
                    iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
                    // 选中时,图标的顶部外边距增加了mDefaultMargin+mShiftAmount
                    iconParams.topMargin = mDefaultMargin + mShiftAmount;
                    mIcon.setLayoutParams(iconParams);
                    // 选中时,mLargeLabel显示、mSmallLabel隐藏
                    mLargeLabel.setVisibility(VISIBLE);
                    mSmallLabel.setVisibility(INVISIBLE);
    
                    mLargeLabel.setScaleX(1f);
                    mLargeLabel.setScaleY(1f);
                    mSmallLabel.setScaleX(mScaleUpFactor);
                    mSmallLabel.setScaleY(mScaleUpFactor);
                } else {
                    LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
                    iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
                    // 未选中时,图标的顶部外边距为默认值
                    iconParams.topMargin = mDefaultMargin;
                    mIcon.setLayoutParams(iconParams);
                    
                    // 未选中时,mLargeLabel隐藏、mSmallLabel显示
                    mLargeLabel.setVisibility(INVISIBLE);
                    mSmallLabel.setVisibility(VISIBLE);
                    
                    mLargeLabel.setScaleX(mScaleDownFactor);
                    mLargeLabel.setScaleY(mScaleDownFactor);
                    mSmallLabel.setScaleX(1f);
                    mSmallLabel.setScaleY(1f);
                }
            }
    
            refreshDrawableState();
        }
    

    从上面的代码中可以看出,问题原因在于选中的条目的图标增加了顶部外边距mShiftAmount,以及大小两个文本框的显隐变化。

    为了解决这两个问题,做出如下扩展:

    /**
     * 统一每个条目的文本大小和图标的外边距
     */
    fun BottomNavigationView.unifyItems(forceUpdate: Boolean = true) {
      try {
        val bottomNavigationMenuView = getChildAt(0) as BottomNavigationMenuView
        val childCount = bottomNavigationMenuView.childCount
        for (i in 0 until childCount) {
          val child = bottomNavigationMenuView.getChildAt(i) as BottomNavigationItemView
          val clazz = child.javaClass
    
          // 使选中/未选中条目的顶部边距不发生变化
          val shiftAmountField = clazz.getDeclaredField("mShiftAmount")
          shiftAmountField.setIntValue(child, 0)
    
          // 使选中/未选中条目的文本保持同样的大小
          child.unifyTextSize()
        }
    
        if (forceUpdate) {
          bottomNavigationMenuView.updateMenuView()
        }
      } catch (e: Exception) {
        e.printStackTrace()
      }
    }
    
    private fun BottomNavigationItemView.unifyTextSize() {
      val baselineLayout = getChildAt(1) as BaselineLayout
      val smallLabel = baselineLayout.getChildAt(0) as TextView
      val largeLabel = baselineLayout.getChildAt(1) as TextView
      largeLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, smallLabel.textSize)
    }
    
    private fun Field.setIntValue(obj: Any, value: Int) {
      isAccessible = true
      setInt(obj, value)
      isAccessible = false
    }
    

    效果如下:


    最终效果.gif

相关文章

网友评论

    本文标题:BottomNavigationView扩展

    本文链接:https://www.haomeiwen.com/subject/ullsbftx.html