MaterialDesign4AppAndroid UIMaterial Design

Android Design Support Library系列

2017-05-22  本文已影响627人  滴滴滴9527

底部导航栏的使用非常广泛,在Android Design Support Library25,google推出了Android的底部导航栏------BottomNavigationView.

BottomNavigationView指南
BottomNavigationView官方文档

一、BottomNavigationView简单使用

使用前添加依赖

compile 'com.android.support:design:25.3.1'

布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/bottom_navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"

        app:menu="@menu/bottom_navigation"> 

    </android.support.design.widget.BottomNavigationView>
</RelativeLayout>

NavigationView的使用差不多,BottomNavigationView的内容部分定义在菜单文件夹下,然后通过 app:menu=" "属性引用该菜单文件即可。
res/menu/bottom_navigation.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/item_1"
        android:icon="@mipmap/p1"
        android:title="消息" />

    <item
        android:id="@+id/item_2"
        android:icon="@mipmap/p2"
        android:title="联系人" />

    <item
        android:id="@+id/item_3"
        android:icon="@mipmap/p3"
        android:title="动态" />

</menu>

效果图

二、BottomNavigationView的常用属性

1、图标颜色修改

上面三张是图标原图,而根据效果图可以发现:选中和未被选中时的颜色都是主题中的,并未使用图标本身颜色,我们可以通过下面这条属性修改图标颜色

app:itemIconTint=" "

(1)这里的图标颜色可以是单一的,选中未选中都是一个颜色,像这样:

 app:itemIconTint="@android:color/holo_blue_light"

(2)也可以给图标颜色添加一个选择器效果,像这样:

app:itemIconTint="@color/seletor_bottom_navi"

颜色选择器:res/color/seletor_bottom_navi.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@android:color/holo_blue_light" 
        android:state_checked="true" />
    <item android:color="@android:color/black" />
</selector>

(3)当然,你也可以恢复图标本身颜色,需要在代码中设置

mBottomNV = (BottomNavigationView) findViewById(R.id.bottom_navigation);
mBottomNV.setItemIconTintList(null);

(4)如果你想给图标也添加一个选择器效果,你可以在菜单文件中引用图片时引用一个seletor

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/item_1"
        android:icon="@drawable/seletor_item1"      
        android:title="消息" />

    <item
        android:id="@+id/item_2"
        android:icon="@mipmap/p2"
        android:title="联系人" />

    <item
        android:id="@+id/item_3"
        android:icon="@mipmap/p3"
        android:title="动态" />
</menu>

图片选择器:res/drawable/seletor_item1.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@mipmap/p1" android:state_checked="true"></item>
    <item android:drawable="@mipmap/p4" ></item>

</selector>
2、字体颜色修改

字体颜色默认也是使用系统主题中的,我们可以通过下面这条属性修改:

app:itemTextColor=" "

你可以使用单一的,也可以添加一个选择器效果

app:itemTextColor="@android:color/holo_blue_light"
app:itemTextColor="@color/seletor_bottom_navi"
3、背景颜色修改
app:itemBackground=""

当然,你也可以直接通过android:background=" "修改背景颜色

三、BottomNavigationView常用方法

设置图标颜色
setItemIconTintList()
设置字体颜色
setItemTextColor()
设置背景
setBackgroundColor()      需要一个颜色值
setItemBackgroundResource()   需要一个资源id,可以是颜色、图片、shape
setBackground()  需要一个drawable对象,minSdkVersion>=16才可以用
设置默认选中哪个item
setSelectedItemId()
设置监听
setOnNavigationItemSelectedListener()

        mBottomNV.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.item_1:
                     //do something
                        break;
                    case R.id.item_2:
                     //do something
                        break;
                    case R.id.item_3:
                     //do something
                        break;
                }
                return true;
            }
        });

四、BottomNavigationView使用规范

1)官方建议菜单item个数为 3~5 个
我尝试6个item,直接报错:


于是查看BottomNavigationView源码:
   public int getMaxItemCount() {
        return BottomNavigationMenu.MAX_ITEM_COUNT;
    }

追踪到BottomNavigationMenu:

 public static final int MAX_ITEM_COUNT = 5;

ok,完全了解了.
我又尝试2个,没有报错,不过2个的话还是不建议使用BottomNavigationView
2)底部导航栏高度建议是56dp
更多规范请查看官网BottomNavigationView指南

五、关于BottomNavigationView的ShiftingMode

(1)上面我们一直使用三个item,下面我们使用4个item试一试

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/item_1"
        android:icon="@mipmap/p1"
        android:title="消息" />

    <item
        android:id="@+id/item_2"
        android:icon="@mipmap/p2"
        android:title="联系人" />
    <item
        android:id="@+id/item_3"
        android:icon="@mipmap/p3"
        android:title="动态" />
    <item
        android:id="@+id/item_4"
        android:icon="@mipmap/p4"
        android:title="我的" />
</menu>

效果图


