Android实现消息提醒小红点效果

本人分享一下,自己写的一个消息提醒小红点控件,支持圆、矩形、椭圆、圆角矩形、正方形五种图形样式,可带文字,支持链式操作。

先看一下实现效果,随便测了几个控件(TextView、ImageView、RadioButton、LinearLayout、RelativeLayout、FrameLayout),不确定其他会不会有问题。

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TabWidget; 

public class BadgeView extends View {
 protected static final String LOG_TAG = "BadgeView";
 // 该控件的背景图形类型
 public static final int SHAPE_CIRCLE = 1;
 public static final int SHAPE_RECTANGLE = 2;
 public static final int SHAPE_OVAL = 3;
 public static final int SHAPTE_ROUND_RECTANGLE = 4;
 public static final int SHAPE_SQUARE = 5;
 // 该框架内容的文本画笔
 private Paint mTextPaint;
 // 该控件的背景画笔
 private Paint mBgPaint; 

 private int mHeight = 0;
 private int mWidth = 0;
 private int mBackgroundShape = SHAPE_CIRCLE;
 private int mTextColor = Color.WHITE;
 private int mTextSize;
 private int mBgColor = Color.RED;
 private String mText = "";
 private int mGravity = Gravity.RIGHT | Gravity.TOP;
 private RectF mRectF;
 private float mtextH;
 private boolean mIsShow = false; 

 public BadgeView(Context context) {
 this(context, null);
 } 

 public BadgeView(Context context, AttributeSet attrs) {
 this(context, attrs, 0);
 } 

 public BadgeView(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr); 

 mRectF = new RectF(); 

