• Android


    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();
        }
    }
    

    在初始化控件后调用此方法就可以达到我们想要的效果

  • 相关阅读:
    SVG ViewBox
    svg中改变class调用的线条颜色
    SVG 箭头线绘制
    Spring3中的mvc:interceptors标签配置拦截器
    MyBatis入门学习
    MyBatis 配置sql语句输出
    使用iBATIS3.0完成增删改查
    iBatis简单入门教程
    SpringMVC常用注解,返回方式,路径匹配形式,验证
    springMVC 返回类型选择 以及 SpringMVC中model,modelMap.request,session取值顺序
  • 原文地址:https://www.cnblogs.com/slyfox/p/8334471.html
Copyright © 2020-2023  润新知