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. Tomcat权威指南-读书摘要系列9

    从源代码组建Tomcat 安装Apache Ant ant是make的开放源代码的替代品,而且是专门为java程序语言设计. Ant的最初用途是作为Tomcat的组建工具: 之后,Ant成为Java软 ...

  2. 流媒体技术学习笔记之(六)FFmpeg官方文档先进音频编码(AAC)

    先进音频编码(AAC)的后继格式到MP3,和以MPEG-4部分3(ISO / IEC 14496-3)被定义.它通常用于MP4容器格式; 对于音乐,通常使用.m4a扩展名.第二最常见的用途是在MKV( ...

  3. PHP魔术方法之__invoke()

    将对象当作函数来使用时,会自动调用该方法. class ShowProfile extends Controller { public function __invoke($id) { return ...

  4. 原生JS不到30行,实现类似javascript MVC的功能-minTemplate

    严格来讲不能说是MVC,应为模版里不能写逻辑语句. 灵感来源于我的上篇文字:<封装JSON数据转自定义HTML方法parseHTML>: 这里再封装一个简单方法,在保持原来的方便改变不大的 ...

  5. 图的最短路径-----------Dijkstra算法详解(TjuOj2870_The Kth City)

    做OJ需要用到搜索最短路径的题,于是整理了一下关于图的搜索算法: 图的搜索大致有三种比较常用的算法: 迪杰斯特拉算法(Dijkstra算法) 弗洛伊德算法(Floyd算法) SPFA算法 Dijkst ...

  6. django+mysql安装和设置

    之前我们已经用sqlite建立了第一个web app.今天来学习如何在django中使用MySQL. 首先需要安装MySQL,到官网下载安装包:https://dev.mysql.com/downlo ...

  7. Hive笔记之严格模式(strict mode)

    Hive有一个严格模式,在严格模式下会对可能产生较大查询结果的语句做限制,禁止其提交执行. 一.切换严格模式 查看当前的模式: hive> set hive.mapred.mode; hive. ...

  8. 安装odbc驱动

    1.下载对应的驱动 (32位/64位) http://www.oracle.com/technetwork/database/database-technologies/instant-client/ ...

  9. oracle行转列

    wm_concat()函数 --创建表 create table test(id number,name varchar2(20)); --插入数据 insert into test values(1 ...

  10. VUE之搭建脚手架

    原文转自http://blog.csdn.net/Shiyaru1314/article/details/54963027 目录(?)[-] 1 安装之前需要检查是否已经安装NodeJS的环境 安装文 ...