Updated 30 June 2023
In every application, we decorate our MenuItem placed on ActionBar. Displaying of badge count not only decorate the ActionBar beautifully but also displays useful information like showing the number of items currently available in your cart or update you with unread notification.
We can create badge count using either a custom view or by adding a distinct drawable to display the each state of MenuItem.
Both the options have its pros and cons.
There is another approach using LayerDrawable which is more flexible and efficient than the former approaches.
A Drawable that manages an array of other Drawables. These are drawn in array order, so the element with the largest index will be drawn on top.It can be defined in an XML file with the
It can be defined in an XML file with the <layer-list>
element. Each Drawable in the layer is defined in a nested<item>
i. Creating a layer drawable to display menu item on layer one and badge on top of it.
ic_menu_cart.xml
1 2 3 4 5 6 7 8 9 10 11 |
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/ic_cart" android:gravity="center" /> <!-- set a place holder Drawable so android:drawable isn't null --> <item android:id="@+id/ic_badge" android:drawable="@drawable/ic_cart" /> </layer-list> |
ii. Creating menu for our activity to display the count on the menu items.
main.xml
1 2 3 4 5 6 7 8 9 10 11 |
<menu 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" tools:context="com.example.mobikul.MainActivity" > <item android:id="@+id/action_cart" android:icon="@drawable/ic_menu_cart" android:title="@string/action_cart" app:showAsAction="always" /> </menu> |
iii. Creating a flexible and efficient custom BagdeDrawable class to draw a view that looks like a count
BagdeDrawable.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
package com.webkul.mobikul.helper; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.support.v4.content.ContextCompat; import com.webkul.mobikul.R; public class BadgeDrawable extends Drawable { private Paint mBadgePaint; private Paint mBadgePaint1; private Paint mTextPaint; private Rect mTxtRect = new Rect(); private String mCount = ""; private boolean mWillDraw; public BadgeDrawable(Context context) { float mTextSize = context.getResources().getDimension(R.dimen.badge_text_size); mBadgePaint = new Paint(); mBadgePaint.setColor(Color.RED); mBadgePaint.setAntiAlias(true); mBadgePaint.setStyle(Paint.Style.FILL); mBadgePaint1 = new Paint(); mBadgePaint1.setColor(ContextCompat.getColor(context.getApplicationContext(), R.color.grey_ivory5)); mBadgePaint1.setAntiAlias(true); mBadgePaint1.setStyle(Paint.Style.FILL); mTextPaint = new Paint(); mTextPaint.setColor(Color.WHITE); mTextPaint.setTypeface(Typeface.DEFAULT); mTextPaint.setTextSize(mTextSize); mTextPaint.setAntiAlias(true); mTextPaint.setTextAlign(Paint.Align.CENTER); } @Override public void draw(Canvas canvas) { if (!mWillDraw) { return; } Rect bounds = getBounds(); float width = bounds.right - bounds.left; float height = bounds.bottom - bounds.top; // Position the badge in the top-right quadrant of the icon. /*Using Math.max rather than Math.min */ float radius = ((Math.max(width, height) / 2)) / 2; float centerX = (width - radius - 1) +5; float centerY = radius -5; if(mCount.length() <= 2){ // Draw badge circle. canvas.drawCircle(centerX, centerY, (int)(radius+7.5), mBadgePaint1); canvas.drawCircle(centerX, centerY, (int)(radius+5.5), mBadgePaint); } else{ canvas.drawCircle(centerX, centerY, (int)(radius+8.5), mBadgePaint1); canvas.drawCircle(centerX, centerY, (int)(radius+6.5), mBadgePaint); // canvas.drawRoundRect(radius, radius, radius, radius, 10, 10, mBadgePaint); } // Draw badge count text inside the circle. mTextPaint.getTextBounds(mCount, 0, mCount.length(), mTxtRect); float textHeight = mTxtRect.bottom - mTxtRect.top; float textY = centerY + (textHeight / 2f); if(mCount.length() > 2) canvas.drawText("99+", centerX, textY, mTextPaint); else canvas.drawText(mCount, centerX, textY, mTextPaint); } /* Sets the count (i.e notifications) to display. */ public void setCount(String count) { mCount = count; // Only draw a badge if there are notifications. mWillDraw = !count.equalsIgnoreCase("0"); invalidateSelf(); } @Override public void setAlpha(int alpha) { // do nothing } @Override public void setColorFilter(ColorFilter cf) { // do nothing } @Override public int getOpacity() { return PixelFormat.UNKNOWN; } } |
We can get the icon of the menu using getIcon() method.
1 2 3 |
MenuItem itemCart = menu.findItem(R.id.action_cart); LayerDrawable icon = (LayerDrawable) itemCart.getIcon(); setBadgeCount(this, icon, "9"); |
Here is our method setBadgeCount(). We can pass LayerDrawable which we get from meniItem and setBadge from anywhere from the application.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public static void setBadgeCount(Context context, LayerDrawable icon, String count) { BadgeDrawable badge; // Reuse drawable if possible Drawable reuse = icon.findDrawableByLayerId(R.id.ic_badge); if (reuse != null && reuse instanceof BadgeDrawable) { badge = (BadgeDrawable) reuse; } else { badge = new BadgeDrawable(context); } badge.setCount(count); icon.mutate(); icon.setDrawableByLayerId(R.id.ic_badge, badge); } |
If you have more details or questions, you can reply to the received confirmation email.
Back to Home
I have a question how to remove badge on click menu item for showing notification read???