BottomNotificationView 是用来实现底部导航的功能,item 超过3时会有偏移动画且选中时文字才会显示。
新版的 BottomNotificationView 有两个属性可以解决这个问题(网上通过反射的解决方案在这个新版本无效,因为此版本BottomNavigationView底层源码修改了)
1、引入依赖
implementation 'com.android.support:design:28.0.0'
2、设置下面两个属性解决上面的问题
app:itemHorizontalTranslationEnabled="false"
app:labelVisibilityMode="labeled"
app:itemHorizontalTranslationEnabled="false" 禁止item水平平移动画效果。
对应的的方法
是setItemHorizontalTranslationEnabled(false)
app:labelVisibilityMode="labeled" 设置图标下面的文字显示,该属性对应的值有auto、labeled、selected、unlabeled
auto 当item小于等于3是,显示文字,item大于3个默认不显示,选中显示文字
labeled 始终显示文字
selected 选中时显示
unlabeled 不显示文字
该属性对应的方法是setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED)
3、创建导航navigation_items.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/nav_bar_home"
android:icon="@drawable/btn_nav_home_press"
android:title="@string/nav_bar_home"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/nav_bar_score"
android:icon="@drawable/btn_nav_score_normal"
android:title="@string/nav_bar_score"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/nav_bar_user"
android:icon="@drawable/btn_nav_user_normal"
android:title="@string/nav_bar_user"
app:showAsAction="ifRoom"/>
</menu>
4、BottomNavigationView 布局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/MatchMatch.Vertical">
<FrameLayout
android:id="@+id/bottom_nav_bar_content"
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="56dp"
android:background="@color/common_white"
android:elevation="4dp"
android:outlineProvider="bounds"
android:translationZ="8dp"
app:itemHorizontalTranslationEnabled="false"
app:itemIconTint="@color/select_item_color"
app:itemTextColor="@color/select_item_color"
app:labelVisibilityMode="unlabeled"
app:menu="@menu/navigation_items"
tools:targetApi="lollipop"/>
</android.support.v7.widget.LinearLayoutCompat>
//select_item_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/common_orange" android:state_checked="true"/>
<item android:color="@color/text_normal"/>
</selector>
5、解决对Fragment的调度与重用问题,达到最优的Fragment切换的工具类封装 NavHelper.class
/**
* @desciption: 解决对Fragment的调度与重用问题,达到最优的Fragment切换
*/
public class NavHelper<T> {
/**
* 所有Tab集合
*/
private final SparseArray<Tab<T>> tabs = new SparseArray<>();
/** 用于初始化的必须参数*/
private final Context mContext;
private final int mContainerId;
private final FragmentManager mFragmentManager;
private final OnTabChangedListener<T> mListener;
/**
* 当前的一个选中的Tab
*/
private Tab<T> mCurrentTab;
public NavHelper(Context context, int containerId,
FragmentManager fragmentManager, OnTabChangedListener<T> listener) {
mListener = listener;
mContext = context;
mContainerId = containerId;
mFragmentManager = fragmentManager;
}
/**
* 添加tab
*
* @param menuId Tab对应的菜单Id
* @param tab Tab
*/
public NavHelper<T> add(int menuId, Tab<T> tab) {
tabs.put(menuId, tab);
return this;
}
/**
* 执行点击菜单的操作
*
* @param menuId 菜单的Id
* @return 是否能够处理这个点击
*/
public boolean performClickMenu(int menuId) {
// 集合中寻找点击的菜单对应的Tab,
// 如果有则进行处理
Tab<T> tab = tabs.get(menuId);
if (tab != null) {
doSelect(tab);
return true;
}
return false;
}
/**
* 进行真实的Tab选择操作
*
* @param tab tab
*/
private void doSelect(Tab<T> tab) {
Tab<T> oldTab = null;
if (mCurrentTab != null) {
oldTab = mCurrentTab;
if (oldTab == tab) {
// 如果说当前的Tab就是点击的Tab,
// 那么我们不做处理
notifyTabReselect(tab);
return;
}
}
// 赋值并调用切换方法
mCurrentTab = tab;
doTabChanged(mCurrentTab, oldTab);
}
private void notifyTabReselect(Tab<T> tab) {
// TODO 二次点击Tab所做的操作
}
/**
* 进行Fragment的真实的调度操作
*
* @param newTab 新的
* @param oldTab 旧的
*/
private void doTabChanged(Tab<T> newTab, Tab<T> oldTab) {
FragmentTransaction ft = mFragmentManager.beginTransaction();
if (oldTab != null) {
if (oldTab.fragment != null) {
// 从界面移除,但是还在Fragment的缓存空间中
ft.detach(oldTab.fragment);
}
}
if (newTab != null) {
if (newTab.fragment == null) {
//首次新建
Fragment fragment = Fragment.instantiate(mContext, newTab.clx.getName());
// 缓存起来
newTab.fragment = fragment;
// 提交到FragmentManger
ft.add(mContainerId, fragment, newTab.clx.getName());
} else {
// 从FragmentManger的缓存空间中重新加载到界面中
ft.attach(newTab.fragment);
}
}
// 提交事务
ft.commit();
//通知回调
notifyTabSelect(newTab, oldTab);
}
/**
* 回调我们的监听器
*
* @param newTab 新的Tab<T>
* @param oldTab 旧的Tab<T>
*/
private void notifyTabSelect(Tab<T> newTab, Tab<T> oldTab) {
if (mListener != null) {
mListener.onTabChanged(newTab, oldTab);
}
}
/**
* 获取当前的显示的Tab
*
* @return 当前的Tab
*/
public Tab<T> getCurrentTab() {
return mCurrentTab;
}
/**
* 定义事件处理完成后的回调接口
*
* @param <T>
*/
public interface OnTabChangedListener<T> {
/**
* 回调接口
*
* @param newTab newTab
* @param oldTab oldTab
*/
void onTabChanged(Tab<T> newTab, Tab<T> oldTab);
}
/**
* 所有的Tab基础属性
*
* @param <T> 泛型的额外参数
*/
public static class Tab<T> {
/**
* Fragment所对应的class值
*/
public Class<?> clx;
/**
* 额外的字段,用户自己设定需要使用
*/
public T extra;
/**
* 内部缓存的对应的Fragment,Package权限,外部无法使用
*/
Fragment fragment;
public Tab(Class<?> clx, T extra) {
this.clx = clx;
this.extra = extra;
}
}
}
6、在Activity中的使用
public class MainActivity extends BaseActivity implements BottomNavigationView.OnNavigationItemSelectedListener,
NavHelper.OnTabChangedListener<Integer> {
private BottomNavigationView mNavigation;
private FragmentManager mFragmentManager;
private long pressTime = 0;
private NavHelper<Integer> mNavHelper;
@Override
protected int setLayoutId() {
return R.layout.activity_main;
}
@Override
protected void onBindView(Bundle savedInstanceState) {
initView();
}
private void initView() {
mNavigation = findViewById(R.id.navigation);
mFragmentManager = getSupportFragmentManager();
mNavHelper = new NavHelper<>(this, R.id.bottom_nav_bar_content,
mFragmentManager, this);
mNavHelper.add(R.id.nav_bar_home, new NavHelper.Tab<Integer>(HomeFragment.class, R.string.nav_bar_home))
.add(R.id.nav_bar_score, new NavHelper.Tab<Integer>(IntegralMallFragment.class, R.string.nav_bar_home))
.add(R.id.nav_bar_user, new NavHelper.Tab<Integer>(PersonalCenterFragment.class, R.string.nav_bar_home));
// 添加对底部按钮点击的监听
mNavigation.setOnNavigationItemSelectedListener(this);
// 从底部导中接管我们的Menu,然后进行手动的触发第一次点击
Menu menu = mNavigation.getMenu();
// 触发首次选中Home
menu.performIdentifierAction(R.id.nav_bar_home, 0);
}
@Override
public void onBackPressed() {
if (System.currentTimeMillis() - pressTime > 2000) {
pressTime = System.currentTimeMillis();
ToastUtils.showShort("再按一次退出程序");
} else {
AppActivityManager.getInstance().exitApp(this);
}
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
// 转接事件流到工具类中
return mNavHelper.performClickMenu(menuItem.getItemId());
}
/**
* NavHelper 处理后回调的方法
*
* @param newTab 新的Tab
* @param oldTab 就的Tab
*/
@Override
public void onTabChanged(NavHelper.Tab newTab, NavHelper.Tab oldTab) {
}
}
网友评论