I want to notify user about new unread message in the app which is accessible through navigation drawer. I was thinking about notification badge something similar Apple have but over drawer toggle in toolbar.
This is what I have now:
This is what I want:
How can I achieve that?
Right-click on drawable > new > vector asset > search for notification icon and select > finish. We are going to use this icon to show our notification count on top of it.
If you want to change badge with number, you can be changed in NOTIFICATION SETTING on the notification panel or Settings > Notifications > App icon badges > Select Show with number.
1 Go to Settings menu > Notifications. 3 Toggle the switch to ensure the App icon badge feature has been enabled. You can choose to Show with or without number of notifications displayed on the badge.
I found this really cool BadgeDrawable class on the internet and you can add badge count to any drawable using this class. Please follow below steps.
Step 1: add below class to your project first.
import android.content.Context; import android.content.res.Resources; 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.util.TypedValue; /** * Created by Admin on 2/25/2016. */ public class BadgeDrawable extends Drawable { private float mTextSize; private Paint mBadgePaint; private Paint mBadgePaint1; private Paint mTextPaint; private Rect mTxtRect = new Rect(); private String mCount = ""; private boolean mWillDraw = false; public BadgeDrawable(Context context) { mTextSize = dpToPx(context, 8); //text size mBadgePaint = new Paint(); mBadgePaint.setColor(Color.RED); mBadgePaint.setAntiAlias(true); mBadgePaint.setStyle(Paint.Style.FILL); mBadgePaint1 = new Paint(); mBadgePaint1.setColor(Color.parseColor("#EEEEEE")); 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); } private float dpToPx(Context context, float value) { Resources r = context.getResources(); float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, r.getDisplayMetrics()); return px; } @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 radius = width * 0.15f; float centerX = (width - radius - 1) +10; float centerY = radius -5; if(mCount.length() <= 2){ // Draw badge circle. canvas.drawCircle(centerX, centerY, radius+9, mBadgePaint1); canvas.drawCircle(centerX, centerY, radius+7, mBadgePaint); } else{ canvas.drawCircle(centerX, centerY, radius+10, mBadgePaint1); canvas.drawCircle(centerX, centerY, radius+8, 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; } }
Step 2: Now create a drawable (in my case it is ic_badge_drawable.xml). Then copy and paste below xml text.
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/ic_main_icon" android:drawable="@drawable/ic_burger" android:gravity="center" /> <!-- set a place holder Drawable so android:drawable isn't null --> <item android:id="@+id/ic_badge" android:drawable="@drawable/ic_burger" /> </layer-list>
here you can pass any drawable for now, later we can pass any drawable to those. These are just like place holders.
Step 3: We have already setup everything. Now you can use below method to set badge count for any drawable.
private Drawable setBadgeCount(Context context, int res, int badgeCount){ LayerDrawable icon = (LayerDrawable) ContextCompat.getDrawable(context, R.drawable.ic_badge_drawable); Drawable mainIcon = ContextCompat.getDrawable(context, res); BadgeDrawable badge = new BadgeDrawable(context); badge.setCount(String.valueOf(badgeCount)); icon.mutate(); icon.setDrawableByLayerId(R.id.ic_badge, badge); icon.setDrawableByLayerId(R.id.ic_main_icon, mainIcon); return icon; }
Step 4: I used it as below to change my default burger icon.
setSupportActionBar(toolbar); getSupportActionBar().setHomeAsUpIndicator(setBadgeCount(this,R.drawable.ic_burger, 3)); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayShowCustomEnabled(true); // enable overriding the default toolbar layout getSupportActionBar().setDisplayShowTitleEnabled(false);// disable the default title element here (for centered title)
I have used simple TextView inside android.support.design.widget.AppBarLayout please check below complete code
MainActivity.java
import android.os.Bundle; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.widget.TextView; public class MainActivity extends AppCompatActivity { private DrawerLayout mDrawerLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); } private void initViews() { mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); setUpToolbar(); } private void setUpToolbar() { Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); final ActionBar ab = getSupportActionBar(); ab.setHomeAsUpIndicator(R.drawable.navigation_drawericon); ab.setDisplayHomeAsUpEnabled(true); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.home_menu, menu); return true; } @Override public boolean onOptionsItemSelected(android.view.MenuItem item) { switch (item.getItemId()) { case android.R.id.home: mDrawerLayout.openDrawer(GravityCompat.START); return true; } return super.onOptionsItemSelected(item); } private void updateCounter(int count) { ((TextView) findViewById(R.id.tv_nav_drawer_count)).setText(count + ""); } public void closeDrawer() { mDrawerLayout.closeDrawers(); } }
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" android:fitsSystemWindows="true"> <include layout="@layout/container_layout"/> <android.support.design.widget.NavigationView android:id="@+id/navigation_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="start" android:fitsSystemWindows="true"> </android.support.design.widget.NavigationView> </android.support.v4.widget.DrawerLayout>
container_layout.xml
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/main_content" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> <TextView android:id="@+id/tv_nav_drawer_count" android:layout_width="15dp" android:layout_height="15dp" android:layout_marginLeft="30dp" android:layout_marginTop="-45dp" android:background="@drawable/menu_text_bg" android:gravity="center" android:text="10" android:textColor="@android:color/white" android:textSize="8dp"/> </android.support.design.widget.AppBarLayout> <FrameLayout android:id="@+id/home_frame_container" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="?actionBarSize"/> </android.support.design.widget.CoordinatorLayout>
home_menu.xml
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/menu_search" android:icon="@android:drawable/ic_menu_search" android:orderInCategory="101" android:title="Search" app:showAsAction="always"/> </menu>
menu_text_bg.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0"> <path android:fillColor="@android:color/holo_red_dark" android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"/> </vector>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With