web-dev-qa-db-fra.com

Badge sur la navigation de fondVoir

J'essaie d'ajouter un badge à l'élément BottomNavigationView sans utiliser de bibliothèque, mais d'une manière ou d'une autre, la BottomNavigationView ne montre pas le badge (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>

Activité prolongée à partir de 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>

Au lieu d'afficher (badge) custom_view, l'élément en question est affiché uniquement:

 enter image description here

Ci-dessous, vous pouvez voir en mode débogage que la view à laquelle vous avez accédé est la bonne et qu'elle est définie correctement. Cependant, d'une manière ou d'une autre, la BottomNavigationView n'est pas invalidée:

 enter image description here

9
hrskrs

J'ai réussi à faire BottomNavigationView avec le badge. Voici mon code (Kotlin).

Ceci est le panneau (hérité de 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)
        }
    }
 }

C'est un fichier attr.xml avec des options pour ce composant:

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

Fond pour le badge du dossier pouvant être tiré:

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

Insigne lui-même:

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

Et voici un exemple d'utilisation dans votre 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>

J'espère que ceci vous aide.

6
Alex Shevelev

@hrskrs Essayez d’ajouter une altitude plus élevée à votre txtCount ou à votre badgeWrapper lui-même. BottomNavigationView semble avoir une altitude plus élevée que les vues à l’écran.

J'ai eu du mal à montrer des badges sur les articles BottomNavigationView. Mon badge (sans aucune valeur de texte) faisant partie du dessinable lui-même est devenu gris lorsque l'utilisateur a cliqué sur un autre élément ou est devenu la même couleur définie dans la teinte (si non défini est colorPrimary). Je pense que vous rencontrerez le même problème que je rencontrais avec la coloration du badge/compteur en haut de l'élément de menu de BottomNavigationView car la couleur de teinte sera appliquée à l'article lui-même et votre badge faisant partie de MenuItem prendra la teinte (devient gris lorsque vous appuyez sur un autre élément que vous ne voudrez plus, je suppose).

Découvrez ma réponse ici: Existe-t-il un moyen d’afficher un badge de notification dans les éléments de menu officiels de Google BottomNavigationView introduits dans l’API 25?

J'ai utilisé un ImageView pour un badge mais vous pouvez avoir votre badgeWrapper RelativeView à la place de ImageView.

1
Waqas