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

代碼比較簡單,就不上了,最後貼個圖

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