Android Design Library之二: BottomNavigationView

来源:互联网 发布:北京java开发工程师 编辑:程序博客网 时间:2024/05/21 22:55

BottomNavitagionView出现之前,我们首先底部的导航栏大多是使用RadioGroup+RadioButton的特性来实现。现在官方为我们提供了另外的一条路。先来尝试下。

Demo

打开官方文档里面就有示例程序,比着敲一遍,看下效果。

 <android.support.design.widget.BottomNavigationView        android:layout_width="match_parent"        android:layout_height="55dp"        android:layout_alignParentBottom="true"        android:layout_gravity="center"        android:gravity="center"        app:itemIconTint="#009877"        app:itemTextColor="#009877"        app:paddingStart="10dp"        app:paddingEnd="10dp"        app:itemBackground="@color/white"        app:menu="@menu/bottom_nav"/>
<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:app="http://schemas.android.com/apk/res-auto">    <item        android:id="@+id/menu_nav_android"        android:icon="@drawable/ic_android_black_36dp"        app:showAsAction="ifRoom"        android:title="Android"/>    <item        android:id="@+id/menu_nav_lock"        android:icon="@drawable/ic_lock_black_36dp"        app:showAsAction="ifRoom"        android:title="Lock"/>    <item        android:id="@+id/menu_nav_group_work"        android:icon="@drawable/ic_group_work_black_36dp"        app:showAsAction="ifRoom"        android:title="Work"/></menu>

效果如下

嗯。效果还是不错的。但是有时候我们需要的是颜色的变化,这个时候我们需要一个color。在res下的color文件夹下创建一个文件名为bottom_nav的文件内容如下。

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

之后为BottomNavitagionView设置上就可以了。
效果如下

        app:itemIconTint="@color/bottom_nav"        app:itemTextColor="@color/bottom_nav"

问题

真的就这么就完了么? too young,too simple。我们底部的菜单项肯定不一定是3个。如果是4个。我们试一下,再加菜单项。很简单为menu再添加个item。来看下效果:

WTF

来看下源码看看到底发生了什么?
BottomNavigationView的源码

    private final MenuBuilder mMenu;    private final BottomNavigationMenuView mMenuView;    private final BottomNavigationPresenter mPresenter = new BottomNavigationPresenter();    private MenuInflater mMenuInflater;    //.....省略代码    public void inflateMenu(int resId) {        mPresenter.setUpdateSuspended(true);        getMenuInflater().inflate(resId, mMenu);        mPresenter.setUpdateSuspended(false);        mPresenter.updateMenuView(true);    }

我们看到。其中主要有这几个属性,通过查看代码我们可以看到。BottomNavigationPresenter来连接MenuBottomNavigationMenuView的。
BottomNavigationPresenter的部分代码

    private MenuBuilder mMenu;    private BottomNavigationMenuView mMenuView;        @Override    public void initForMenu(Context context, MenuBuilder menu) {        mMenuView.initialize(mMenu);        mMenu = menu;    }    ....省略...    @Override    public void updateMenuView(boolean cleared) {        if (mUpdateSuspended) return;        if (cleared) {            mMenuView.buildMenuView();        } else {            mMenuView.updateMenuView();        }    }

我们可以看到。更新MenuView的方法是通过Presenter来调用的。其内部的代码

  public void buildMenuView() {        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);        }        mActiveButton = Math.min(mMenu.size() - 1, mActiveButton);        mMenu.getItem(mActiveButton).setChecked(true);    }

这里我们应该就看出来端倪了。mShiftingMode是个boolean值,当menu的长度大于三时,就为true。也就为每一个BottomNavigationItemView 设置上了child.setShiftingMode(mShiftingMode); true。在这里每一个BottomNavigationItemView就是一个tab
BottomNavigationItemView的代码中我们可以看到。其填充的布局为R.layout.design_bottom_navigation_item布局中有两个TextView(smallLabel和largeLabel) 和一个ImageView(icon),详细的代码自己搜一下吧。在design包中,这里就不贴出来了。

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

啊哈。看了这么多终于找到原因了。 这就是问题所在。我们见到如果我们吧mShiftingMode设置为false那么就不会出现那种效果。怎么设置呢。我们可以使用反射的机制来进行设置。
代码如下

 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);                item.setShiftingMode(false);                item.setChecked(item.getItemData().isChecked());            }        } catch (NoSuchFieldException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }    }

http://blog.magicer.xyz/2017/06/android-design-library-bottomnavigationview/

阅读全文
0 0
原创粉丝点击