Android - Bottom Navigation View
Android - Bottom Navigation View
Overview
一直以来,关于Android的底部导航的功能实现的方法一直是各行其道不成规范,使用各种方法的都有
- RadioButton
- TextView
- ...
在Material Design 中推出了这样的一个控件来解决底部导航栏的不统一的问题,但是这个控件有一点点的问题...
问题所在
现在的效果非常棒...

结果一旦Item的数量超过了3个,就会有一个非常鬼畜的动画效果,让人无法接受。

如何使用
在menu目录下新建一个menu菜单,这个菜单将会用于生成BottomNavigationView控件的item
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/navItem_UI"
android:icon="@drawable/ui"
android:title="UI" />
<item
android:id="@+id/navItem_data"
android:icon="@drawable/data"
android:title="Data" />
<item
android:id="@+id/navItem_API"
android:icon="@drawable/api"
android:title="API" />
</menu>
xml 布局文件
<android.support.design.widget.BottomNavigationView
android:id="@+id/nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#f6f6f6"
app:itemTextColor="@color/colorPrimary"
app:itemIconTint="@color/colorPrimary"
app:menu="@menu/nav_menu"/>
主要属性
- itemTextColor 字体的颜色
- itemIconTint 图标的颜色
- menu 绑定的菜单
处理事件
void registerEvent() {
//设置Item的点击事件
navView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
CommonUtil.toast(item.getTitle().toString());
return true;
}
});
}
干掉那个浮夸的动画
效果图

