"support:design:28.0.0"或androidx使用BottomNavigationView時取消位移動畫

  Android 項目在使用androidx 或者 "support:design:28.0.0"依賴時,取消BottomNavigationView大於3個item的位移動畫

 最近新項目要使用底部導航BottomNavigationView控件,但是在底部item大於3個的時候就會有位移動畫,我們需要禁用位移動畫,(作爲面向網絡編程的程序員)我上網一搜索,複製粘貼過來:

    /**
     * 解決BottomNavigationView大於3個item時的位移
     * @param view
     */
    public static void disableShiftMode(BottomNavigationView view) {
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.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 item = (BottomNavigationItemView) menuView.getChildAt(i);

                item.setShiftingMode(false);

                item.setChecked(item.getItemData().isChecked());
            }
        } catch (NoSuchFieldException e) {
            Log.e("BNVHelper", "Unable to get shift mode field", e);
        } catch (IllegalAccessException e) {
            Log.e("BNVHelper", "Unable to change value of shift mode", e);
        }
    }

   然後運行,but,並沒有起作用,認真分析代碼,思路就是要利用反射,把 mShiftingMode 字段設置爲false , 點進源碼搜索發現並沒有這個字段。後來在之前項目中發現這個代碼方法並沒有問題,只是項目引用的support:design 版本不一樣,原來Google在support:design:28.0.0的時候把一些組件的源碼更改了(真坑啊。。。) 回到28版本的BottomNavigationItemView 源碼中仔細閱讀源碼,發現了兩個變量:labelVisibilityMode  isShifting 。在setCheck(boolean checked)方法中,當分析實驗後發現只有當lableVisibility爲1並且isShifting 爲false時,才能達到我們的效果。源碼如下: 

​
public void setChecked(boolean checked) {
        this.largeLabel.setPivotX((float)(this.largeLabel.getWidth() / 2));
        this.largeLabel.setPivotY((float)this.largeLabel.getBaseline());
        this.smallLabel.setPivotX((float)(this.smallLabel.getWidth() / 2));
        this.smallLabel.setPivotY((float)this.smallLabel.getBaseline());
        switch(this.labelVisibilityMode) {
        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;
        case 0:
            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);
            break;
        case 1:
            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;
        case 2:
            this.setViewLayoutParams(this.icon, this.defaultMargin, 17);
            this.largeLabel.setVisibility(8);
            this.smallLabel.setVisibility(8);
        }

        this.refreshDrawableState();
        this.setSelected(checked);
    }

  所以,我們可以這樣寫: 

class BottomNavigationViewUtil {
    companion object {
        /**
         * 解決BottomNavigationView大於3個item時的位移
         * 針對com.android.support:design:28.0.0以上或andoidx中com.google.android.material:material:1.0.0-beta01以上
         * @param view
         */
        @SuppressLint("RestrictedApi")
        fun disableShiftMode(view: BottomNavigationView) {
            val menuView = view.getChildAt(0) as BottomNavigationMenuView
            try {
                menuView.labelVisibilityMode = LabelVisibilityMode.LABEL_VISIBILITY_LABELED // 1
                for (i in 0 until menuView.childCount) {
                    val item = menuView.getChildAt(i) as BottomNavigationItemView
                    item.setShifting(false)
                }
            } catch (e: Exception) {
                Log.e("NavigationView", "Unable to get shift mode field", e)
            }

        }
    }

}

  最後,使用底部導航BottomNavigationView時先注意引入的support:design是哪個版本的,如果是support:design:28.0.0或者使用的是androix版本,可以用後面這種方法,反之用最上面的方法。

 

//===============================================================================================

參考博客:https://blog.csdn.net/qq_33707520/article/details/81941857

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章