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. windows服务写完之后怎么让它跑起来

    当然你可以在命令框里面自己去手动的敲代码,也可以写一个.bat文件一劳永逸......这里我就介绍写.bat文件的方法 就是上图所示的三个东东啦,有了这三个东东,把他们拖到你windows服务的deb ...

  2. vue npm start 自动打开网页

    打开config/index.js,设置: autoOpenBrowser: true,(默认是false,把false改为true即可)

  3. 蓝桥杯 算法训练 单词接龙 _DFS_搜索 字符串比较

    单词接龙 问题描述  单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相 ...

  4. html5 canvas文本处理

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. html5 canvas 径向渐变

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. CentOS配置源

    一.源列表 aliyun源 #各系统版本repo文件对应的下载操作 CentOS wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.al ...

  7. 利用itertools生成密码字典,多线程撞库破解rar压缩文件密码

    脚本功能: 利用itertools生成密码字典(迭代器形式) 多线程并发从密码字典中取出密码进行验证 验证成功后把密码写入文件中保存 #!/usr/bin/env python # -*- codin ...

  8. OpenLayers 3 之 地图图层数据来源(ol.source)详解

    原文地址 source 是 Layer 的重要组成部分,表示图层的来源,也就是服务地址.除了在构造函数中制定外,可以使用 layer.setSource(source) 稍后指定.一.包含的类型 ol ...

  9. (maven项目)使用java -jar命令遇到的小问题|xx.jar中没有主清单或Error:Invalid or corrupt jarfile xx.jar

    xx.jar中没有主清单或Error:Invalid or corrupt jarfile xx.jar 遇到这个问题,是因为你的jar包没有设置主类的入口. 即在META-INF文件夹的MANIFE ...

  10. JavaScript:document.execCommand()的用法

    document.execCommand()的用法小记 一.语法 execCommand方法是执行一个对当前文档,当前选择或者给出范围的命令.处理Html数据时常用. 如下格式:document.ex ...