一直以为Google会提供相应的方法,但是找了半天都没找到,但是我们有源码啊,只要溜进去控件的内部,看一看是怎么回事了。
/**
在源码中,返现,这个控件是基于MVP架构的,去MVP架构的View中找
*/
private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
private static final int[] DISABLED_STATE_SET = {-android.R.attr.state_enabled};
private static final int MENU_PRESENTER_ID = 1;
private final MenuBuilder mMenu;
//这个字段是MVP架构中的View,点进去他的源码中寻找
private final BottomNavigationMenuView mMenuView;
private final BottomNavigationPresenter mPresenter = new BottomNavigationPresenter();
private MenuInflater mMenuInflater;
private OnNavigationItemSelectedListener mSelectedListener;
private OnNavigationItemReselectedListener mReselectedListener;
进入BottomNavigationView中继续寻找
@RestrictTo(LIBRARY_GROUP)
public class BottomNavigationMenuView extends ViewGroup implements MenuView {
private static final long ACTIVE_ANIMATION_DURATION_MS = 115L;
private final TransitionSet mSet;
private final int mInactiveItemMaxWidth;
private final int mInactiveItemMinWidth;
private final int mActiveItemMaxWidth;
private final int mItemHeight;
private final OnClickListener mOnClickListener;
private final Pools.Pool<BottomNavigationItemView> mItemPool = new Pools.SynchronizedPool<>(5);
//找到了一个比较可疑的字段, shifting 有道翻译一下-> 位移 关闭动画应该就是这个了
//这个字段是关闭的控件的位移动画
private boolean mShiftingMode = true;
//这个是BottomNavigationMenuView 中的各个item,进入继续找
private BottomNavigationItemView[] mButtons;
private int mSelectedItemId = 0;
private int mSelectedItemPosition = 0;
private ColorStateList mItemIconTint;
private ColorStateList mItemTextColor;
private int mItemBackgroundRes;
private int[] mTempChildWidths;
private BottomNavigationPresenter mPresenter;
private MenuBuilder mMenu;
进入到BottomNavigationMenuView 中继续寻找
@RestrictTo(LIBRARY_GROUP)
public class BottomNavigationItemView extends FrameLayout implements MenuView.ItemView {
public static final int INVALID_ITEM_POSITION = -1;
private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };
private final int mDefaultMargin;
private final int mShiftAmount;
private final float mScaleUpFactor;
private final float mScaleDownFactor;
//这里还有一个动画效果的设置, 不过这个有方法来供我们设置,不同通过反射来设置了
//这个字段标识的是,图标上移的动画,如果不关闭这个动画,那么如果ItemNavigationView的Item超过了3个那么
//只有选中了的Item才会显示文字,而其他的不显示文字
private boolean mShiftingMode;
private ImageView mIcon;
private final TextView mSmallLabel;
private final TextView mLargeLabel;
private int mItemPosition = INVALID_ITEM_POSITION;
private MenuItemImpl mItemData;
private ColorStateList mIconTint;
找到了标志属性,那就该我们的反射出场了了
void initNav() {
try {
//在这里为什么使用getChildAt(0),的线索可以在BottomNavigationMenuView的构造方法中找到线索
BottomNavigationMenuView menuView = (BottomNavigationMenuView) navView.getChildAt(0);
Field field = menuView.getClass().getDeclaredField("mShiftingMode");
//取消位移动画
field.setAccessible(true);
field.setBoolean(menuView, false);
//遍历所有的Item取消上移动画
for (int i = 0; i < navView.getChildCount(); i++) {
//这里为什么调用的是getChildAt(i); 可以在BottomNavigationMenuView的buildMenuView方法中找到线索
BottomNavigationItemView itemView = (BottomNavigationItemView) menuView.getChildAt(i);
itemView.setShiftingMode(false);
}
////更新一下MenuView,如果不加这句代码,初始化的是时候会一个显示样式的小bug出现
menuView.updateMenuView();
} catch (Exception e) {
e.printStackTrace();
}
}
在初始化控件后调用此方法就可以达到我们想要的效果
Android - Bottom Navigation View的更多相关文章
- Android Design Support Library——Navigation View
前沿 Android 从5.0开始引入了Material design元素的设计,这种新的设计语言让整个安卓的用户体验焕然一新,google在Android Design Support Librar ...
- Material Design学习之 Bottom navigation
转载请注明出处:王亟亟的大牛之路 礼拜4一天由于事假没有去单位然后礼拜3由于生日也没写文章,今天一早上班就补一篇MD的内容.这一篇是关于颇有争议的Bottom navigation相关内容(主要是翻译 ...
- Android界面的View以及ViewGroup的区别
因为这个问题会经常成为面试的热点,所以我们来谈谈View以及ViewGroup的区别. 先看看View及ViewGroup类关系 Android View和ViewGroup从组成架构上看,似乎 ...
- Android 自己定义View (二) 进阶
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24300125 继续自己定义View之旅.前面已经介绍过一个自己定义View的基础 ...
- Android面试,View绘制流程以及invalidate()等相关方法分析
整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简单概况为 根据之前设置的状态,判断是否需要重新计算视图大小(measu ...
- 详解实现Android中实现View滑动的几种方式
注: 本文提到的所有三种滑动方式的完整demo:ScrollDemo 1. 关于View我们需要知道的 (1)什么是View? Android中的View类是所有UI控件的基类(Base class) ...
- Android开发 navigation入门详解
前言 Google 在2018年推出了 Android Jetpack,在Jetpack里有一种管理fragment的新架构模式,那就是navigation. 字面意思是导航,但是除了做APP引导页面 ...
- Android 判断一个 View 是否可见 getLocalVisibleRect(rect) 与 getGlobalVisibleRect(rect)
Android 判断一个 View 是否可见 getLocalVisibleRect(rect) 与 getGlobalVisibleRect(rect) [TOC] 这两个方法的区别 View.ge ...
- 1.Android 视图及View绘制分析笔记之setContentView
自从1983年第一台图形用户界面的个人电脑问世以来,几乎所有的PC操作系统都支持可视化操作,Android也不例外.对于所有Android Developer来说,我们接触最多的控件就是View.通常 ...
随机推荐
- Hadoop生态圈-Kafka的本地模式部署
Hadoop生态圈-Kafka的本地模式部署 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Kafka简介 1>.什么是JMS 答:在Java中有一个角消息系统的东西,我 ...
- jQuery总结或者锋利的jQuery笔记一
在线测试脚本网站 层次 选择器要多花时间看看. 第一章: hover = enter+leave jQuery对象 jQuery产生的对象时jQuery独有的,只能自己调用 var $c=$(&q ...
- mybatis 不整合spring 入门小例子
先上一个搭建完的项目结构截图: 相对比较重要的配置文件有 db.properties , SqlMappingConfig.xml , mapper/User.xml , log4j.properti ...
- Docker CE的安装 与镜像加速
Docker CE 的安装与镜像加速 Docker CE是docker的开源版本 CENTOS 安装Docker CE 系统要求: 操作系统需要使用centos7() centos-extras库 必 ...
- js截取图片上传(仅原理)----闲的无聊了代码就不共享了!写的难看,不好意思给你们看了(囧)
就算世界再坑爹,总有一些属性能带你走出绝望(伟大的absolute) 今天吐槽一下!......在我的世界里没有正统UI,所以效果图永远都是那么坑爹! 这里我要感谢有个position:absolut ...
- iOS 6 & iOS 7 的适配笔记
iOS 6 & iOS 7 的适配 场景1: 没有NavigationController,同时根视图是UIView- (void)viewWillLayoutSubviews{ if ([[ ...
- laravel一个页面两个表格分页处理
关键是看懂laravel自带的 paginate() 方法. 在Builder.php文件(项目名称/laravel/vendor/laravel/framework/src/Illuminate/D ...
- 第9月第5天 AVVideoAverageBitRateKey
1. https://stackoverflow.com/questions/11751883/how-can-i-reduce-the-file-size-of-a-video-created-wi ...
- TensorFlow 从零到helloWorld
目录 1.git安装与使用 1.1 git安装 1.2 修改git bash默认路径 1.3 git常用操作 2.环境搭建 2.1 tensorflow安装 2.2 CUDA安装 2.3 ...
- 【Python】Flask系列-数据库笔记
MySQL-python中间件的介绍与安装: 1.如果是在类unix系统上,直接进入虚拟环境,输入sudo pip install mysql-python. 2.如果是在windows系统上,那么在 ...