底部导航栏的使用非常广泛,在Android Design Support Library25,google推出了Android的底部导航栏------BottomNavigationView.
BottomNavigationView指南
BottomNavigationView官方文档
一、BottomNavigationView简单使用
使用前添加依赖
compile 'com.android.support:design:25.3.1'
布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:menu="@menu/bottom_navigation">
</android.support.design.widget.BottomNavigationView>
</RelativeLayout>
和NavigationView的使用差不多,BottomNavigationView的内容部分定义在菜单文件夹下,然后通过 app:menu=" "属性引用该菜单文件即可。
在res/menu/bottom_navigation.xml中
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/item_1"
android:icon="@mipmap/p1"
android:title="消息" />
<item
android:id="@+id/item_2"
android:icon="@mipmap/p2"
android:title="联系人" />
<item
android:id="@+id/item_3"
android:icon="@mipmap/p3"
android:title="动态" />
</menu>
效果图
二、BottomNavigationView的常用属性
1、图标颜色修改
上面三张是图标原图,而根据效果图可以发现:选中和未被选中时的颜色都是主题中的,并未使用图标本身颜色,我们可以通过下面这条属性修改图标颜色
app:itemIconTint=" "
(1)这里的图标颜色可以是单一的,选中未选中都是一个颜色,像这样:
app:itemIconTint="@android:color/holo_blue_light"
(2)也可以给图标颜色添加一个选择器效果,像这样:
app:itemIconTint="@color/seletor_bottom_navi"
颜色选择器:res/color/seletor_bottom_navi.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/holo_blue_light"
android:state_checked="true" />
<item android:color="@android:color/black" />
</selector>
(3)当然,你也可以恢复图标本身颜色,需要在代码中设置
mBottomNV = (BottomNavigationView) findViewById(R.id.bottom_navigation);
mBottomNV.setItemIconTintList(null);
(4)如果你想给图标也添加一个选择器效果,你可以在菜单文件中引用图片时引用一个seletor
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/item_1"
android:icon="@drawable/seletor_item1"
android:title="消息" />
<item
android:id="@+id/item_2"
android:icon="@mipmap/p2"
android:title="联系人" />
<item
android:id="@+id/item_3"
android:icon="@mipmap/p3"
android:title="动态" />
</menu>
图片选择器:res/drawable/seletor_item1.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/p1" android:state_checked="true"></item>
<item android:drawable="@mipmap/p4" ></item>
</selector>
2、字体颜色修改
字体颜色默认也是使用系统主题中的,我们可以通过下面这条属性修改:
app:itemTextColor=" "
你可以使用单一的,也可以添加一个选择器效果
app:itemTextColor="@android:color/holo_blue_light"
app:itemTextColor="@color/seletor_bottom_navi"
3、背景颜色修改
app:itemBackground=""
当然,你也可以直接通过android:background=" "修改背景颜色
三、BottomNavigationView常用方法
设置图标颜色
setItemIconTintList()
设置字体颜色
setItemTextColor()
设置背景
setBackgroundColor() 需要一个颜色值
setItemBackgroundResource() 需要一个资源id,可以是颜色、图片、shape
setBackground() 需要一个drawable对象,minSdkVersion>=16才可以用
设置默认选中哪个item
setSelectedItemId()
设置监听
setOnNavigationItemSelectedListener()
mBottomNV.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.item_1:
//do something
break;
case R.id.item_2:
//do something
break;
case R.id.item_3:
//do something
break;
}
return true;
}
});
四、BottomNavigationView使用规范
1)官方建议菜单item个数为 3~5 个
我尝试6个item,直接报错:
于是查看BottomNavigationView源码:
public int getMaxItemCount() {
return BottomNavigationMenu.MAX_ITEM_COUNT;
}
追踪到BottomNavigationMenu:
public static final int MAX_ITEM_COUNT = 5;
ok,完全了解了.
我又尝试2个,没有报错,不过2个的话还是不建议使用BottomNavigationView
2)底部导航栏高度建议是56dp
更多规范请查看官网BottomNavigationView指南
五、关于BottomNavigationView的ShiftingMode
(1)上面我们一直使用三个item,下面我们使用4个item试一试
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/item_1"
android:icon="@mipmap/p1"
android:title="消息" />
<item
android:id="@+id/item_2"
android:icon="@mipmap/p2"
android:title="联系人" />
<item
android:id="@+id/item_3"
android:icon="@mipmap/p3"
android:title="动态" />
<item
android:id="@+id/item_4"
android:icon="@mipmap/p4"
android:title="我的" />
</menu>
效果图
可以看见,当item数量为4个的时候,效果和之前完全不一样了。。。。。。
(2)查看源码,最终追踪到:
public void buildMenuView() {
removeAllViews();
if (mButtons != null) {
for (BottomNavigationItemView item : mButtons) {
mItemPool.release(item);
}
}
if (mMenu.size() == 0) {
mSelectedItemId = 0;
mSelectedItemPosition = 0;
mButtons = null;
return;
}
mButtons = new BottomNavigationItemView[mMenu.size()];
mShiftingMode = mMenu.size() > 3;//❤❤❤❤❤
for (int i = 0; i < mMenu.size(); i++) {
mPresenter.setUpdateSuspended(true);
mMenu.getItem(i).setCheckable(true);
mPresenter.setUpdateSuspended(false);
BottomNavigationItemView child = getNewItem();
mButtons[i] = child;
child.setIconTintList(mItemIconTint);
child.setTextColor(mItemTextColor);
child.setItemBackground(mItemBackgroundRes);
child.setShiftingMode(mShiftingMode);//❤❤❤❤❤
child.initialize((MenuItemImpl) mMenu.getItem(i), 0);
child.setItemPosition(i);
child.setOnClickListener(mOnClickListener);
addView(child);
}
mSelectedItemPosition = Math.min(mMenu.size() - 1, mSelectedItemPosition);
mMenu.getItem(mSelectedItemPosition).setChecked(true);
}
public void setShiftingMode(boolean enabled) {
mShiftingMode = enabled;
}
public void setChecked(boolean checked) {
ViewCompat.setPivotX(mLargeLabel, mLargeLabel.getWidth() / 2);
ViewCompat.setPivotY(mLargeLabel, mLargeLabel.getBaseline());
ViewCompat.setPivotX(mSmallLabel, mSmallLabel.getWidth() / 2);
ViewCompat.setPivotY(mSmallLabel, mSmallLabel.getBaseline());
if (mShiftingMode) {//❤❤❤❤❤
if (checked) {
LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
iconParams.topMargin = mDefaultMargin;
mIcon.setLayoutParams(iconParams);
mLargeLabel.setVisibility(VISIBLE);
ViewCompat.setScaleX(mLargeLabel, 1f);
ViewCompat.setScaleY(mLargeLabel, 1f);
} else {
LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
iconParams.gravity = Gravity.CENTER;
iconParams.topMargin = mDefaultMargin;
mIcon.setLayoutParams(iconParams);
mLargeLabel.setVisibility(INVISIBLE);
ViewCompat.setScaleX(mLargeLabel, 0.5f);
ViewCompat.setScaleY(mLargeLabel, 0.5f);
}
mSmallLabel.setVisibility(INVISIBLE);
} else {//❤❤❤❤❤
if (checked) {
LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
iconParams.topMargin = mDefaultMargin + mShiftAmount;
mIcon.setLayoutParams(iconParams);
mLargeLabel.setVisibility(VISIBLE);
mSmallLabel.setVisibility(INVISIBLE);
ViewCompat.setScaleX(mLargeLabel, 1f);
ViewCompat.setScaleY(mLargeLabel, 1f);
ViewCompat.setScaleX(mSmallLabel, mScaleUpFactor);
ViewCompat.setScaleY(mSmallLabel, mScaleUpFactor);
} else {
LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
iconParams.topMargin = mDefaultMargin;
mIcon.setLayoutParams(iconParams);
mLargeLabel.setVisibility(INVISIBLE);
mSmallLabel.setVisibility(VISIBLE);
ViewCompat.setScaleX(mLargeLabel, mScaleDownFactor);
ViewCompat.setScaleY(mLargeLabel, mScaleDownFactor);
ViewCompat.setScaleX(mSmallLabel, 1f);
ViewCompat.setScaleY(mSmallLabel, 1f);
}
}
refreshDrawableState();
}
好吧,item数量大于3的时候会开启ShiftingMode,效果和之前完全不一样了......
这种效果简直难以忍受,而且目前还没有一个属性或者方法能够修改ShiftingMode.
(3) 通过反射修改ShiftingMode
准备用反射来修改ShiftingMode值,结果发现stackoverflow上早已经有外国小哥写好了,直接copy就可以了~~~
/**
* 新建一个BottomNavigationView帮助者类
*/
public class BottomNavigationViewHelper {
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);
//noinspection RestrictedApi
item.setShiftingMode(false);
// set once again checked value, so view will be updated
//noinspection RestrictedApi
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);
}
}
}
然后调用即可
BottomNavigationViewHelper.disableShiftMode(mBottomNV);
最后,你需要在混淆文件中配置
-keepclassmembers class android.support.design.internal.BottomNavigationMenuView {
boolean mShiftingMode;
}
(4) 效果图
ok,完美解决