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.通常 ...
随机推荐
- REDIS 缓存的穿透,雪崩和热点key
穿透 穿透:频繁查询一个不存在的数据,由于缓存不命中,每次都要查询持久层.从而失去缓存的意义. 解决办法:①用一个bitmap和n个hash函数做布隆过滤器过滤没有在缓存的键. ②持久层查询不到就 ...
- 解决提交按钮在IE浏览器正常在360浏览器不可用
用meta标签指定使用哪个浏览器内核解析网页.在页面头部head标签里加上下面的代码即可:<meta name="renderer" content="webkit ...
- Spark记录-Scala数组
Scala提供了一种数据结构叫作数组,数组是一种存储了相同类型元素的固定大小顺序集合.数组用于存储数据集合,但将数组视为相同类型变量的集合通常更为有用. 可以声明一个数组变量,例如:numbers,使 ...
- SOCKET中send和recv函数工作原理与注意点
https://blog.csdn.net/rankun1/article/details/50488989
- zookeeper笔记之基于zk实现分布式锁
一.分布式锁概述 Java中基于AQS框架提供了一系列的锁,但是当需要在集群中的多台机器上互斥执行一段代码或使用资源时Java提供的这种单机锁就没了用武之地,此时需要使用分布式锁协调它们.分布式锁有很 ...
- mybatis一对一关联查询——(八)
1.需求 查询所有订单信息,关联查询下单用户信息. 注意: 因为一个订单信息只会是一个人下的订单,所以从查询订单信息出发关联查询用户信息为一对一查询.如果从用户信息出发查询用户下的订单信息则为一对多查 ...
- 从TFS 删除工作项
一.进入命令执行窗口的方式 1.若你的TFS服务器上安装了VS开发工作,可以按以下步骤,进入命令行方式,图如下: 2.若你TFS上没有安装VS开发工作,可以从你的开发机器上的VS安装目录下(一般情况下 ...
- [原创]jQuery Validation范例
上班无事,学习jQuery Validation,于是手写一公共范例,并收藏以便后用 验证操作类formValidatorClass.js }); 测试页index.html * {} ...
- 小白学习安全测试(一)——Http协议基础
Http协议基础 Web技术发展[http://www.cnblogs.com/ProgrammerGE/articles/1824657.html] 静态WEB[网页] 动态WEB 属于一种应用程序 ...
- NFS基础配置
需要安装的包: rpc-bind nfs-utils 修改配置文件 /etc/exports 配置 /tmp *(ro) 修改配置之后记得重启服务 sudo systemctl restart nfs ...