【问题标题】:Badge on BottomNavigationViewBottomNavigationView 上的徽章
【发布时间】:2017-06-24 12:44:06
【问题描述】:

我正在尝试在不使用任何库的情况下将徽章添加到 BottomNavigationView 项目,但不知何故 BottomNavigationView 没有显示徽章 (custom_view)

main_view.xml:

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:id="@+id/activity_main"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  tools:context="com.hrskrs.test.MainActivity">

  <FrameLayout
    android:id="@+id/container"
    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:itemBackground="@color/colorPrimary"
    app:itemIconTint="@color/colorAccent"
    app:itemTextColor="@color/colorPrimaryDark"
    app:menu="@menu/bottom_navigation_main" />
</RelativeLayout>

bottom_navigation_menu.xml:

    <menu xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto">
  <item
    android:id="@+id/item_test"
    android:icon="@mipmap/ic_launcher"
    android:title="action1"
    app:showAsAction="always" />

  <item
    android:enabled="true"
    android:icon="@mipmap/ic_launcher"
    android:title="action2"
    app:showAsAction="ifRoom" />

  <item
    android:enabled="true"
    android:icon="@mipmap/ic_launcher"
    android:title="action3"
    app:showAsAction="ifRoom" />
</menu>

活动扩展自AppCompatActivity

@Override
  public boolean onCreateOptionsMenu(Menu menu) {
    menu = bottomNavigationView.getMenu();
    menu.clear();
    getMenuInflater().inflate(R.menu.bottom_navigation_main, menu);
    MenuItem item = menu.findItem(R.id.item_test);
    item = MenuItemCompat.setActionView(item, R.layout.custom_view);
    RelativeLayout badgeWrapper = (RelativeLayout) MenuItemCompat.getActionView(item);

    TextView textView = (TextView) badgeWrapper.findViewById(R.id.txtCount);
    textView.setText("99+");

    return super.onCreateOptionsMenu(menu);
  }

custom_view.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  style="@android:style/Widget.ActionButton"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:background="@android:color/transparent"
  android:clickable="true"
  android:gravity="center"
  android:orientation="vertical">

  <ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:contentDescription="Notification Icon"
    android:gravity="center"
    android:src="@mipmap/ic_launcher" />

  <TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/txtCount"
    android:gravity="right"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/ic_badge"
    android:text="55"
    android:textColor="#ffffffff"
    android:textSize="12sp" />
</RelativeLayout>

而不是显示(badge) custom_view,它只显示项目本身:

从下面的调试模式可以看出,访问的view 是正确的,并且设置正确。然而不知何故 BottomNavigationView 并没有被无效:

【问题讨论】:

标签: android android-layout bottomnavigationview material-components-android material-components


【解决方案1】:

您可以使用Material Components Library提供的BottomNavigationView

只需将BottomNavigationView 添加到您的布局中:

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

然后在你的代码中使用:

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

要更改徽章的重力,请使用 setBadgeGravity 方法。

badge.setBadgeGravity(BadgeDrawable.BOTTOM_END);

【讨论】:

    【解决方案2】:

    我设法用徽章制作了 BottomNavigationView。这是我的代码 (Kotlin)。

    这是面板(继承自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)
            }
        }
     }
    

    它是带有此组件选项的 attr.xml 文件:

    <?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>
    

    可绘制文件夹中徽章的背景:

    <?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>
    

    徽章本身:

    <?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>
    

    这是一个如何在您的代码中使用它的示例:

    <?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>
    

    希望对你有帮助。

    【讨论】:

    • 什么是 UICalculatorInterface ??
    • @MuneerahRashed 这是我的 UI 度量计算助手 - 大小等。对于这个解决方案,它不是必需的。
    【解决方案3】:

    @hrskrs 尝试在 txtCount 或 badgeWrapper 本身上添加更高的海拔。 BottomNavigationView 的高度似乎比屏幕上的视图高。

    我很难在BottomNavigationView 项目上显示徽章。当用户单击其他项目或变成与色调中定义的相同颜色(如果未定义为 colorPrimary)时,我的徽章(没有任何文本值)作为可绘制对象本身的一部分变为灰色。 我认为您会遇到与BottomNavigationView菜单项顶部的徽章/计数器着色相同的问题,因为色调颜色将应用于项目本身,您的badgeWrapper作为MenuItem的一部分将采用色调(当您点击我猜您不想要的任何其他项目时变为灰色)。

    在这里查看我的答案:Is there a way to display notification badge on Google's official BottomNavigationView menu items introduced in API 25?

    我使用 ImageView 作为徽章,但您可以使用您的 badgeWrapper RelativeView 而不是 ImageView。

    【讨论】:

    • 我不是在寻求替代方案,因为有多种方法可以实现它。我要求将徽章添加到 BottomNavigationViewMenu resources
    • 我在菜单资源方面遇到了困难,但它对我不起作用。用菜单资源做这件事是正确的方法。我很高兴看到您是否可以使用菜单资源。
    【解决方案4】:

    像这样使用BadgeDrawable

    Integer amount = tabBadgeCountMap.get(tab);
                BadgeDrawable badgeDrawable = bottomNavigationView.getOrCreateBadge(tabMenuResId);
                badgeDrawable.setNumber(amount != null ? amount : 0);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-25
      • 2019-08-15
      • 2020-02-18
      • 1970-01-01
      • 2012-09-20
      • 2019-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多