Badge on BottomNavigationView

前端 未结 4 1211
隐瞒了意图╮
隐瞒了意图╮ 2020-12-02 02:03

I am trying to add a badge to the BottomNavigationView Item without using any library, however somehow the BottomNavigationView is not showing the

相关标签:
4条回答
  • 2020-12-02 02:17

    use the BadgeDrawable like this:

    Integer amount = tabBadgeCountMap.get(tab);
                BadgeDrawable badgeDrawable = bottomNavigationView.getOrCreateBadge(tabMenuResId);
                badgeDrawable.setNumber(amount != null ? amount : 0);
    
    0 讨论(0)
  • 2020-12-02 02:35

    I managed to make BottomNavigationView with the badge. Here is my code (Kotlin).

    This is the panel (inherited from BottomNavigationView)

    /** Bottom menu with badge */
    class AdvancedBottomNavigationView(context: Context, attrs: AttributeSet) : BottomNavigationView(context, attrs) {
    
        private companion object {
            const val BADGE_MIN_WIDTH = 16          // [dp]
            const val BADGE_MARGIN_TOP = 5          // [dp]
            const val BADGE_MARGIN_LEFT = 15        // [dp]
        }
    
        @Inject internal lateinit var uiCalculator: UICalculatorInterface
    
        private val bottomMenuView: BottomNavigationMenuView
    
        init {
            //  Get access to internal menu
            val field = BottomNavigationView::class.java.getDeclaredField("mMenuView")
            field.isAccessible = true
            bottomMenuView = field.get(this) as BottomNavigationMenuView
    
            App.injections.presentationLayerComponent!!.inject(this)
    
            @SuppressLint("CustomViewStyleable")
            val a = context.obtainStyledAttributes(attrs, R.styleable.advanced_bottom_navigation_bar)
            val badgeLayoutId  = a.getResourceId(R.styleable.advanced_bottom_navigation_bar_badge_layout, -1)
            a.recycle()
    
            initBadges(badgeLayoutId)
        }
    
        /**
         * [position] index of menu item */
        fun setBadgeValue(position: Int, count: Int) {
            val menuView = bottomMenuView
            val menuItem = menuView.getChildAt(position) as BottomNavigationItemView
    
            val badge = menuItem.findViewById(R.id.bottom_bar_badge)
            val badgeText = menuItem.findViewById(R.id.bottom_bar_badge_text) as TextView
    
            if (count > 0) {
                badgeText.text = count.toString()
                badge.visibility = View.VISIBLE
            } else {
                badge.visibility = View.GONE
            }
        }
    
        /**
         * Select menu item
         * [position] index of menu item to select
         */
        fun setSelected(position: Int) = bottomMenuView.getChildAt(position).performClick()
    
        private fun initBadges(badgeLayoutId: Int) {
            // Adding badges to each Item
            val menuView = bottomMenuView
            val totalItems = menuView.childCount
    
            val oneItemAreaWidth = uiCalculator.getScreenSize(context).first / totalItems
    
            val marginTop = uiCalculator.dpToPixels(context, BADGE_MARGIN_TOP)
            val marginLeft = uiCalculator.dpToPixels(context, BADGE_MARGIN_LEFT)
    
            for (i in 0 until totalItems) {
                val menuItem = menuView.getChildAt(i) as BottomNavigationItemView
    
                // Add badge to every item
                val badge = View.inflate(context, badgeLayoutId, null) as FrameLayout
                badge.visibility = View.GONE
                badge.minimumWidth = uiCalculator.dpToPixels(context, BADGE_MIN_WIDTH)
    
                val layoutParam = FrameLayout.LayoutParams(
                    FrameLayout.LayoutParams.WRAP_CONTENT,
                    FrameLayout.LayoutParams.WRAP_CONTENT)
                layoutParam.gravity = Gravity.START
    
                layoutParam.setMargins(oneItemAreaWidth / 2 + marginLeft, marginTop, 0, 0)
                menuItem.addView(badge, layoutParam)
            }
        }
     }
    

    It's attr.xml file with options for this component:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="advanced_bottom_navigation_bar">
            <attr name="badge_layout" format="reference|integer" />
        </declare-styleable>
    </resources>
    

    Background for badge from drawable folder:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item>
            <shape>
                <solid android:color="#ff0000" />
                <corners android:radius="10dp" />
            </shape>
        </item>
    </selector>
    

    Badge itself:

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
        android:id="@+id/bottom_bar_badge"
        android:layout_height="20dp"
        android:layout_width="20dp"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:background="@drawable/bcg_badge"
        >
    <TextView
        android:id="@+id/bottom_bar_badge_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1"
        android:textSize="10sp"
        android:textColor="@android:color/white"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:textAlignment="center"
        android:layout_gravity="center"/>
    </FrameLayout>
    

    And this is an example how to use it in your code:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="su.ivcs.ucim.presentationLayer.userStories.mainScreen.view.MainActivity">
    
        <su.ivcs.ucim.presentationLayer.common.advancedBottomNavigationView.AdvancedBottomNavigationView
            android:id="@+id/bottom_navigation"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            app:itemBackground="@android:color/white"
            app:itemIconTint="@color/main_screen_tabs_menu_items"
            app:itemTextColor="@color/main_screen_tabs_menu_items"
            app:menu="@menu/main_screen_tabs_menu"
            app:badge_layout = "@layout/common_badge"
    
            app:layout_constraintTop_toBottomOf="@+id/fragmentsContainer"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            />
    
    </android.support.constraint.ConstraintLayout>
    

    I hope this helps you.

    0 讨论(0)
  • 2020-12-02 02:35

    @hrskrs Try adding a higher elevation on your txtCount or badgeWrapper itself. BottomNavigationView seems to have higher elevation than the views on the screen.

    I struggled with showing badges on BottomNavigationView items. My badge (without any text value) being part of the drawable itself turned grey when user clicked other item or became the same color defined in the tint (if not defined is colorPrimary). I think you will run into the same problem I faced with colouring of the badge/counter on top of menu item of BottomNavigationViewas tint color will be applied to the item itself and your badgeWrapper being part of MenuItem will take the tint (turns grey when you tap any other item which you will not want I guess).

    Check out my answer here: Is there a way to display notification badge on Google's official BottomNavigationView menu items introduced in API 25?

    I used an ImageView for a badge but you can have your badgeWrapper RelativeView instead of the ImageView.

    0 讨论(0)
  • 2020-12-02 02:36

    You can use the BottomNavigationView provided by the Material Components Library.

    Just add the BottomNavigationView to your layout:

      <com.google.android.material.bottomnavigation.BottomNavigationView
          android:layout_gravity="bottom"
          app:menu="@menu/navigation_main" 
          ../>
    

    Then use in your code:

      int menuItemId = bottomNavigationView.getMenu().getItem(0).getItemId();
      BadgeDrawable badge = bottomNavigationView.getOrCreateBadge(menuItemId);
      badge.setNumber(2);
    

    To change the badge gravity use the setBadgeGravity method.

    badge.setBadgeGravity(BadgeDrawable.BOTTOM_END);
    

    0 讨论(0)
提交回复
热议问题