how can i add notification badges in the app? - android

I want to add a notification badge in the application like the following one:
How to implement badges. Please Guide.

If you want to add badge to Icon
BadgeDrawable is a custom drawable
package com.wisilica.cms.utitlty.viewHelper;
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.wisilica.cms.R;
/**
* Created by Godwin Joseph on 02-11-2016 11:49 for Cms_Android application.
*/
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.white));
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;
}
}
And Add code
{
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(mContext);
}
badge.setCount(count);
icon.mutate();
icon.setDrawableByLayerId(R.id.ic_badge, badge);
}
You can set Drwabale in any view

This is called badges.
You can use this library for badge support.
Leolin Shortcut Badger
and this is also Android ActionItem Badged
I think its not possible for all devices. although Samsung used it.
You can read here the Posts seems same as yours.

<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="5dp"
>
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="#null"
android:text="Button" />
<FrameLayout
android:id="#+id/badgecountlayout"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="left"
android:layout_marginLeft="8dp"
android:layout_marginTop="10dp">
<TextView
android:id="#+id/badgecount"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/round_notification"
android:gravity="center"
android:text="99" />
</FrameLayout>
</FrameLayout>
round_notification.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" >
<gradient android:startColor="#color/yellow_dark" android:endColor="#color/yellow_dark"
android:angle="270"/>
</shape>

Related

android -- How to draw a rect in circle

