Android官方BottomNavigationView添加Badge(角标)

Google在Android API24添加了实现底部导航的BottomNavigationView,还算是比较良心的,相信做过类似功能的老铁对开源的BottomNavigationBar一定不会感到陌生,这个开源项目很好的实现了我们所需要的功能,包括我今天重点要说的添加角标Badge,它添加Badge的方式是在创建底部导航按钮的时候就设置了Badge:

    bottomNavigationBar
.addItem(new BottomNavigationItem(R.drawable.ic_error, "主页").setBadgeItem(faultBadgeItem))
.addItem(new BottomNavigationItem(R.drawable.ic_assignment, "通知").setBadgeItem(maintainBadgeItem))
.addItem(new BottomNavigationItem(R.drawable.ic_notifications, "消息").setBadgeItem(announcementBadgeItem))
.addItem(new BottomNavigationItem(R.drawable.ic_forum, "我的").setBadgeItem(imBadgeItem))
.initialise();

但是API24的BottomNavigationView是通过Menu的形式创建的,我们无法在它创建的时候就设置Badge,必须获取到每一个导航按钮Item所在的View,才能够添加上去。当然方法不是绝对的,之前看过看到一篇文章是通过在顶级容器上加入小红点,调整位置,伪装成和控件一体的方式实现,我还是觉得太过复杂,然后就看了一下BottomNavigationView的源码还是有所发现。

1.由于是通过Menu的方式创建,所以要把得到的MenuView添加进去,在构造方法中发现:

public BottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);

    ThemeUtils.checkAppCompatTheme(context);

    // Create the menu
    mMenu = new BottomNavigationMenu(context);

    mMenuView = new BottomNavigationMenuView(context);
    FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    params.gravity = Gravity.CENTER;
    mMenuView.setLayoutParams(params);

    mPresenter.setBottomNavigationMenuView(mMenuView);
    mPresenter.setId(MENU_PRESENTER_ID);
    mMenuView.setPresenter(mPresenter);
    mMenu.addMenuPresenter(mPresenter);
    mPresenter.initForMenu(getContext(), mMenu);

    // Custom attributes
    TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
            R.styleable.BottomNavigationView, defStyleAttr,
            R.style.Widget_Design_BottomNavigationView);

    if (a.hasValue(R.styleable.BottomNavigationView_itemIconTint)) {
        mMenuView.setIconTintList(
                a.getColorStateList(R.styleable.BottomNavigationView_itemIconTint));
    } else {
        mMenuView.setIconTintList(
                createDefaultColorStateList(android.R.attr.textColorSecondary));
    }
    if (a.hasValue(R.styleable.BottomNavigationView_itemTextColor)) {
        mMenuView.setItemTextColor(
                a.getColorStateList(R.styleable.BottomNavigationView_itemTextColor));
    } else {
        mMenuView.setItemTextColor(
                createDefaultColorStateList(android.R.attr.textColorSecondary));
    }
    if (a.hasValue(R.styleable.BottomNavigationView_elevation)) {
        ViewCompat.setElevation(this, a.getDimensionPixelSize(
                R.styleable.BottomNavigationView_elevation, 0));
    }

    int itemBackground = a.getResourceId(R.styleable.BottomNavigationView_itemBackground, 0);
    mMenuView.setItemBackgroundRes(itemBackground);

    if (a.hasValue(R.styleable.BottomNavigationView_menu)) {
        inflateMenu(a.getResourceId(R.styleable.BottomNavigationView_menu, 0));
    }
    a.recycle();

    addView(mMenuView, params);
    if (Build.VERSION.SDK_INT < 21) {
        addCompatibilityTopDivider(context);
    }

    mMenu.setCallback(new MenuBuilder.Callback() {
        @Override
        public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
            if (mReselectedListener != null && item.getItemId() == getSelectedItemId()) {
                mReselectedListener.onNavigationItemReselected(item);
                return true; // item is already selected
            }
            return mSelectedListener != null
                    && !mSelectedListener.onNavigationItemSelected(item);
        }

        @Override
        public void onMenuModeChange(MenuBuilder menu) {}
    });
}

上边有两句关键代码:mMenuView = new BottomNavigationMenuView(context); addView(mMenuView, params);因而我们可以获取到BottomNavigationView的子View,类型为BottomNavigationMenuView:

BottomNavigationMenuView menuView = (BottomNavigationMenuView) navigation.getChildAt(0);

2.拿到BottomNavigationMenuView,我基本就确定了底部导航的几个按钮就是它的子VIew,不放心,再看BottomNavigationMenuView的源码,看了OnLayout就100%确定了,so我们可以拿到每个导航按钮所在的View了:

View view1 = menuView.getChildAt(0);
View view1 = menuView.getChildAt(0);
View view1 = menuView.getChildAt(0);
...

拿到各个ItemView就So easy了,那不就是在它上边添加文字嘛:

BottomNavigationMenuView menuView = (BottomNavigationMenuView) bottomNavigationView.getChildAt(0);

BadgeView.Builder.newBuilder()
    .setTargetView(menuView.getChildAt(0))
    .setBadgeCount(10)
    .setMargin(new Integer[]{0, 8, 24, 0})
    .build(this);

BadgeView.Builder.newBuilder()
    .setTargetView(menuView.getChildAt(1))
    .setBadgeCount(2)
    .setMargin(new Integer[]{0, 8, 24, 0})
    .build(this);

BadgeView.Builder.newBuilder()
    .setTargetView(menuView.getChildAt(2))
    .setBadgeCount(8)
    .setMargin(new Integer[]{0, 8, 24, 0})
    .build(this);

代码比较简单,就不上了,最后贴个图

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章