Android如何仿QQ微信未读消息小红点BadgeHelper
发表于:2024-12-12 作者:千家信息网编辑
千家信息网最后更新 2024年12月12日,这篇文章给大家分享的是有关Android如何仿QQ微信未读消息小红点BadgeHelper的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Android 小红点 未读消息功能
千家信息网最后更新 2024年12月12日Android如何仿QQ微信未读消息小红点BadgeHelper
这篇文章给大家分享的是有关Android如何仿QQ微信未读消息小红点BadgeHelper的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
Android 小红点 未读消息功能 BadgeHelper
因为最近的项目需求,翻遍github上的未读消息红点开源库, 发现大部分
不能适配不同情况的布局, 所以我写了一个能兼容全部的 !
网上的写法是 继承TextView然后生成一个小红点drawable,设置到背景中去, 然后把目标view外层加一层FrameLayout,然后把小红点添加进去
但这样做的问题来了, 小红点与目标View 会叠起来!, 挡住文字,!!! 看得我瞎了~~~ 而且 他们提供的setOffsetX setpadding 之类的没卵用,你如果想要偏移小红点让它不与下面的View重叠,那是不可能的
所以我的写法是 为了更好的性能,直接继承View然后画小红点背景, 然后把目标view外层加一层LinearLayout 让小红点View放目标的右边,这样就不会重叠
同时 我也支持设置 重叠模式和非重叠模式
这是效果图
由于github账号出问题了,没法上传, 所以写到博客上算了
这只是一个小工具类 供大家学习下我的思路, 就不多说了, 具体实现注释里写的很清楚,不太清楚的可以回复问我
#核心类:
##BadgeHelper .java
package com.truescend.gofit.views;import android.content.Context;import android.content.res.Resources;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.RectF;import android.support.annotation.IntDef;import android.support.design.widget.TabLayout;import android.util.Log;import android.util.TypedValue;import android.view.Gravity;import android.view.View;import android.view.ViewGroup;import android.widget.FrameLayout;import android.widget.LinearLayout;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.reflect.Field;/** * 作者:东芝(2018/8/23). * 支持 重叠目标模式 和 放目标右上角但不重叠的模式 两种模式 通过setOverlap 设置, 默认为false=不重叠 */public class BadgeHelper extends View { private static final String TAG = "BadgeHelper"; private float density; private Paint mTextPaint; private Paint mBackgroundPaint; private String text = "0"; private int number; @Type private int type = Type.TYPE_POINT; private boolean isOverlap; private final RectF rect = new RectF(); private int badgeColor = 0xFFD3321B; //默认的小红点颜色 private int textColor = 0xFFFFFFff; private float textSize; private int w; private int h; private boolean isSetup; private boolean mIgnoreTargetPadding; private boolean isCenterVertical; private int leftMargin; private int topMargin; private int rightMargin; private int bottomMargin; @IntDef({Type.TYPE_POINT, Type.TYPE_TEXT}) @Retention(RetentionPolicy.SOURCE) public @interface Type { int TYPE_POINT = 0; int TYPE_TEXT = 1; } public BadgeHelper(Context context) { super(context); } private void init(@Type int type, boolean isOverlap) { this.type = type; this.isOverlap = isOverlap; density = getResources().getDisplayMetrics().density; switch (type) { case Type.TYPE_POINT: mBackgroundPaint = new Paint(); mBackgroundPaint.setStyle(Paint.Style.FILL); mBackgroundPaint.setFlags(Paint.ANTI_ALIAS_FLAG); mBackgroundPaint.setColor(badgeColor); //计算小红点无文本情况下的小红点大小, 按屏幕像素计算, 如果你有你自己认为更好的算法, 改这里即可 w = h = Math.round(density * 7f); break; case Type.TYPE_TEXT: mBackgroundPaint = new Paint(); mBackgroundPaint.setStyle(Paint.Style.FILL); mBackgroundPaint.setFlags(Paint.ANTI_ALIAS_FLAG); mBackgroundPaint.setColor(badgeColor); mTextPaint = new Paint(); mTextPaint.setStyle(Paint.Style.FILL); mTextPaint.setFlags(Paint.ANTI_ALIAS_FLAG); mTextPaint.setColor(textColor);//文本颜色 if (textSize == 0) { mTextPaint.setTextSize(density * 10);//文本大小按屏幕像素 计算, 没写死是为了适配各种屏幕, 但如果你有你认为更合理的计算方式 你可以改这里 } else { mTextPaint.setTextSize(textSize);//使用自定义大小 } //计算小红点有文本情况下的小红点大小, 按文本宽高计算, 如果你有你自己认为更好的算法, 改这里即可 float textWidth = getTextWidth("99", mTextPaint); w = h = Math.round(textWidth * 1.4f);//让背景比文本大一点 break; } } /** * 设置Margin 可用于做偏移 * @param left * @param top * @param right * @param bottom * @return */ public BadgeHelper setBadgeMargins(int left, int top, int right, int bottom) { leftMargin = left; topMargin = top; rightMargin = right; bottomMargin = bottom; return this; } /** * 设置Gravity居中 * @return */ public BadgeHelper setBadgeCenterVertical( ) { isCenterVertical = true; return this; } /** * 设置小红点类型 * * @param type * @return */ public BadgeHelper setBadgeType(@Type int type) { this.type = type; return this; } /** * 设置小红点大小, 默认自动适配 * * @param textSize * @return */ public BadgeHelper setBadgeTextSize(int textSize) { Context c = getContext(); Resources r; if (c == null) { r = Resources.getSystem(); } else { r = c.getResources(); } this.textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, textSize, r.getDisplayMetrics()); return this; } /** * 设置小红点文字颜色, 默认白 * * @param textColor * @return */ public BadgeHelper setBadgeTextColor(int textColor) { this.textColor = textColor; return this; } /** * 设置重叠模式, 默认是false(不重叠) * * @param isOverlap 是否把小红点重叠到目标View之上 * @return */ public BadgeHelper setBadgeOverlap(boolean isOverlap) { return setBadgeOverlap(isOverlap, false); } /** * 设置重叠模式, 默认是false(不重叠) * * @param isOverlap 是否把小红点重叠到目标View之上 * @param isIgnoreTargetPadding 是否忽略目标View的padding * @return */ public BadgeHelper setBadgeOverlap(boolean isOverlap, boolean isIgnoreTargetPadding) { this.isOverlap = isOverlap; this.mIgnoreTargetPadding = isIgnoreTargetPadding; if (!isOverlap && isIgnoreTargetPadding) { Log.w(TAG, "警告:只有重叠模式isOverlap=true 设置mIgnoreTargetPadding才有意义"); } return this; } /** * 设置小红点颜色 * * @param mBadgeColor * @return */ public BadgeHelper setBadgeColor(int mBadgeColor) { this.badgeColor = mBadgeColor; return this; } /** * 设置小红点大小 * * @param w * @param h * @return */ public BadgeHelper setBadgeSize(int w, int h) { this.w = w; this.h = h; return this; } /** * 是否显示 * @param enable */ public void setBadgeEnable(boolean enable) { setVisibility(enable?VISIBLE:INVISIBLE); } /** * 设置小红点的文字 * * @param number */ public void setBadgeNumber(int number) { this.number = number; this.text = String.valueOf(number); if (isSetup) { if(number==0){ setVisibility(INVISIBLE); }else{ setVisibility(VISIBLE); } invalidate(); } } public void bindToTargetView(TabLayout target, int tabIndex) { TabLayout.Tab tab = target.getTabAt(tabIndex); View targetView = null; View tabView = null; try { Field viewField = TabLayout.Tab.class.getDeclaredField("mView"); viewField.setAccessible(true); targetView = tabView = (View) viewField.get(tab); } catch (Exception e) { e.printStackTrace(); } try { if (tabView != null) { Field mTextViewField = tabView.getClass().getDeclaredField("mTextView");//"mIconView" mTextViewField.setAccessible(true); targetView = (View) mTextViewField.get(tabView); } } catch (Exception e) { e.printStackTrace(); } if (targetView != null) { bindToTargetView(targetView); } } /** * 绑定小红点到目标View的右上角 * * @param target */ public void bindToTargetView(View target) { init(type, isOverlap); if (getParent() != null) { ((ViewGroup) getParent()).removeView(this); } if (target == null) { return; } if (target.getParent() instanceof ViewGroup) { ViewGroup parent = (ViewGroup) target.getParent(); int groupIndex = parent.indexOfChild(target); parent.removeView(target); if (isOverlap) {//[小红点与目标View重叠]模式 FrameLayout badgeContainer = new FrameLayout(getContext()); ViewGroup.LayoutParams targetLayoutParams = target.getLayoutParams(); badgeContainer.setLayoutParams(targetLayoutParams); target.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); parent.addView(badgeContainer, groupIndex, targetLayoutParams); badgeContainer.addView(target); badgeContainer.addView(this); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) getLayoutParams(); if(isCenterVertical) { layoutParams.gravity = Gravity.CENTER_VERTICAL ; }else{ layoutParams.gravity = Gravity.END | Gravity.TOP; } if (mIgnoreTargetPadding) { layoutParams.rightMargin = target.getPaddingRight() - w; layoutParams.topMargin = target.getPaddingTop() - h / 2; } setLayoutParams(layoutParams); } else {//[小红点放右侧]模式 LinearLayout badgeContainer = new LinearLayout(getContext()); badgeContainer.setOrientation(LinearLayout.HORIZONTAL); ViewGroup.LayoutParams targetLayoutParams = target.getLayoutParams(); badgeContainer.setLayoutParams(targetLayoutParams); target.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); parent.addView(badgeContainer, groupIndex, targetLayoutParams); badgeContainer.addView(target); badgeContainer.addView(this); if(isCenterVertical) { badgeContainer.setGravity(Gravity.CENTER_VERTICAL); } } boolean hasSetMargin = leftMargin>0||topMargin>0||rightMargin>0||bottomMargin>0; if (hasSetMargin&&getLayoutParams() instanceof ViewGroup.MarginLayoutParams) { ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) getLayoutParams(); p.setMargins(leftMargin, topMargin, rightMargin, bottomMargin); setLayoutParams(p); } isSetup = true; } else if (target.getParent() == null) { throw new IllegalStateException("目标View不能没有父布局!"); } if(number==0){ setVisibility(INVISIBLE); }else{ setVisibility(VISIBLE); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (w > 0 && h > 0) { setMeasuredDimension(w, h); } else { throw new IllegalStateException("如果你自定义了小红点的宽高,就不能设置其宽高小于0 ,否则请不要设置!"); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //这里不用解释了 很简单 就是画一个圆形和文字 rect.left = 0; rect.top = 0; rect.right = getWidth(); rect.bottom = getHeight(); canvas.drawRoundRect(rect, getWidth() / 2, getWidth() / 2, mBackgroundPaint); if (type == Type.TYPE_TEXT) { float textWidth = getTextWidth(text, mTextPaint); float textHeight = getTextHeight(text, mTextPaint); canvas.drawText(text, getWidth() / 2 - textWidth / 2, getHeight() / 2 + textHeight / 2, mTextPaint); } } private float getTextWidth(String text, Paint p) { return p.measureText(text, 0, text.length()); } private float getTextHeight(String text, Paint p) { Rect rect = new Rect(); p.getTextBounds(text, 0, text.length(), rect); return rect.height(); }}
#使用示例:
public class Main2Activity extends AppCompatActivity { private TextView mVTypeA; private TextView mVTypeB; private TextView mVTypeC; private TextView mVTypeD; private ImageView mVTypeE; private TabLayout mTabLayout; private void initView() { mVTypeA = (TextView) findViewById(R.id.vTypeA); mVTypeB = (TextView) findViewById(R.id.vTypeB); mVTypeC = (TextView) findViewById(R.id.vTypeC); mVTypeD = (TextView) findViewById(R.id.vTypeD); mVTypeE = (ImageView) findViewById(R.id.vTypeE); mTabLayout = (TabLayout) findViewById(R.id.tabLayout); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); initView(); //情况A(有margin时) new BadgeHelper(this) .setBadgeType(BadgeHelper.Type.TYPE_POINT) .setBadgeOverlap(false) .bindToTargetView(mVTypeA); //情况B(有padding时) new BadgeHelper(this) .setBadgeType(BadgeHelper.Type.TYPE_POINT) .setBadgeOverlap(true, true)//重叠模式+忽略目标ViewPadding 效果, 什么意思? 你可以把第二个参数写成false看看会发生什么 .bindToTargetView(mVTypeB); //情况C(默认情况) BadgeHelper badgeHelperC = new BadgeHelper(this) .setBadgeType(BadgeHelper.Type.TYPE_TEXT) .setBadgeOverlap(false); badgeHelperC.bindToTargetView(mVTypeC); badgeHelperC.setBadgeNumber(6);//数字模式 //情况D(有权重时) new BadgeHelper(this) .setBadgeColor(0xff0f00ff)//顺便演示下 小红点颜色的设置 .setBadgeType(BadgeHelper.Type.TYPE_POINT) .setBadgeOverlap(false) .bindToTargetView(mVTypeD); //情况E(小红点与图片重叠)+ 数字模式 BadgeHelper badgeHelperE = new BadgeHelper(this) .setBadgeType(BadgeHelper.Type.TYPE_TEXT) .setBadgeOverlap(true, true);//注意 isIgnoreTargetPadding=true时 和 setBadgeMargins 不能同时使用 //.setBadgeSize(100,100)//设置小红点的大小, 如果未设置则使用默认宽高, 一般默认就好 //.setBadgeTextSize(15) //设置文本大小, 不设置 则使用默认, 一般默认就好 badgeHelperE.bindToTargetView(mVTypeE); //任意地方可以刷新数字 badgeHelperE.setBadgeNumber(58);//数字 //情况F(TabLayout兼容) BadgeHelper badgeHelperF = new BadgeHelper(this) .setBadgeType(BadgeHelper.Type.TYPE_TEXT) .setBadgeCenterVertical()//红点居中 .setBadgeMargins(10,0,0,0)//偏移一下 .setBadgeOverlap(false); badgeHelperF.bindToTargetView(mTabLayout, 0); badgeHelperF.setBadgeNumber(5); new BadgeHelper(this) .setBadgeType(BadgeHelper.Type.TYPE_POINT) .setBadgeCenterVertical()//红点居中 .setBadgeMargins(10,0,0,0)//偏移一下 .setBadgeOverlap(false) .bindToTargetView(mTabLayout,1); }}
#布局:
感谢各位的阅读!关于"Android如何仿QQ微信未读消息小红点BadgeHelper"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!
小红
模式
目标
情况
大小
文本
颜色
消息
数字
文字
偏移
屏幕
布局
背景
红点
适配
像素
内容
写法
同时
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
数据库加速设备
甘肃政法大学网络安全学院
CF刷枪会不会使服务器崩溃
茂名招聘网络安全工程师信息
成都萌果果软件开发
使命召唤登入服务器连接已中断
安卓 数据库开发
数据库实验报告 华科
湖北安防数显钟服务器云服务器
阿冰团队网络技术部
和人口有关的微观数据库
sql2008脚本还原数据库
网络技术公司发票内容
lotus邮箱数据库怎么存本地
湖州电脑软件开发教程
软件开发有限公司股东
螺旋模型 软件开发
地下数据库
做软件开发的笔记本屏幕要多大
知科技互联网运营是干嘛的
BT盒子服务器码
安宁哪有定制软件开发
边缘计算网络安全深信服
瞬联软件开发是外包吗
网络安全进校园我们一直在行动
服务器2016硬盘怎么分区
安卓软件开发框架源码
数据库aqt啥意思
国家网络安全日的由来
网络安全法宣传专页