I need a view like below:
The blue height will be updated according to the voice.
I know that using can draw that round rectangle
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#color/bg_send_text" />
<corners android:radius="100dip" />
</shape>
And then I write a VoiceDrawable extends GradientDrawable, and using this code:
public void setVoice(int voice) {
level = (float) 1.0 * voice / 100;
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
rect = getBounds();
canvas.drawRect(rect.left, rect.top + (rect.bottom - rect.top) *
(1 - level), rect.right, rect.bottom, paint);
}
But the result is :
Though I using:
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
So how can I implement this view? What can I do?
You should change ur PorterDuff Mode:
All
I have implemented this view:
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.GradientDrawable;
public class VoiceDrawable extends GradientDrawable {
private static final float DEFAULT_LEVEL = 0.5f;
private Paint levelPaint;
private Paint viewPaint;
private BitmapShader bitmapShader;
private Matrix shaderMatrix;
private float radius;
private float level;
public VoiceDrawable() {
super();
init();
}
private void init() {
levelPaint = new Paint();
levelPaint.setStyle(Paint.Style.FILL);
viewPaint = new Paint();
shaderMatrix = new Matrix();
}
public void setCornerRadius(float radius) {
super.setCornerRadius(radius);
this.radius = radius;
}
public void setVoice(float level) {
this.level = level;
invalidateSelf();
}
public void setLevelColor(int color) {
levelPaint.setColor(color);
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
Rect rect = getBounds();
if (bitmapShader == null) {
initLevel(rect);
}
float scale = level == 0 ? 100 : (1 - level) / (1 - DEFAULT_LEVEL);
shaderMatrix.setScale(1, scale, 0, DEFAULT_LEVEL);
bitmapShader.setLocalMatrix(shaderMatrix);
float rad = Math.min(radius, Math.min(rect.width(), rect.height()) * 0.5f);
canvas.drawRoundRect(new RectF(rect), rad, rad, viewPaint);
}
private void initLevel(Rect rect) {
Bitmap bitmap = Bitmap.createBitmap(rect.width(), rect.height(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawRect(rect.left, rect.top + rect.height() * (1 - DEFAULT_LEVEL), rect.right, rect.bottom, levelPaint);
bitmapShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
viewPaint.setShader(bitmapShader);
}
}
The main idea is using shader.
And I get idea from https://github.com/gelitenight/WaveView

Android How to draw a regular polygon via xml or programical

Is there any way to draw polygonal shapes on Android xml layouts?
or is any helper class as library to draw them?
I am using enhanced version of this Class
See working sample on GitHub (https://github.com/hiteshsahu/Benzene)
Drawable Class
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
/**
* Originally Created by AnderWeb (Gustavo Claramunt) on 7/10/14.
*/
public class PolygonalDrwable extends Drawable {
private int numberOfSides = 3;
private Path polygon = new Path();
private Path temporal = new Path();
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
public PolygonalDrwable(int color, int sides) {
paint.setColor(color);
polygon.setFillType(Path.FillType.EVEN_ODD);
this.numberOfSides = sides;
}
#Override
public void draw(Canvas canvas) {
canvas.drawPath(polygon, paint);
}
#Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
#Override
public void setColorFilter(ColorFilter cf) {
paint.setColorFilter(cf);
}
#Override
public int getOpacity() {
return paint.getAlpha();
}
#Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
computeHex(bounds);
invalidateSelf();
}
public void computeHex(Rect bounds) {
final int width = bounds.width();
final int height = bounds.height();
final int size = Math.min(width, height);
final int centerX = bounds.left + (width / 2);
final int centerY = bounds.top + (height / 2);
polygon.reset();
polygon.addPath(createHexagon(size, centerX, centerY));
polygon.addPath(createHexagon((int) (size * .8f), centerX, centerY));
}
private Path createHexagon(int size, int centerX, int centerY) {
final float section = (float) (2.0 * Math.PI / numberOfSides);
int radius = size / 2;
Path polygonPath = temporal;
polygonPath.reset();
polygonPath.moveTo((centerX + radius * (float)Math.cos(0)), (centerY + radius
* (float)Math.sin(0)));
for (int i = 1; i < numberOfSides; i++) {
polygonPath.lineTo((centerX + radius * (float)Math.cos(section * i)),
(centerY + radius * (float)Math.sin(section * i)));
}
polygonPath.close();
return polygonPath;
}
}
Set drawable to any Imageview like this
//Triangle
((ImageView) findViewById(R.id.triangle))
.setBackgroundDrawable(new PolygonalDrwable(Color.GREEN, 3));
//Square
((ImageView) findViewById(R.id.square))
.setBackgroundDrawable(new PolygonalDrwable(Color.MAGENTA, 4));
//Pentagon
((ImageView) findViewById(R.id.pentagon))
.setBackgroundDrawable(new PolygonalDrwable(Color.LTGRAY, 5));
//Hexagon
((ImageView) findViewById(R.id.hex))
.setBackgroundDrawable(new PolygonalDrwable(Color.RED, 6));
//Heptagon
((ImageView) findViewById(R.id.hept))
.setBackgroundDrawable(new PolygonalDrwable(Color.MAGENTA, 7));
//Octagon
((ImageView) findViewById(R.id.oct))
.setBackgroundDrawable(new PolygonalDrwable(Color.YELLOW, 8));
You can create custom drawable and shapes as drawable resources.
Right click on the "drawable" folder in Android Studio and select New->Drawable Resource File.
Here is a decent tutorial for shapes and strokes to get started.
Here is some example shapes ready to use.
Here is documentation for some more complex things you can do with drawables.

How to y-offset the Android 5 Lollipop shadow direction

I used the android material design library to make a tab strip like this.
I added a view at the bottom of the screen like so.
Right now, I am trying to add the shadow effect from the top widget to the bottom view.
I found a solution in the form of an answer to this question.
The only way I found to create a top shadow was to modify some of the source of the Android compatibility v7 CardView project. This project brings the CardView class to older Android versions and thus also includes the elevation shadow. The resulting shadow is very close to a "real" elevation shadow.
I followed the instructions, and I ended with the following result to use an illustration
I added these colors to res/values/values.xml
<color name="cardview_shadow_end_color">#03000000</color>
<color name="cardview_shadow_start_color">#47000000</color>
<dimen name="cardview_compat_inset_shadow">1dp</dimen>
And I used the class RoundRectDrawableWithShadow from the modified Android compatibility v7 CardView project to set the shadow
float elevation = 200;
float density = 0.1f;
View bottomView = (View) rootView.findViewById(R.id.bottomView);
bottomView.setBackgroundDrawable(new RoundRectDrawableWithShadow(
getResources(), Color.BLACK, 0,
elevation * density, ((elevation + 1) * density) + 1
));
Here is my modifed CardView project code RoundRectDrawableWithShadow class
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.graphics.RectF;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
/**
* A rounded rectangle drawable which also includes a shadow around.
*/
public class RoundRectDrawableWithShadow extends Drawable {
// used to calculate content padding
final static double COS_45 = Math.cos(Math.toRadians(45));
final static float SHADOW_MULTIPLIER = 1.5f;
final int mInsetShadow; // extra shadow to avoid gaps between card and shadow
/*
* This helper is set by CardView implementations.
* <p>
* Prior to API 17, canvas.drawRoundRect is expensive; which is why we need this interface
* to draw efficient rounded rectangles before 17.
* */
static RoundRectHelper sRoundRectHelper;
Paint mPaint;
Paint mCornerShadowPaint;
Paint mEdgeShadowPaint;
final RectF mCardBounds;
float mCornerRadius;
Path mCornerShadowPath;
// updated value with inset
float mMaxShadowSize;
// actual value set by developer
float mRawMaxShadowSize;
// multiplied value to account for shadow offset
float mShadowSize;
// actual value set by developer
float mRawShadowSize;
private boolean mDirty = true;
private final int mShadowStartColor;
private final int mShadowEndColor;
private boolean mAddPaddingForCorners = true;
/**
* If shadow size is set to a value above max shadow, we print a warning
*/
private boolean mPrintedShadowClipWarning = false;
public RoundRectDrawableWithShadow(
Resources resources, int backgroundColor, float radius,
float shadowSize, float maxShadowSize
) {
mShadowStartColor = resources.getColor(R.color.cardview_shadow_start_color);
mShadowEndColor = resources.getColor(R.color.cardview_shadow_end_color);
mInsetShadow = resources.getDimensionPixelSize(R.dimen.cardview_compat_inset_shadow);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
mPaint.setColor(backgroundColor);
mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
mCornerShadowPaint.setStyle(Paint.Style.FILL);
mCornerRadius = (int) (radius + .5f);
mCardBounds = new RectF();
mEdgeShadowPaint = new Paint(mCornerShadowPaint);
mEdgeShadowPaint.setAntiAlias(false);
setShadowSize(shadowSize, maxShadowSize);
RoundRectDrawableWithShadow.sRoundRectHelper
= new RoundRectDrawableWithShadow.RoundRectHelper() {
#Override
public void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius,
Paint paint) {
canvas.drawRoundRect(bounds, cornerRadius, cornerRadius, paint);
}
};
}
/**
* Casts the value to an even integer.
*/
private int toEven(float value) {
int i = (int) (value + .5f);
if (i % 2 == 1) {
return i - 1;
}
return i;
}
public void setAddPaddingForCorners(boolean addPaddingForCorners) {
mAddPaddingForCorners = addPaddingForCorners;
invalidateSelf();
}
#Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
mCornerShadowPaint.setAlpha(alpha);
mEdgeShadowPaint.setAlpha(alpha);
}
#Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mDirty = true;
}
void setShadowSize(float shadowSize, float maxShadowSize) {
if (shadowSize < 0 || maxShadowSize < 0) {
throw new IllegalArgumentException("invalid shadow size");
}
shadowSize = toEven(shadowSize);
maxShadowSize = toEven(maxShadowSize);
if (shadowSize > maxShadowSize) {
shadowSize = maxShadowSize;
if (!mPrintedShadowClipWarning) {
mPrintedShadowClipWarning = true;
}
}
if (mRawShadowSize == shadowSize && mRawMaxShadowSize == maxShadowSize) {
return;
}
mRawShadowSize = shadowSize;
mRawMaxShadowSize = maxShadowSize;
mShadowSize = (int)(shadowSize * SHADOW_MULTIPLIER + mInsetShadow + .5f);
mMaxShadowSize = maxShadowSize + mInsetShadow;
mDirty = true;
invalidateSelf();
}
#Override
public boolean getPadding(Rect padding) {
int vOffset = (int) Math.ceil(calculateVerticalPadding(mRawMaxShadowSize, mCornerRadius,
mAddPaddingForCorners));
// int hOffset = (int) Math.ceil(calculateHorizontalPadding(mRawMaxShadowSize, mCornerRadius,
// mAddPaddingForCorners));
// padding.set(hOffset, vOffset, hOffset, vOffset);
padding.set(0, vOffset, 0, 0);
return true;
}
static float calculateVerticalPadding(float maxShadowSize, float cornerRadius,
boolean addPaddingForCorners) {
if (addPaddingForCorners) {
return (float) (maxShadowSize * SHADOW_MULTIPLIER + (1 - COS_45) * cornerRadius);
} else {
return maxShadowSize * SHADOW_MULTIPLIER;
}
}
static float calculateHorizontalPadding(float maxShadowSize, float cornerRadius,
boolean addPaddingForCorners) {
if (addPaddingForCorners) {
return (float) (maxShadowSize + (1 - COS_45) * cornerRadius);
} else {
return maxShadowSize;
}
}
#Override
public void setColorFilter(ColorFilter cf) {
mPaint.setColorFilter(cf);
mCornerShadowPaint.setColorFilter(cf);
mEdgeShadowPaint.setColorFilter(cf);
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
void setCornerRadius(float radius) {
radius = (int) (radius + .5f);
if (mCornerRadius == radius) {
return;
}
mCornerRadius = radius;
mDirty = true;
invalidateSelf();
}
#Override
public void draw(Canvas canvas) {
if (mDirty) {
buildComponents(getBounds());
mDirty = false;
}
canvas.translate(0, -mRawShadowSize / 2);
drawShadow(canvas);
canvas.translate(0, +mRawShadowSize / 2);
sRoundRectHelper.drawRoundRect(canvas, mCardBounds, mCornerRadius, mPaint);
}
private void drawShadow(Canvas canvas) {
final float edgeShadowTop = -mCornerRadius - mShadowSize;
final float insetVertical = mCornerRadius + mInsetShadow + mRawShadowSize / 2;
final float insetHorizontal = -mInsetShadow;
// LT top
int saved = canvas.save();
canvas.translate(mCardBounds.left + insetHorizontal, mCardBounds.top + insetVertical);
canvas.drawPath(mCornerShadowPath, mCornerShadowPaint);
canvas.drawRect(0, edgeShadowTop,
mCardBounds.width() - 2 * insetHorizontal, -mCornerRadius + mShadowSize,
mEdgeShadowPaint);
canvas.restoreToCount(saved);
// RT right
saved = canvas.save();
canvas.translate(mCardBounds.right - insetHorizontal, mCardBounds.top + insetVertical);
canvas.rotate(90f);
canvas.drawPath(mCornerShadowPath, mCornerShadowPaint);
canvas.restoreToCount(saved);
}
private void buildShadowCorners() {
RectF innerBounds = new RectF(-mCornerRadius, -mCornerRadius, mCornerRadius, mCornerRadius);
RectF outerBounds = new RectF(innerBounds);
outerBounds.inset(-mShadowSize, -mShadowSize);
if (mCornerShadowPath == null) {
mCornerShadowPath = new Path();
} else {
mCornerShadowPath.reset();
}
mCornerShadowPath.setFillType(Path.FillType.EVEN_ODD);
mCornerShadowPath.moveTo(-mCornerRadius, 0);
mCornerShadowPath.rLineTo(-mShadowSize, 0);
// outer arc
mCornerShadowPath.arcTo(outerBounds, 180f, 90f, false);
// inner arc
mCornerShadowPath.arcTo(innerBounds, 270f, -90f, false);
mCornerShadowPath.close();
float startRatio = mCornerRadius / (mCornerRadius + mShadowSize);
mCornerShadowPaint.setShader(new RadialGradient(0, 0, mCornerRadius + mShadowSize,
new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor},
new float[]{0f, startRatio, 1f}
, Shader.TileMode.CLAMP));
// we offset the content shadowSize/2 pixels up to make it more realistic.
// this is why edge shadow shader has some extra space
// When drawing bottom edge shadow, we use that extra space.
mEdgeShadowPaint.setShader(new LinearGradient(0, -mCornerRadius + mShadowSize, 0,
-mCornerRadius - mShadowSize,
new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor},
new float[]{0f, .5f, 1f}, Shader.TileMode.CLAMP));
mEdgeShadowPaint.setAntiAlias(false);
}
private void buildComponents(Rect bounds) {
// Card is offset SHADOW_MULTIPLIER * maxShadowSize to account for the shadow shift.
// We could have different top-bottom offsets to avoid extra gap above but in that case
// center aligning Views inside the CardView would be problematic.
final float verticalOffset = mRawMaxShadowSize * SHADOW_MULTIPLIER;
mCardBounds.set(bounds.left + mRawMaxShadowSize, bounds.top + verticalOffset,
bounds.right - mRawMaxShadowSize, bounds.bottom - verticalOffset);
buildShadowCorners();
}
float getCornerRadius() {
return mCornerRadius;
}
void getMaxShadowAndCornerPadding(Rect into) {
getPadding(into);
}
void setShadowSize(float size) {
setShadowSize(size, mRawMaxShadowSize);
}
void setMaxShadowSize(float size) {
setShadowSize(mRawShadowSize, size);
}
float getShadowSize() {
return mRawShadowSize;
}
float getMaxShadowSize() {
return mRawMaxShadowSize;
}
float getMinWidth() {
final float content = 2 *
Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow + mRawMaxShadowSize / 2);
return content + (mRawMaxShadowSize + mInsetShadow) * 2;
}
float getMinHeight() {
final float content = 2 * Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow
+ mRawMaxShadowSize * SHADOW_MULTIPLIER / 2);
return content + (mRawMaxShadowSize * SHADOW_MULTIPLIER + mInsetShadow) * 2;
}
public void setColor(int color) {
mPaint.setColor(color);
invalidateSelf();
}
static interface RoundRectHelper {
void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius, Paint paint);
}
}
So the problem was that I was drawing a rectangle ove the entire view. The rectangle needs to be drawn on a seperate view dedicated to the shadow effect.
Additionally, the shadow view should have a height no greater than 6dp, or the rectangle will show, if that makes sense.
One last note, use these values for density and elevation
float elevation = 2;
float density = getResources().getDisplayMetrics().density;
Here is my layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="info.androidhive.materialtabs.fragments.OneFragment">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="This Is A Fragment"
android:gravity="center"
android:textSize="40dp"
android:textStyle="bold"
android:layout_centerInParent="true"
android:layout_above="#+id/bottomView"/>
<View
android:id="#+id/bottomView"
android:layout_width="match_parent"
android:layout_height="6dp"
android:layout_above="#+id/other"/>
<View
android:id="#id/other"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="175dp"
android:background="?attr/colorPrimary"/>
</RelativeLayout>