 mTextSize = dip2px(context, 1);
 mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mTextPaint.setColor(mTextColor);
 mTextPaint.setStyle(Paint.Style.FILL);
 mTextPaint.setTextSize(mTextSize);
 mTextPaint.setTextAlign(Paint.Align.CENTER);
 mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 mBgPaint.setColor(mBgColor);
 mBgPaint.setStyle(Paint.Style.FILL);
 FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
  FrameLayout.LayoutParams.WRAP_CONTENT,
  FrameLayout.LayoutParams.WRAP_CONTENT);
 params.gravity = mGravity;
 setLayoutParams(params);
 } 

 @Override
 protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 mRectF.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
 Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
 mtextH = fontMetrics.descent - fontMetrics.ascent;
 switch (mBackgroundShape) {
  case SHAPE_CIRCLE:
  canvas.drawCircle(getMeasuredWidth() / 2f,
   getMeasuredHeight() / 2f, getMeasuredWidth() / 2, mBgPaint);
  canvas.drawText(mText, getMeasuredWidth() / 2f, getMeasuredHeight()
   / 2f + (mtextH / 2f - fontMetrics.descent), mTextPaint);
  break;
  case SHAPE_OVAL: 

  canvas.drawOval(mRectF, mBgPaint);
  canvas.drawText(mText, getMeasuredWidth() / 2f, getMeasuredHeight()
   / 2f + (mtextH / 2f - fontMetrics.descent), mTextPaint);
  break;
  case SHAPE_RECTANGLE:
  canvas.drawRect(mRectF, mBgPaint);
  canvas.drawText(mText, getMeasuredWidth() / 2f, getMeasuredHeight()
   / 2f + (mtextH / 2f - fontMetrics.descent), mTextPaint);
  break;
  case SHAPE_SQUARE:
  int sideLength = Math.min(getMeasuredHeight(), getMeasuredWidth());
  mRectF.set(0, 0, sideLength, sideLength);
  canvas.drawRect(mRectF, mBgPaint);
  canvas.drawText(mText, sideLength / 2f, sideLength / 2f
   + (mtextH / 2f - fontMetrics.descent), mTextPaint);
  break;
  case SHAPTE_ROUND_RECTANGLE:
  canvas.drawRoundRect(mRectF, dip2px(getContext(), getMeasuredWidth()/2),
   dip2px(getContext(), getMeasuredWidth()/2), mBgPaint);
  canvas.drawText(mText, getMeasuredWidth() / 2f, getMeasuredHeight()
   / 2f + (mtextH / 2f - fontMetrics.descent), mTextPaint);
  break;
 } 

 } 

 /**
 * 设置该控件的背景颜色
 *
 * @param color
 *  背景颜色
 * @return BadgeView
 */
 public BadgeView setBadgeBackgroundColor(int color) {
 mBgColor = color;
 mBgPaint.setColor(color);
 invalidate();
 return this;
 } 

 /**
 * 设置该控件的背景图形
 *
 * @param shape
 *  图形
 * @return
 */
 public BadgeView setBackgroundShape(int shape) {
 mBackgroundShape = shape;
 invalidate();
 return this;
 } 

 /**
 * 设置该控件的宽
 *
 * @param width
 *  宽
 * @return BadgeView
 */
 public BadgeView setWidth(int width) {
 this.mWidth = width;
 this.setBadgeLayoutParams(width, mHeight);
 return this; 

 } 

 /**
 * 设置该控件的高
 *
 * @param height
 *  高
 * @return BadgeView
 */
 public BadgeView setHeight(int height) {
 this.mHeight = height;
 this.setBadgeLayoutParams(mWidth, height);
 return this;
 } 

 /**
 * 设置该控件的高和宽
 *
 * @param width
 *  宽
 * @param height
 *  高
 * @return
 */
 public BadgeView setBadgeLayoutParams(int width, int height) {
 this.mWidth = width;
 this.mHeight = height;
 FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
 params.width = dip2px(getContext(), width);
 params.height = dip2px(getContext(), height);
 setLayoutParams(params);
 return this;
 } 

 /**
 * 设置该控件的位置
 *
 * @param gravity
 *  位置
 * @return BadgeView
 */
 public BadgeView setBadgeGravity(int gravity) {
 mGravity = gravity;
 FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
 params.gravity = gravity;
 setLayoutParams(params);
 return this;
 } 

 /**
 * 设置该控件的高和宽、位置
 *
 * @param width
 *  宽
 * @param height
 *  高
 * @param gravity
 *  位置
 * @return BadgeView
 */
 public BadgeView setBadgeLayoutParams(int width, int height, int gravity) {
 FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
 params.width = dip2px(getContext(), width);
 params.height = dip2px(getContext(), height);
 setLayoutParams(params);
 setBadgeGravity(gravity);
 return this;
 } 

 /**
 * 设置该控件的文本大小
 *
 * @param size
 *  文本大小(sp)
 * @return
 */
 public BadgeView setTextSize(int size) {
 mTextSize = sp2px(getContext(), size);
 mTextPaint.setTextSize(sp2px(getContext(), size));
 invalidate();
 return this;
 } 

 /**
 * 设置该控件的文本颜色
 *
 * @param color
 *  文本颜色
 * @return BadgeView
 */
 public BadgeView setTextColor(int color) {
 mTextColor = color;
 mTextPaint.setColor(color);
 invalidate();
 return this;
 } 

 /**
 * 设置该控件的文本是否为粗体
 *
 * @param flag
 */
 public void setBadgeBoldText(boolean flag) {
 mTextPaint.setFakeBoldText(flag);
 invalidate();
 } 

 /**
 * 设置该控件要显示的整数文本
 *
 * @param count
 *  要显示的整数文本
 * @return BadgeView
 */
 public BadgeView setBadgeText(int count) {
 mText = String.valueOf(count);
 invalidate();
 return this;
 } 

 /**
 * 设置该控件要显示的整数文本数字,超过指定上限显示为指定的上限内容
 *
 * @param count
 *  要显示的整数文本
 * @param maxCount
 *  数字上限
 * @param text
 *  超过上限要显示的字符串文本
 * @return BadgeView
 */
 public BadgeView setBadgeText(int count, int maxCount, String text) {
 if (count <= maxCount) {
  mText = String.valueOf(count);
 } else {
  mText = text;
 }
 invalidate();
 return this;
 } 

 /**
 * 设置该控件要显示的字符串文本
 *
 * @param text
 *  要显示的字符串文本
 * @return BadgeView
 */
 public BadgeView setBadgeText(String text) {
 mText = text;
 invalidate();
 return this;
 } 

 /**
 * 设置绑定的控件
 *
 * @param view
 *  要绑定的控件
 * @return BadgeView
 */
 public BadgeView setBindView(View view) {
 mIsShow = true;
 if (getParent() != null)
  ((ViewGroup) getParent()).removeView(this);
 if (view == null)
  return this;
 if (view.getParent() instanceof FrameLayout) {
  ((FrameLayout) view.getParent()).addView(this);
 } else if (view.getParent() instanceof ViewGroup) {
  ViewGroup parentContainer = (ViewGroup) view.getParent();
  int viewIndex = ((ViewGroup) view.getParent()).indexOfChild(view);
  ((ViewGroup) view.getParent()).removeView(view);
  FrameLayout container = new FrameLayout(getContext());
  ViewGroup.LayoutParams containerParams = view.getLayoutParams();
  container.setLayoutParams(containerParams);
  container.setId(view.getId());
  view.setLayoutParams(new ViewGroup.LayoutParams(
   ViewGroup.LayoutParams.MATCH_PARENT,
   ViewGroup.LayoutParams.MATCH_PARENT));
  container.addView(view);
  container.addView(this);
  parentContainer.addView(container, viewIndex);
 } else if (view.getParent() == null) {
  Log.e(LOG_TAG, "View must have a parent");
 }
 return this;
 } 

 /**
 * 设置绑定的控件
 *
 * @param view 要绑定的控件
 * @param tabIndex 要绑定的控件的子项
 */
 public void setBindView(TabWidget view, int tabIndex) {
 View tabView = view
  .getChildTabViewAt(tabIndex);
 this.setBindView(tabView);
 } 

 /**
 * 移除绑定的控件
 *
 * @return BadgeView
 */
 public boolean removebindView() {
 if (getParent() != null) {
  mIsShow = false;
  ((ViewGroup) getParent()).removeView(this);
  return true;
 }
 return false;
 } 

 /**
 * @return 改控件的显示状态
 */
 public boolean isShow() {
 return mIsShow;
 } 

 /**
 * @return 控件的字符串文本
 */
 public String getBadgeText() {
 return mText;
 } 

 private int dip2px(Context context, int dip) {
 return (int) (dip
  * getContext().getResources().getDisplayMetrics().density + 0.5f);
 } 

 private int sp2px(Context context, float spValue) {
 final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
 return (int) (spValue * fontScale + 0.5f);
 } 

} 

