要添加底部导航栏,可以使用AS自带的BottomNavigationView来实现,方式就是选择Activity,找到BottomNavigationActivity,这样直接改代码方便实现。
因为是导航,所以还需要有具体的页面,这里是activity,将导航页面布局文件大概处理成如下,同理,导航菜单也需要修改,在此略过不讲。
<!--内容具体的布局容器,以供加载页面-->
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</FrameLayout>
<!--导航选择,以供选择加载页面-->
<android.support.design.widget.BottomNavigationView
android:id="@+id/navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="0dp"
android:layout_marginStart="0dp"
android:background="?android:attr/windowBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/navigation" />
具体的页面就需要fragment来实现了,在此添加几个fragment,添加方式跟fragment类似,下面是项目添加fragment后,在此activity里面添加变量引用
private FragmentDeviceTab deviceTab;
private FragmentHomeTab homeTab;
private FragmentMonitorTab monitorTab;
private FragmentOrderTab orderTab;
private FragmentNotificationTab notificationTab;
//记录当前正在使用的fragment
private Fragment isFragment;
修改mOnNavigationItemSelectedListener实现,我们要根据不同的fragment加载不同的页面
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
if (homeTab == null) {
homeTab = new FragmentHomeTab();
}
switchContent(isFragment, homeTab);
return true;
case R.id.navigation_device:
if (deviceTab == null) {
deviceTab = new FragmentDeviceTab();
}
switchContent(isFragment, deviceTab);
return true;
case R.id.navigation_monitor:
if (monitorTab == null) {
monitorTab = new FragmentMonitorTab();
}
switchContent(isFragment, monitorTab);
return true;
case R.id.navigation_order:
if (orderTab == null) {
orderTab = new FragmentOrderTab();
}
switchContent(isFragment, orderTab);
return true;
case R.id.navigation_notifications:
if (notificationTab == null) {
notificationTab = new FragmentNotificationTab();
}
switchContent(isFragment, notificationTab);
return true;
}
return false;
}
};
public void switchContent(Fragment from, Fragment to) {
if (isFragment != to) {
isFragment = to;
FragmentTransaction ft = getFragmentManager().beginTransaction();
if (!to.isAdded()) { // 先判断是否被add过
ft.hide(from).add(R.id.container, to).commit(); // 隐藏当前的fragment,add下一个到Activity中
} else {
ft.hide(from).show(to).commit(); // 隐藏当前的fragment,显示下一个
}
}
}
然后更改初始化代码如下
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化Fragment及底部导航栏,判断activity是否重建,如果不是,则不需要重新建立fragment.
if (savedInstanceState == null) {
FragmentTransaction beginTransaction = getFragmentManager().beginTransaction();
if (homeTab == null) {
homeTab = new FragmentHomeTab();
}
isFragment = homeTab;
beginTransaction.replace(R.id.container, homeTab).commit();
}
BottomNavigationView navigation = (BottomNavigationView)findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
至此,底部导航即实现了。不过当导航菜单超过3个时,效果和3个及以下的效果已经完全不一样了,只有选中的菜单项才会显示出文字,未选中的菜单项只显示图标,如果要去掉此效果,这时需要使用此方法
@SuppressLint("RestrictedApi")
public static void disableShiftMode(BottomNavigationView view) {
//Acquisition child View BottomNavigationMenuView Objects
BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
try {
//Setting private member variables mShiftingMode Can be modified
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);
}
}
不过当依赖库 'com.android.support:appcompat-v7:X.0.0-rc02' 中大于等于28时,则应该用以下disableShiftMode方法
@SuppressLint("RestrictedApi")
public static void disableShiftMode(BottomNavigationView view) {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
menuView.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);
menuView.buildMenuView();
}
另外,如果想要在导航栏添加消息提示角标,实现思路是将一个文本控件的背景设为红色圆圈,然后文本为消息数,最后将此控件附加到导航菜单项上,在onCreate方法里添加代码如下
//获取整个的NavigationView
BottomNavigationMenuView menuView = (BottomNavigationMenuView) navigation.getChildAt(0);
//这里就是获取所添加的每一个Tab(或者叫menu),
View tab = menuView.getChildAt(3);
BottomNavigationItemView itemView = (BottomNavigationItemView) tab;
//加载我们的角标View,新创建的一个布局
View badge = LayoutInflater.from(this).inflate(R.layout.menu_badge, menuView, false);
//添加到Tab上
itemView.addView(badge);
TextView textView = badge.findViewById(R.id.tv_msg_count);
textView.setText(String.valueOf(1));
//无消息时可以将它隐藏即可
textView.setVisibility(View.VISIBLE);
布局文件如下,里面的background为圆形背景图片
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_msg_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="@dimen/dp_10"
android:layout_marginEnd="@dimen/dp_3"
android:background="@drawable/bg_red_circle_10"
android:gravity="center"
android:textColor="@color/White"
android:textSize="@dimen/sp_12"
android:visibility="gone" />
</LinearLayout>
如果要设置按钮选中状态效果,需要设置两个菜单背景图标,一个选择一个未选中状态。在drawable选中,右击→new →Drawable Resources file新增xml资源文件,然后再图标引用处的background设为此xml文件名称。
至此,底部导航实现,去掉原生动画效果,导航栏的消息提示都设计到了,下面放上效果图
其他对底部导航的设置
设置图片和文件件的距离,直接values资源文件夹下面的在dimens中设置:
<dimen tools:override="true" name="design_bottom_navigation_margin">5dp</dimen>
增加底部导航栏的高度,默认的底部导航栏的高度是 56dp
<dimen tools:override="true" name="design_bottom_navigation_height">84dp</dimen>
设置选中后字体不变,我们现在设置的选中的时候字体会变大,设置为不变:
<dimen tools:override="true" name="design_bottom_navigation_text_size">12sp</dimen>
<dimen tools:override="true" name="design_bottom_navigation_active_text_size">12sp</dimen>