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