Actionbar Notification Count Icon (Badge) Like Google Has

Actionbar notification count icon (badge) like Google has

I am not sure if this is the best solution or not, but it is what I need.

Please tell me if you know what is need to be changed for better performance or quality. In my case, I have a button.

Custom item on my menu - main.xml

<item
android:id="@+id/badge"
android:actionLayout="@layout/feed_update_count"
android:icon="@drawable/shape_notification"
android:showAsAction="always">
</item>

Custom shape drawable (background square) - shape_notification.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:color="#22000000" android:width="2dp"/>
<corners android:radius="5dp" />
<solid android:color="#CC0001"/>
</shape>

Layout for my view - feed_update_count.xml

<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/notif_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="32dp"
android:minHeight="32dp"
android:background="@drawable/shape_notification"
android:text="0"
android:textSize="16sp"
android:textColor="@android:color/white"
android:gravity="center"
android:padding="2dp"
android:singleLine="true">
</Button>

MainActivity - setting and updating my view

static Button notifCount;
static int mNotifCount = 0;

@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.main, menu);

View count = menu.findItem(R.id.badge).getActionView();
notifCount = (Button) count.findViewById(R.id.notif_count);
notifCount.setText(String.valueOf(mNotifCount));
return super.onCreateOptionsMenu(menu);
}

private void setNotifCount(int count){
mNotifCount = count;
invalidateOptionsMenu();
}

Notification Badge On Action Item Android

You can show custom MenuItem on ActionBar by creating a custom layout for MenuItem. To set a custom layout you have to use menu item attribute app:actionLayout.

Follow below steps to create a Badge on Cart action item. See the attached image for result.

  1. Create a custom layout with ImageView(for cart icon) and TextView(for count value)

layout/custom_action_item_layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
style="?attr/actionButtonStyle"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:focusable="true">

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_action_cart"/>

<TextView
android:id="@+id/cart_badge"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="right|end|top"
android:layout_marginEnd="-5dp"
android:layout_marginRight="-5dp"
android:layout_marginTop="3dp"
android:background="@drawable/badge_background"
android:gravity="center"
android:padding="3dp"
android:textColor="@android:color/white"
android:text="0"
android:textSize="10sp"/>

</FrameLayout>

  1. Create drawable circular badge background using Shape.

drawable/badge_background.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">

<solid android:color="@android:color/holo_red_dark"/>
<stroke android:color="@android:color/white" android:width="1dp"/>

</shape>

  1. Add custom layout to menu item.

menu/main_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/action_cart"
android:icon="@drawable/ic_action_cart"
android:title="Cart"
app:actionLayout="@layout/custom_action_item_layout"
app:showAsAction="always"/>

</menu>

  1. In your MainActivity, add following codes:

MainActivity.java:

public class MainActivity extends AppCompatActivity {
................
......................
TextView textCartItemCount;
int mCartItemCount = 10;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

.....................
............................
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);

final MenuItem menuItem = menu.findItem(R.id.action_cart);

View actionView = menuItem.getActionView();
textCartItemCount = (TextView) actionView.findViewById(R.id.cart_badge);

setupBadge();

actionView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onOptionsItemSelected(menuItem);
}
});

return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

switch (item.getItemId()) {

case R.id.action_cart: {
// Do something
return true;
}
}
return super.onOptionsItemSelected(item);
}

private void setupBadge() {

if (textCartItemCount != null) {
if (mCartItemCount == 0) {
if (textCartItemCount.getVisibility() != View.GONE) {
textCartItemCount.setVisibility(View.GONE);
}
} else {
textCartItemCount.setText(String.valueOf(Math.min(mCartItemCount, 99)));
if (textCartItemCount.getVisibility() != View.VISIBLE) {
textCartItemCount.setVisibility(View.VISIBLE);
}
}
}
}

..................
..............................

}

OUTPUT:

Sample Image

How to make an icon in the action bar with the number of notification?

After a lot of trying of nearly all resources on SO I turned to blogs; successfully. I want to share what worked for me (Api >= 13).

Let's start with the way it's used in code:

 public boolean onCreateOptionsMenu(Menu menu) {
//inflate menu
getMenuInflater().inflate(R.menu.menu_my, menu);

// Get the notifications MenuItem and LayerDrawable (layer-list)
MenuItem item = menu.findItem(R.id.action_notifications);
LayerDrawable icon = (LayerDrawable) item.getIcon();

// Update LayerDrawable's BadgeDrawable
Utils2.setBadgeCount(this, icon, 2);

return true;
}

The menu_my.xml:

<menu 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"
tools:context=".MainActivity">
<item
android:id="@+id/action_notifications"
android:icon="@drawable/ic_menu_notifications"
android:title="Notifications"
app:showAsAction="always" />
</menu>

This class that conveniently makes a BadgeDrawable:

public class BadgeDrawable extends Drawable {

private float mTextSize;
private Paint mBadgePaint;
private Paint mTextPaint;
private Rect mTxtRect = new Rect();

private String mCount = "";
private boolean mWillDraw = false;

public BadgeDrawable(Context context) {
//mTextSize = context.getResources().getDimension(R.dimen.badge_text_size);
mTextSize = 12F;

mBadgePaint = new Paint();
mBadgePaint.setColor(Color.RED);
mBadgePaint.setAntiAlias(true);
mBadgePaint.setStyle(Paint.Style.FILL);

mTextPaint = new Paint();
mTextPaint.setColor(Color.WHITE);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
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.
float radius = ((Math.min(width, height) / 2) - 1) / 2;
float centerX = width - radius - 1;
float centerY = radius + 1;

// Draw badge circle.
canvas.drawCircle(centerX, centerY, radius, 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);
canvas.drawText(mCount, centerX, textY, mTextPaint);
}

/*
Sets the count (i.e notifications) to display.
*/
public void setCount(int count) {
mCount = Integer.toString(count);

// Only draw a badge if there are notifications.
mWillDraw = count > 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;
}
}

This class that helps to set the number.

public class Utils2 {
public static void setBadgeCount(Context context, LayerDrawable icon, int 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);
}


}

And mui importante a drawable (like a layout) in res/drawable:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/ic_notification"
android:drawable="@drawable/ice_skate"
android:gravity="center" />

<!-- set a place holder Drawable so android:drawable isn't null -->
<item
android:id="@+id/ic_badge"
android:drawable="@drawable/ice_skate" />
</layer-list>

Good luck!



Related Topics



Leave a reply



Submit