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的更多相关文章

  1. Android Design Support Library——Navigation View

    前沿 Android 从5.0开始引入了Material design元素的设计,这种新的设计语言让整个安卓的用户体验焕然一新,google在Android Design Support Librar ...

  2. Material Design学习之 Bottom navigation

    转载请注明出处:王亟亟的大牛之路 礼拜4一天由于事假没有去单位然后礼拜3由于生日也没写文章,今天一早上班就补一篇MD的内容.这一篇是关于颇有争议的Bottom navigation相关内容(主要是翻译 ...

  3. Android界面的View以及ViewGroup的区别

    因为这个问题会经常成为面试的热点,所以我们来谈谈View以及ViewGroup的区别. 先看看View及ViewGroup类关系    Android View和ViewGroup从组成架构上看,似乎 ...

  4. Android 自己定义View (二) 进阶

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24300125 继续自己定义View之旅.前面已经介绍过一个自己定义View的基础 ...

  5. Android面试,View绘制流程以及invalidate()等相关方法分析

    整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简单概况为 根据之前设置的状态,判断是否需要重新计算视图大小(measu ...

  6. 详解实现Android中实现View滑动的几种方式

    注: 本文提到的所有三种滑动方式的完整demo:ScrollDemo 1. 关于View我们需要知道的 (1)什么是View? Android中的View类是所有UI控件的基类(Base class) ...

  7. Android开发 navigation入门详解

    前言 Google 在2018年推出了 Android Jetpack,在Jetpack里有一种管理fragment的新架构模式,那就是navigation. 字面意思是导航,但是除了做APP引导页面 ...

  8. Android 判断一个 View 是否可见 getLocalVisibleRect(rect) 与 getGlobalVisibleRect(rect)

    Android 判断一个 View 是否可见 getLocalVisibleRect(rect) 与 getGlobalVisibleRect(rect) [TOC] 这两个方法的区别 View.ge ...

  9. 1.Android 视图及View绘制分析笔记之setContentView

    自从1983年第一台图形用户界面的个人电脑问世以来,几乎所有的PC操作系统都支持可视化操作,Android也不例外.对于所有Android Developer来说,我们接触最多的控件就是View.通常 ...

随机推荐

  1. Hadoop生态圈-Kafka的本地模式部署

    Hadoop生态圈-Kafka的本地模式部署 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Kafka简介 1>.什么是JMS 答:在Java中有一个角消息系统的东西,我 ...

  2. jQuery总结或者锋利的jQuery笔记一

      在线测试脚本网站 层次 选择器要多花时间看看. 第一章: hover = enter+leave jQuery对象 jQuery产生的对象时jQuery独有的,只能自己调用 var $c=$(&q ...

  3. mybatis 不整合spring 入门小例子

    先上一个搭建完的项目结构截图: 相对比较重要的配置文件有 db.properties , SqlMappingConfig.xml , mapper/User.xml , log4j.properti ...

  4. Docker CE的安装 与镜像加速

    Docker CE 的安装与镜像加速 Docker CE是docker的开源版本 CENTOS 安装Docker CE 系统要求: 操作系统需要使用centos7() centos-extras库 必 ...

  5. js截取图片上传(仅原理)----闲的无聊了代码就不共享了!写的难看,不好意思给你们看了(囧)

    就算世界再坑爹,总有一些属性能带你走出绝望(伟大的absolute) 今天吐槽一下!......在我的世界里没有正统UI,所以效果图永远都是那么坑爹! 这里我要感谢有个position:absolut ...

  6. iOS 6 & iOS 7 的适配笔记

    iOS 6 & iOS 7 的适配 场景1: 没有NavigationController,同时根视图是UIView- (void)viewWillLayoutSubviews{ if ([[ ...

  7. laravel一个页面两个表格分页处理

    关键是看懂laravel自带的 paginate() 方法. 在Builder.php文件(项目名称/laravel/vendor/laravel/framework/src/Illuminate/D ...

  8. 第9月第5天 AVVideoAverageBitRateKey

    1. https://stackoverflow.com/questions/11751883/how-can-i-reduce-the-file-size-of-a-video-created-wi ...

  9. TensorFlow 从零到helloWorld

    目录 1.git安装与使用 1.1 git安装 1.2 修改git bash默认路径 1.3 git常用操作 2.环境搭建   2.1 tensorflow安装   2.2 CUDA安装   2.3 ...

  10. 【Python】Flask系列-数据库笔记

    MySQL-python中间件的介绍与安装: 1.如果是在类unix系统上,直接进入虚拟环境,输入sudo pip install mysql-python. 2.如果是在windows系统上,那么在 ...