14

Why BadgeDrawable is not displayed anywhere? I'm trying to add on MaterialCardView, MaterialButton etc. It's not showing. Anyone have ideas how to fix this? Or have the same library that replacing this?

Here's code:

val badgeDrawable = BadgeDrawable.create(holder.itemView.context)
badgeDrawable.number = 10
badgeDrawable.badgeGravity = BadgeDrawable.TOP_END
badgeDrawable.backgroundColor = holder.itemView.context.getColor(R.color.colorAccent)
holder.itemView.home_cardview.overlay.add(badgeDrawable)
badgeDrawable.updateBadgeCoordinates(holder.itemView.home_cardview, null)

This method not working too:

BadgeUtils.attachBadgeDrawable(badgeDrawable, anchor, null);

By the way in new version compatBadgeParent is required field

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
Mindgamer
  • 209
  • 1
  • 2
  • 10

7 Answers7

11

You can apply the BadgeDrawable to a MaterialCardView or a MaterialButton using a layout as:

<FrameLayout
    android:id="@+id/layout"
    android:clipChildren="false"
    android:clipToPadding="false"
    ..>

        <com.google.android.material.card.MaterialCardView
            android:id="@+id/card"
            .../>

</FrameLayout>

Then just use the method BadgeUtils.attachBadgeDrawable.

For example with a CardView:

    MaterialCardView cardview = findViewById(R.id.card);
    cardview.setClipToOutline(false);  //Important with a CardView

    cardview.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            BadgeDrawable badgeDrawable = BadgeDrawable.create(MainActivity.this);
            badgeDrawable.setNumber(15);
            BadgeUtils.attachBadgeDrawable(badgeDrawable, cardview, findViewById(R.id.layout));

            cardview.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });

enter image description here

For a Button:

<FrameLayout
    android:id="@+id/layout"
    android:clipChildren="false"
    android:clipToPadding="false">

  <com.google.android.material.button.MaterialButton
      android:id="@+id/button"
      ../>

</FrameLayout>

and then a similar code:

    button.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            BadgeDrawable badgeDrawable = BadgeDrawable.create(MainActivity.this);
            badgeDrawable.setNumber(7);
            badgeDrawable.setBackgroundColor(......);
            badgeDrawable.setVerticalOffset(20);
            badgeDrawable.setHorizontalOffset(15);

            BadgeUtils.attachBadgeDrawable(badgeDrawable, button, findViewById(R.id.layout));

            button.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });

enter image description here

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
3

Here I have implemented BadgeDrawable using BadgeUtils with xml style to add badge on Button.

private fun setBadgeCount(count: Int) {
        BadgeDrawable.createFromResource(this, R.xml.badge_style).apply {
            number = count
            BadgeUtils.attachBadgeDrawable(this, binding.buttonContact)
        }
    }

badge_style.xml:

<badge xmlns:app="http://schemas.android.com/apk/res-auto"
    style="@style/Widget.MaterialComponents.Badge"
    app:backgroundColor="#FF0000"
    app:badgeTextColor="#FFFFFF"
    app:horizontalOffset="6dp"
    app:maxCharacterCount="2"
    app:verticalOffset="8dp" />

Output:

enter image description here

Reference:

  1. https://material.io/develop/android/supporting/badge
  2. https://developer.android.com/reference/com/google/android/material/badge/package-summary
pRaNaY
  • 24,642
  • 24
  • 96
  • 146
2

Here is the solution posted by @0X0nosugar on my question so please go check out his answer and give him a thumbs up. Links placed above, thank you!

BottomNavigationView.getOrCreateBadge() does not only assign the BadgeDrawable as foreground Drawable, but it also sets the drawable bounds. Without this step, they stay at (0,0,0,0), so there is nothing to draw.

In order to set the bounds, let's introduce an extension function for BadgeDrawable