可自由定制自己喜欢的控件,为了方便使用这里还采用工厂模式封装一些基本方法,如下:

import android.content.Context;
import android.view.Gravity; 

public class BadgeFactory { 

 public static BadgeView create(Context context) {
 return new BadgeView(context);
 } 

 public static BadgeView createDot(Context context) {
 return new BadgeView(context).setBadgeLayoutParams(10, 10)
  .setTextSize(0)
  .setBadgeGravity(Gravity.RIGHT | Gravity.TOP)
  .setBackgroundShape(BadgeView.SHAPE_CIRCLE);
 } 

 public static BadgeView createCircle(Context context) {
 return new BadgeView(context).setBadgeLayoutParams(16, 16)
  .setTextSize(12)
  .setBadgeGravity(Gravity.RIGHT | Gravity.TOP)
  .setBackgroundShape(BadgeView.SHAPE_CIRCLE);
 } 

 public static BadgeView createRectangle(Context context) {
 return new BadgeView(context).setBadgeLayoutParams(2, 20)
  .setTextSize(12)
  .setBadgeGravity(Gravity.RIGHT | Gravity.TOP)
  .setBackgroundShape(BadgeView.SHAPE_RECTANGLE);
 } 

 public static BadgeView createOval(Context context) {
 return new BadgeView(context).setBadgeLayoutParams(25, 20)
  .setTextSize(12)
  .setBadgeGravity(Gravity.RIGHT | Gravity.TOP)
  .setBackgroundShape(BadgeView.SHAPE_OVAL);
 } 

 public static BadgeView createSquare(Context context) {
 return new BadgeView(context).setBadgeLayoutParams(20, 20)
  .setTextSize(12)
  .setBadgeGravity(Gravity.RIGHT | Gravity.TOP)
  .setBackgroundShape(BadgeView.SHAPE_SQUARE);
 } 

 public static BadgeView createRoundRect(Context context) {
 return new BadgeView(context).setBadgeLayoutParams(25, 20)
  .setTextSize(12)
  .setBadgeGravity(Gravity.RIGHT | Gravity.TOP)
  .setBackgroundShape(BadgeView.SHAPTE_ROUND_RECTANGLE);
 } 

}

