简介:上一篇讲解了BottomNavigationBar底部导航栏的使用,这一篇还是底部导航栏,它属于Material Design下面的 ,用法更加简单,扩展稍微少些,属于弱化版~
版本更新:2020-2-29
1、动态设置导航栏个数
2、解决选中和未选中字体大小不一致
版本更新:2019-5-13
1.新增androidX适配
2.androidX水波纹无效果
androidX依赖更改:
1、更新前:
implementation 'com.android.support:design:27.1.1'
更新后:
implementation 'com.google.android.material:material:1.0.0'
2、包名更改:
更新前:
android.support.design.widget.BottomNavigationView
更新后:
com.google.android.material.bottomnavigation.BottomNavigationView
setItemType这个方法可以删除不使用了,在布局文件中新增即可:
app:labelVisibilityMode="labeled"
1、
2、项目build.gradle添加依赖:(注意studio3.0以下将implementation 换成 compile)
implementation 'com.android.support:design:27.1.1'
3、MainActivity
import android.annotation.SuppressLint;
import android.support.annotation.NonNull;
import android.support.design.internal.BottomNavigationItemView;
import android.support.design.internal.BottomNavigationMenuView;
import android.support.design.widget.BottomNavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import java.lang.reflect.Field;
public class MainActivity extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener {
private BottomNavigationView navigation;
//默认选择第一个fragment
private int lastSelectedPosition = 0;
private FirstFragment firstFragment;
private SecondFragment secondFragment;
private ThirdFragment thirdFragment;
private FourthFragment fourthFragment;
private Fragment[] fragments;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
navigation = this.findViewById(R.id.navigation);
initFragments();
}
private void initFragments() {
//监听切换事件
navigation.setOnNavigationItemSelectedListener(this);
//平均布局
setItemType(navigation);
//添加角标消息数
setAddNumber();
firstFragment = new FirstFragment();
secondFragment = new SecondFragment();
thirdFragment = new ThirdFragment();
fourthFragment = new FourthFragment();
fragments = new Fragment[]{firstFragment, secondFragment, thirdFragment,fourthFragment};
lastSelectedPosition = 0;
//默认提交第一个
getSupportFragmentManager()
.beginTransaction()
.add(R.id.tb, firstFragment)//添加
.show(firstFragment)//展示
.commit();//提交
}
private void setAddNumber() {
//获取整个的NavigationView
BottomNavigationMenuView menuView = (BottomNavigationMenuView) navigation.getChildAt(0);
//获取所添加的每一个Tab,并给第三个Tab添加消息角标
View tabView = menuView.getChildAt(2 );
BottomNavigationItemView itemView = (BottomNavigationItemView) tabView;
//加载我们的角标布局View,新创建的一个布局
View badgeView = LayoutInflater.from(this).inflate(R.layout.number_badge, menuView, false);
TextView number=badgeView.findViewById(R.id.msg_number);
//设置显示的内容
number.setText("99");
//添加到Tab上
itemView.addView(badgeView);
}
/**
* 切换Fragment
* @param lastIndex 上个显示Fragment的索引
* @param index 需要显示的Fragment的索引
*/
private void setDefaultFragment(int lastIndex, int index) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.hide(fragments[lastIndex]);
if (!fragments[index].isAdded()) {
transaction.add(R.id.tb, fragments[index]);
}
//需要展示fragment下标的位置
//commit:安排该事务的提交。这一承诺不会立即发生;它将被安排在主线程上,以便在线程准备好的时候完成。
//commitAllowingStateLoss:与 commit类似,但允许在活动状态保存后执行提交。这是危险的,因为如果Activity需要从其状态恢复,
// 那么提交就会丢失,因此,只有在用户可以意外地更改UI状态的情况下,才可以使用该提交
transaction.show(fragments[index]).commit();
}
/**
* 切换事件
*/
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_homefirst:
if (0 != lastSelectedPosition) {
setDefaultFragment(lastSelectedPosition, 0);
lastSelectedPosition = 0;
}
return true;
case R.id.navigation_homesecond:
if (1 != lastSelectedPosition) {
setDefaultFragment(lastSelectedPosition, 1);
lastSelectedPosition = 1;
}
return true;
case R.id.navigation_homethird:
if (2 != lastSelectedPosition) {
setDefaultFragment(lastSelectedPosition, 2);
lastSelectedPosition = 2;
}
return true;
case R.id.navigation_homefourth:
if (3 != lastSelectedPosition) {
setDefaultFragment(lastSelectedPosition, 3);
lastSelectedPosition = 3;
}
return true;
}
return false;
}
/**
* 防止超过3个fragment布局不平分
*/
@SuppressLint("RestrictedApi")
private void setItemType(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);
}
}
}
布局文件activity_main.xml
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<FrameLayout
android:id="@+id/tb"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<android.support.design.widget.BottomNavigationView
android:id="@+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff"
app:itemTextColor="@drawable/home_color_shape"
app:itemIconTint="@drawable/home_color_shape"
app:menu="@menu/navigation" />
</LinearLayout>
4、资源文件 在res目录下新建一个menu文件,在里面新建navigation.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/navigation_homefirst"
android:icon="@drawable/home1_shape"
android:title="首页"
android:tooltipText="drr" />
<item
android:id="@+id/navigation_homesecond"
android:icon="@drawable/home2_shape"
android:title="订单" />
<item
android:id="@+id/navigation_homethird"
android:icon="@drawable/home3_shape"
android:title="动态" />
<item
android:id="@+id/navigation_homefourth"
android:icon="@drawable/home4_shape"
android:title="我的" />
</menu>
home1_shape.xml、(1-4大同小异)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_launcher_background" android:state_checked="true" />
<item android:drawable="@drawable/home" android:state_checked="false" />
</selector>
home_color_shape.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="@color/colorAccent" />
<item android:state_checked="false" android:color="@color/un_Accent"/>
</selector>
false 未选中的状态的文字或图片 true 选中的状态的文字或图片
5、replace方式 (setDefaultFragment方法处改为如下即可)
private void setDefaultFragment( int index) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.tb, fragments[index]);
transaction.commit();
}