BottomNavigationView解決三個限制記錄

夜幕降流星雨發表於2018-04-11

在檢視lottie動畫庫的程式碼時發現它的底部是利用BottomNavigationView實現的底部導航欄,但是卻不受3個的限制(控制元件超過三個就會進行處理,隱藏除選中外的文字並縮小),還保留了控制元件原本3個以內的效果,這裡我就把它的程式碼貼出來

BottomNavigationView解決三個限制記錄

  • BottomNavigationView的結構,清楚了控制元件的構成就容易解決問題了

//從上倒下包含
BottomNavigationView 
BottomNavigationMenu 
BottomNavigationItemView 複製程式碼
  • lottie中程式碼使用kotlin寫的

private val TAG = NoShiftBottomNavigationView::class.java.name
​
class NoShiftBottomNavigationView @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0
) : BottomNavigationView(context, attrs, defStyleAttr) {
​
    override fun onViewAdded(child: View?) {
        super.onViewAdded(child)
        removeShiftAnimation()
    }
​
    @SuppressLint("RestrictedApi")
    private fun removeShiftAnimation() {
        val menuView = getChildAt(0) as BottomNavigationMenuView
        try {
            menuView::class.java.getDeclaredField("mShiftingMode").apply {
                isAccessible = true
                setBoolean(menuView, false)
                isAccessible = false
            }
​
            menuView.children
                    .map { it as BottomNavigationItemView }
                    .forEach {
                        it.setShiftingMode(false)
                        it.setChecked(it.itemData.isChecked)
                    }
        } catch (e: NoSuchFieldException) {
            Log.e(TAG, "Unable to get shift mode field", e)
        } catch (e: IllegalAccessException) {
            Log.e(TAG, "Unable to change value of shift mode", e)
        }
    }
}複製程式碼
  • 我也寫了一份java的(最近正好在學koltin)

public class NoShiftBottomNavigationView extends BottomNavigationView {
​
    private String TAG = getClass().getSimpleName();
    
    public NoShiftBottomNavigationView(Context context) {
        this(context,null);
    }
​
    public NoShiftBottomNavigationView(Context context, AttributeSet attrs) {
        super(context, attrs,0);
    }
​
    public NoShiftBottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
​
    @Override
    public void onViewAdded(View child) {
        super.onViewAdded(child);
        //當底部導航選單被新增,去除系統的效果
        removeShiftAnimation();
    }
​
    @SuppressLint("RestrictedApi")
    private void removeShiftAnimation() {
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) getChildAt(0);
        try {
            //利用反射獲取到mShiftingMode屬性,設定為false不需要shift動畫效果(控制移動動畫)
            Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
            //忽略該屬性的訪問顯示
            shiftingMode.setAccessible(true);
            shiftingMode.setBoolean(menuView,false);
            shiftingMode.setAccessible(false);
​
            //取消每一個子選單的shift動畫效果(控制文字是否顯示隱藏)
            for (int i = 0; i < menuView.getChildCount(); i++) {
                BottomNavigationItemView itemView  = (BottomNavigationItemView) menuView.getChildAt(i);
                itemView.setShiftingMode(false);
                itemView.setChecked(itemView.getItemData().isChecked());
            }
        } catch (NoSuchFieldException e) {
            Log.e(TAG, "Unable to get shift mode field", e);
        } catch (IllegalAccessException e) {
            Log.e(TAG, "Unable to change value of shift mode", e);
        }
    }
}複製程式碼
  • 注意

    如果混淆了design包記得忽略混淆該屬性,防止混淆後屬性名變化,反射無法找到該屬性,導致異常

-keepclassmembers class android.support.design.internal.BottomNavigationMenuView { 
    boolean mShiftingMode; 
}複製程式碼


相關文章