源码下载:Android实现消息提醒小红点

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android高仿微信5.2.1主界面及消息提醒

    好久没更新博客了,最近在做公司的项目,这也算是我接触的第一个正式项目.通过项目的检验,发现自己积累了一年的知识还是远远不够,想要提高,好的方法是 :项目+书+视频+博客.最重要一点:勤动手.最近发现了慕课网的视频,居然都是高清无码免费的!而且满满的干货!我用业余时间跟着视频中大神的讲解学习了不少知识,下面就将这些小demo与大家分享,当然,我做了一些优化,代码与视频中有些出入,但功能可以完全实现. 这是一个模仿5.2.1版本的显示界面,如下图所示: 功能及实现思路简介 主要功能很简单: 1.上面

  • Android实现消息提醒小红点效果

    本人分享一下,自己写的一个消息提醒小红点控件,支持圆.矩形.椭圆.圆角矩形.正方形五种图形样式,可带文字,支持链式操作. 先看一下实现效果,随便测了几个控件(TextView.ImageView.RadioButton.LinearLayout.RelativeLayout.FrameLayout),不确定其他会不会有问题. import android.content.Context; import android.graphics.Canvas; import android.graphic

  • Android使用贝塞尔曲线仿QQ聊天消息气泡拖拽效果

    本文实例为大家分享了Android仿QQ聊天消息气泡拖拽效果展示的具体代码,供大家参考,具体内容如下 先画圆,都会吧.代码如下: public class Bezier extends View { private final Paint mGesturePaint = new Paint(); private final Path mPath = new Path(); private float mX1 = 100, mY1 = 150; private float mX2 = 300, m

  • Asp.net使用SignalR实现消息提醒

    一.引言 前面一篇文章我介绍了如何使用SignalR实现图片的传输,然后对于即时通讯应用来说,消息提醒是必不可少的.现在很多网站的都有新消息的提醒功能.自然对于SignalR系列也少不了这个功能的实现了.在这篇文章中将介绍如何使用SignalR+iNotify库来实现新消息的声音和弹框提醒. 二.消息提醒的实现思路 消息提醒也就是当客户有新消息来时,在客户端的右下角进行弹框提醒.要实现这个功能的思路是: 1.SignalR服务端推送消息到客户端的实现方式为调用客户端的receiveMessage

  • PHP实现RTX发送消息提醒的实例代码

    RTX是腾讯公司推出的企业级即时通信平台,大多数公司都在使用它,但是我们很多时候需要将自己系统或者产品的一些通知实时推送给RTX,这就需要用到RTX的服务端SDK,建议先去看看RTX的SDK开发文档(客户端,服务器),我们先看看功能效果:    当然,现在很多公司都已经在RTX的基础上升级成了企业微信,没关系,这个API同样可以使用,还是同样的接口,只是展示效果不一样而已: 下面是用PHP实现RTX发送消息提醒: 1.首先在服务器端安装RTX的服务端和客户端,再安装SDK开发包(对于发送消息提醒

  • Android利用CountDownTimer实现验证码倒计时效果实例

    前言 等待总是让人感到焦急和厌烦的,特别是看不到进展的等待.所以为了不让用户痴痴地等,我们在进行某些耗时操作时,一般都要设计一个进度条或者倒计时器,让进度可视化,告诉用户"等待之后更精彩".在使用短信验证码注册或者登录App就可以看到这样的设计:点击"发送验证码"的按钮之后,按钮上就会出现倒计时(一般为60秒),倒计时结束之后,按钮的文字就会变成"重新发送". 在Android中要实现这样的效果可以使用Handler发送消息,但其实还有一个已经封

  • Android仿斗鱼直播的弹幕效果

    记得之前有位朋友在我的公众号里问过我,像直播的那种弹幕功能该如何实现?如今直播行业确实是非常火爆啊,大大小小的公司都要涉足一下直播的领域,用斗鱼的话来讲,现在就是千播之战.而弹幕则无疑是直播功能当中最为重要的一个功能之一,那么今天,我就带着大家一起来实现一个简单的Android端弹幕效果. 分析 首先我们来看一下斗鱼上的弹幕效果,如下图所示: 这是一个Dota2游戏直播的界面,我们可以看到,在游戏界面的上方有很多的弹幕,看直播的观众们就是在这里进行讨论的. 那么这样的一个界面该如何实现呢?其实并

  • Android实现上下菜单双向滑动效果

    这是研究了网上大神双向左右滑动后实现的上下双向滑动特效,有兴趣的朋友可以看下面代码,注释很详细,原理就是根据手指滑动的方向,来将上下两个布局进行显示与隐藏.主要用了onTouch方法,获取滑动的距离进行偏移. import android.content.Context; import android.os.AsyncTask; import android.util.AttributeSet; import android.view.MotionEvent; import android.vi

  • Android编程实现通知栏进度条效果的方法示例

    本文实例讲述了Android编程实现通知栏进度条效果的方法.分享给大家供大家参考,具体如下: /** * 通知管理工具类 * * @description: * @author ldm * @date 2016-5-3 上午9:39:56 */ public class NotificationUtil { private Context mContext; // NotificationManager : 是状态栏通知的管理类,负责发通知.清楚通知等. private Notification

  • Android仿微信长按菜单效果

    本文实例为大家分享了Android仿微信长按菜单展示的具体代码,供大家参考,具体内容如下 FloatMenu A menu style pop-up window that mimics WeChat.仿微信的长按菜单. 效果如下 引入方法: Github地址:https://github.com/JavaNoober/FloatMenu dependencies { .... compile 'com.noober.floatmenu:common:1.0.2' } 使用说明 使用方法1: A

随机推荐