/**
 * Inspired by BadgeUtils in com.google.android.material library
 *
 * Sets the bounds of a BadgeDrawable 
 */
private fun BadgeDrawable.setBoundsFor(@NonNull anchor: View, @NonNull parent: FrameLayout){
    val rect = Rect()
    parent.getDrawingRect(rect)
    this.setBounds(rect)
    this.updateBadgeCoordinates(anchor, parent)
}

Use this function with your BadgeDrawable for FrameLayout:

private fun setFindShiftBadge(state: HomeState) {
    val findShiftsBadge = BadgeDrawable.create(this)
    // configure the badge drawable
    findShiftsBadge.badgeGravity = BadgeDrawable.TOP_END
    findShiftsBadge.backgroundColor = resources.getColor(R.color.colorWhite)
    findShiftsBadge.badgeTextColor = resources.getColor(R.color.colorPrimary)
    findShiftsBadge.number = state.availableShifts.size
    // set bounds inside which it will be drawn
    findShiftsBadge.setBoundsFor(btn_badge, home_framelayout)
    // assign as foreground drawable
    home_framelayout.foreground = findShiftsBadge
}

enter image description here

Princeps Polycap
  • 220
  • 2
  • 16
2

You can use the following function without FrameLayout in Kotlin way as:

view is the component where you want to put the notification badge!

@SuppressLint("UnsafeExperimentalUsageError")
    private fun initBadge(view : View, nbrNotification : Int) {

        if(nbrNotification == 0) return // Don't show the badge

        view.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {

            override fun onGlobalLayout() {

                BadgeDrawable.create(requireContext()).apply {
                    number = nbrNotification
                    verticalOffset = 70
                    horizontalOffset = 70
                    //badgeDrawable.setBackgroundColor() #to change the background color
                    BadgeUtils.attachBadgeDrawable(this, view)
                }

                view.viewTreeObserver.removeOnGlobalLayoutListener(this)
            }
        })
    }
Yasser AKBBACH
  • 539
  • 5
  • 7
0

verify the version that are you using, I am using:

com.google.android.material:material: 1.1.0-beta01

and try with this:

bottomNavigationView.getOrCreateBadge(R.id.menu_item_notifications).apply {
            backgroundColor = resources.getColor(R.color.red)
            badgeTextColor = resources.getColor(R.color.white)
            maxCharacterCount = 3
            number = 10 //should be change
            isVisible = true
        }
Osvaldo Bringaz
  • 127
  • 1
  • 7
0

I encountered the same problem. It may be a bug in the Badge library. This's work:

        badgeDrawable = BadgeDrawable.create(frameLayoutContainer.getContext());
        frameLayoutContainer.setForeground(badgeDrawable);
        frameLayoutContainer.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
            //
            badgeDrawable.updateBadgeCoordinates(frameLayoutContainer, frameLayoutContainer);
        });

frameLayoutContainer is a FrameLayout that sets BadgeDrawable to its foreground.

尹劍平
  • 184
  • 1
  • 1
  • 5
0
    BadgeDrawable badgeDrawable = BadgeDrawable.create(this);
    badgeDrawable.setNumber(15);

    FrameLayout frameLayout = findViewById(R.id.framelayout);

    ImageView imageView = findViewById(R.id.iv_center);

    //core code
    frameLayout.setForeground(badgeDrawable);
    frameLayout.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {


        //either of the following two lines of code  work
        //badgeDrawable.updateBadgeCoordinates(imageView, frameLayout);
        BadgeUtils.attachBadgeDrawable(badgeDrawable, imageView, frameLayout);
    });





    <FrameLayout
        android:id="@+id/framelayout"
        android:layout_width="150dp"
        android:layout_height="150dp">

        <ImageView
            android:layout_gravity="center"
            android:id="@+id/iv_center"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:scaleType="fitXY"
            android:src="@drawable/ic_beard" />
    </FrameLayout>
Kevin Yuan
  • 307
  • 3
  • 13