可以看见,当item数量为4个的时候,效果和之前完全不一样了。。。。。。
(2)查看源码,最终追踪到:
 public void buildMenuView() {
        removeAllViews();
        if (mButtons != null) {
            for (BottomNavigationItemView item : mButtons) {
                mItemPool.release(item);
            }
        }
        if (mMenu.size() == 0) {
            mSelectedItemId = 0;
            mSelectedItemPosition = 0;
            mButtons = null;
            return;
        }
        mButtons = new BottomNavigationItemView[mMenu.size()];
        mShiftingMode = mMenu.size() > 3;//❤❤❤❤❤
        for (int i = 0; i < mMenu.size(); i++) {
            mPresenter.setUpdateSuspended(true);
            mMenu.getItem(i).setCheckable(true);
            mPresenter.setUpdateSuspended(false);
            BottomNavigationItemView child = getNewItem();
            mButtons[i] = child;
            child.setIconTintList(mItemIconTint);
            child.setTextColor(mItemTextColor);
            child.setItemBackground(mItemBackgroundRes);
            child.setShiftingMode(mShiftingMode);//❤❤❤❤❤
            child.initialize((MenuItemImpl) mMenu.getItem(i), 0);
            child.setItemPosition(i);
            child.setOnClickListener(mOnClickListener);
            addView(child);
        }
        mSelectedItemPosition = Math.min(mMenu.size() - 1, mSelectedItemPosition);
        mMenu.getItem(mSelectedItemPosition).setChecked(true);
    }
 public void setShiftingMode(boolean enabled) {
        mShiftingMode = enabled;
 }
    public void setChecked(boolean checked) {
        ViewCompat.setPivotX(mLargeLabel, mLargeLabel.getWidth() / 2);
        ViewCompat.setPivotY(mLargeLabel, mLargeLabel.getBaseline());
        ViewCompat.setPivotX(mSmallLabel, mSmallLabel.getWidth() / 2);
        ViewCompat.setPivotY(mSmallLabel, mSmallLabel.getBaseline());
        if (mShiftingMode) {//❤❤❤❤❤
            if (checked) {
                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
                iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
                iconParams.topMargin = mDefaultMargin;
                mIcon.setLayoutParams(iconParams);
                mLargeLabel.setVisibility(VISIBLE);
                ViewCompat.setScaleX(mLargeLabel, 1f);
                ViewCompat.setScaleY(mLargeLabel, 1f);
            } else {
                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
                iconParams.gravity = Gravity.CENTER;
                iconParams.topMargin = mDefaultMargin;
                mIcon.setLayoutParams(iconParams);
                mLargeLabel.setVisibility(INVISIBLE);
                ViewCompat.setScaleX(mLargeLabel, 0.5f);
                ViewCompat.setScaleY(mLargeLabel, 0.5f);
            }
            mSmallLabel.setVisibility(INVISIBLE);
        } else {//❤❤❤❤❤
            if (checked) {
                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
                iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
                iconParams.topMargin = mDefaultMargin + mShiftAmount;
                mIcon.setLayoutParams(iconParams);
                mLargeLabel.setVisibility(VISIBLE);
                mSmallLabel.setVisibility(INVISIBLE);

                ViewCompat.setScaleX(mLargeLabel, 1f);
                ViewCompat.setScaleY(mLargeLabel, 1f);
                ViewCompat.setScaleX(mSmallLabel, mScaleUpFactor);
                ViewCompat.setScaleY(mSmallLabel, mScaleUpFactor);
            } else {
                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
                iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
                iconParams.topMargin = mDefaultMargin;
                mIcon.setLayoutParams(iconParams);
                mLargeLabel.setVisibility(INVISIBLE);
                mSmallLabel.setVisibility(VISIBLE);

                ViewCompat.setScaleX(mLargeLabel, mScaleDownFactor);
                ViewCompat.setScaleY(mLargeLabel, mScaleDownFactor);
                ViewCompat.setScaleX(mSmallLabel, 1f);
                ViewCompat.setScaleY(mSmallLabel, 1f);
            }
        }
        refreshDrawableState();
    }

好吧,item数量大于3的时候会开启ShiftingMode,效果和之前完全不一样了......
这种效果简直难以忍受,而且目前还没有一个属性或者方法能够修改ShiftingMode.

(3) 通过反射修改ShiftingMode
准备用反射来修改ShiftingMode值,结果发现stackoverflow上早已经有外国小哥写好了,直接copy就可以了~~~

/**
 * 新建一个BottomNavigationView帮助者类
 */
public class BottomNavigationViewHelper {
    public static void disableShiftMode(BottomNavigationView view) {
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
        try {
            Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
            shiftingMode.setAccessible(true);
            shiftingMode.setBoolean(menuView, false);
            shiftingMode.setAccessible(false);
            for (int i = 0; i < menuView.getChildCount(); i++) {
                BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
                //noinspection RestrictedApi
                item.setShiftingMode(false);
                // set once again checked value, so view will be updated
                //noinspection RestrictedApi
                item.setChecked(item.getItemData().isChecked());
            }
        } catch (NoSuchFieldException e) {
            Log.e("BNVHelper", "Unable to get shift mode field", e);
        } catch (IllegalAccessException e) {
            Log.e("BNVHelper", "Unable to change value of shift mode", e);
        }
    }
}

然后调用即可

BottomNavigationViewHelper.disableShiftMode(mBottomNV);

最后,你需要在混淆文件中配置

-keepclassmembers class android.support.design.internal.BottomNavigationMenuView { 
    boolean mShiftingMode; 
}

(4) 效果图


ok,完美解决
上一篇下一篇

猜你喜欢

热点阅读