Badge notification over drawer toggle in toolbar - Android

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?
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>
I know its late but still.
if you are using android Side Navigation Menu as a starter then there would be a file name app_bar_main.xml
in this file you'll see some code like below except for the TextView this TextView is responsible for showing badge just initialize it in MainActivity where you are initializing your Toolbar and change its visibility according to your need (visible when count is positive else gone) right now as you can see its visibility is gone
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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="com.thumbsol.beakns.activities.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<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/AppTheme.PopupOverlay"></android.support.v7.widget.Toolbar>
<TextView
android:id="#+id/hamburger_count"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginLeft="30dp"
android:layout_marginTop="-45dp"
android:background="#drawable/red_circle_bacground"
android:gravity="center"
android:text="10"
android:textColor="#android:color/white"
android:visibility="gone" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main" />
and here is the code of red_circle_bacground.xml put it in drawable
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#f00" />
<corners
android:bottomLeftRadius="30dp"
android:bottomRightRadius="30dp"
android:topLeftRadius="30dp"
android:topRightRadius="30dp" />
<size
android:height="25dp"
android:width="25dp"/>
</shape>
Based on the answer from TDSoft, you can shorten the procedure even further by extending DrawerArrowDrawable.
Step 1: (Except for DrawerArrowDrable, basically Same as TDSoft's Badge class).
public class BadgeNavigationDrawable extends DrawerArrowDrawable{
private float mTextSize;
private Paint mBadgePaint;
private Paint mBadgePaint1;
private Paint mTextPaint;
private Rect mTxtRect = new Rect();
private String mCount = "";
private boolean mWillDraw = false;
/**
* #param context used to get the configuration for the drawable from
*/
public BadgeNavigationDrawable(Context context) {
super(context);
setColor(context.getResources().getColor(R.color.accent));
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);
}
#Override
public void draw(Canvas canvas) {
super.draw(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;
}
private float dpToPx(Context context, float value) {
Resources r = context.getResources();
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, r.getDisplayMetrics());
return px;
}
}
Step 2: That is all you need, if you need to update your navigation drawer icon, call - Your events are all all preserved.
BadgeNavigationDrawable drawerIcon = new BadgeNavigationDrawable(MainActivity.this);
drawerIcon.setCount(String.valueOf(count));
mDrawerToggle.setDrawerArrowDrawable(drawerIcon);
mDrawerToggle.syncState();
I achive this by adding a TextView to my main layout with targeting the toggle.
in my mainactivity.xml I added this
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/badge_ham"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="26dp"
android:layout_marginTop="14dp"
android:textSize="9sp" />
</RelativeLayout>
and for adding badge:
private void addBadgeToHamburger(int badge){
badge_ham.setVisibility(View.VISIBLE);
String counter = Integer.toString(badge);
String s = " " + counter + " ";
SpannableString sColored = new SpannableString(s);
sColored.setSpan(new RoundedBackgroundSpan(Color.RED, Color.WHITE), s.length() - 3, s.length(), 0);
badge_ham.setText(sColored);
}

add a badge to ActionBar Home Icon

I need to add to the actionbar Home Button (Activity icon) a badge count.
i have a drawerLayout that opens when i press on the Home Button
i need to add a badge if a certain action took place.
i searched on how to add badge count to button but couldn't find what i want.(i know how to do this for an icon in menu.xml).
any help would be appreciated.
what i tried:
BitmapDrawable d1 = (BitmapDrawable) getResources().getDrawable(R.drawable.ic_launcher);
Drawable drawableArray[]= new Drawable[]{d1};
LayerDrawable layerDraw = new LayerDrawable(drawableArray);
NewMessageIcon.setBadgeCount(this,layerDraw,getActionBar(),3);
setbadgecountfunction:
public static void setBadgeCount(Context context, LayerDrawable icon, ActionBar action,int countunread) {
BadgeDrawable badge=null;
Drawable reuse;
reuse = icon.findDrawableByLayerId(R.id.ic_badge_fornewmessage);
if (reuse != null && reuse instanceof BadgeDrawable) {
reuse.invalidateSelf();
badge = (BadgeDrawable) reuse;
}
else {
badge = new BadgeDrawable(context);
}
badge.setCount(countunread);
if (countunread>0)
{
badge.mBadgePaint.setColor(Color.parseColor("#F00000"));
}
else
{
badge.mBadgePaint.setColor(Color.parseColor("#ffae19"));
}
icon.mutate();
icon.setDrawableByLayerId(R.id.ic_badge_fornewmessage, badge);
action.setIcon(icon); /////SHOULD CHANGE BUT NOT CHANGING!
}
badge class (I USED THIS CLASS FOR AN ICON IN MENU.XML AND ITS WORKING FINE)
public class BadgeDrawable extends Drawable {
private float mTextSize;
public 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); //GET THE PREDIFINED TEXT SIZE
//FOR THE CIRCLE
mBadgePaint = new Paint();
mBadgePaint.setColor(Color.parseColor("#ffae19"));
mBadgePaint.setAntiAlias(true);
mBadgePaint.setStyle(Paint.Style.FILL);
//FOR THE NUMBER WITHIN THE CIRCLE
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;
}
CREATING THE CIRCLE SHAPE
Rect bounds = getBounds();
//float width = bounds.right - bounds.left;
//float height = bounds.bottom - bounds.top;
float width = (bounds.right - bounds.left) + 20;
float height = (bounds.bottom - bounds.top) + 20;
// 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;
}
}
ic_menu_newmessage.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/ic_newmessage_notification"
android:drawable="#drawable/ic_launcher"
android:gravity="center" />
<item
android:id="#+id/ic_badge_fornewmessage"
android:drawable="#drawable/ic_launcher" />
</layer-list>

Categories

Resources