# Android Widget: 显示消息数量的徽标
分析:
- 自定义 RelativeLayout 布局控件
- 按需求绘制 徽标气泡的显示 与 隐藏
- 设置自定义参数
# 动手 搞一下
- 创建 BadgeView类 继承 RelativeLayout 类
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);
init(context, attrs);
}
- 定义样式 参数
private void init(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.BadgeView);
//徽标显示的数字
mBadgeText = array.getString(R.styleable.BadgeView_badgeText);
//徽标背景颜色
mBadgeBgcolor = array.getColor(R.styleable.BadgeView_badgeBgColor, 0);
//徽标边框颜色
mBadgeBordercolor = array.getColor(R.styleable.BadgeView_badgeBorderColor, 0);
//徽标字体颜色
mBadgeTextcolor = array.getColor(R.styleable.BadgeView_badgeTextColor, 0);
//徽标边框宽度
mBorderWidth = (int) array.getDimension(R.styleable.BadgeView_badgeBorderWidth, 0);
//徽标字体大小
mBadgeTextSize = (int) array.getDimension(R.styleable.BadgeView_badgeTextSize, DEF_TEXT_SIZE);
//徽章显示位置
<!--徽章显示的位置-->
<attr name="badgeAnchorPosition">
<enum name="AnchorLeftTop" value="0" />
<enum name="AnchorLeftBottom" value="1" />
<enum name="AnchorRightTop" value="2" />
<enum name="AnchorRightBottom" value="3" />
</attr>
mBadgeAnchorPosition = array.getInt(R.styleable.BadgeView_badgeAnchorPosition, 2);
// 横向 间距
mMarginHorizon = (int) array.getDimension(R.styleable.BadgeView_badgeMarginHorizon, 0);
// 竖向间距
mMarginVertical = (int) array.getDimension(R.styleable.BadgeView_badgeMarginVertical, 0);
//内边距 横向
mPaddingH = array.getDimension(R.styleable.BadgeView_badgePaddingHorizon, DEF_HORIZON_PADDING) * 2 + mBorderWidth;
//内边距 竖向
mPaddingV = array.getDimension(R.styleable.BadgeView_badgePaddingVertical, DEF_VERTICAL_PADDING) * 2 + mBorderWidth;
array.recycle();
//徽标字体画笔
mBadgeTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBadgeTextPaint.setTextSize(mBadgeTextSize);
mBadgeTextPaint.setColor(mBadgeTextcolor);
//徽标背景画笔
mBadgeBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBadgeBgPaint.setColor(mBadgeBgcolor);
mBadgeBgPaint.setStyle(Paint.Style.FILL);
//边框描边画笔
mBadgeBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBadgeBorderPaint.setStyle(Paint.Style.STROKE);
mBadgeBorderPaint.setColor(mBadgeBordercolor);
mBadgeBorderPaint.setStrokeWidth(mBorderWidth);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
drawBadge(canvas);
}
private void drawBadge(Canvas canvas) {
if (TextUtils.isEmpty(mBadgeText)) {
return;
}
Paint.FontMetrics metrics = mBadgeTextPaint.getFontMetrics();
float textWidth = mBadgeTextPaint.measureText(mBadgeText);
RectF rectF = getBadgeRectF(textWidth);
if (rectF.width() > 0) {
//绘制背景
canvas.drawRoundRect(rectF, rectF.height() / 2, rectF.height() / 2, mBadgeBgPaint);
//绘制徽章边框
if (mBorderWidth > 0) {
canvas.drawRoundRect(rectF, rectF.height() / 2, rectF.height() / 2, mBadgeBorderPaint);
}
//绘制字体
canvas.drawText(mBadgeText, rectF.centerX() - textWidth / 2,
rectF.centerY() - (metrics.top + metrics.bottom) / 2, mBadgeTextPaint);
}
}
//获取绘制区域
private RectF getBadgeRectF(float textWidth) {
float left = 0, right = 0, top = 0, bottom = 0, width = 0, height = 0;
int offset = mBorderWidth / 2;
switch (mBadgeAnchorPosition) {
case ANCHOR_LEFT_TOP:
left = mMarginHorizon + offset;
right = mMarginHorizon + textWidth + mPaddingH + offset;
top = mMarginVertical + offset;
bottom = mMarginVertical + mBadgeTextSize + mPaddingV + offset;
width = right - left;
height = bottom - top;
if (width < height) {
right = right + height - width;
}
break;
case ANCHOR_LEFT_BOTTOM:
left = mMarginHorizon + offset;
right = mMarginHorizon + textWidth + mPaddingH + offset;
top = getHeight() - mMarginVertical - mBadgeTextSize - mPaddingV - offset;
bottom = top + mBadgeTextSize + mPaddingV - offset;
width = right - left;
height = bottom - top;
if (width < height) {
right = right + height - width;
}
break;
case ANCHOR_RIGHT_TOP:
left = getWidth() - textWidth - mMarginHorizon - mPaddingH - offset;
right = left + textWidth + mPaddingH - offset;
top = mMarginVertical + offset;
bottom = mMarginVertical + mBadgeTextSize + mPaddingV + offset;
width = right - left;
height = bottom - top;
if (width < height) {
left = left - (height - width);
}
break;
case ANCHOR_RIGHT_BOTTOM:
left = getWidth() - textWidth - mMarginHorizon - mPaddingH - offset;
right = left + textWidth + mPaddingH - offset;
top = getHeight() - mBadgeTextSize - mMarginVertical - mPaddingV - offset;
bottom = top + mBadgeTextSize + mPaddingV - offset;
width = right - left;
height = bottom - top;
if (width < height) {
left = left - (height - width);
}
break;
}
return new RectF(left, top, right, bottom);
}
@IntDef({ANCHOR_LEFT_TOP, ANCHOR_LEFT_BOTTOM, ANCHOR_RIGHT_TOP, ANCHOR_RIGHT_BOTTOM})
public @interface Position {
}
<declare-styleable name="BadgeView">
<!--显示文本-->
<attr name="badgeText" format="string" />
<!--文本字体大小-->
<attr name="badgeTextSize" format="dimension" />
<!--文本颜色-->
<attr name="badgeTextColor" format="color" />
<!--边框宽度-->
<attr name="badgeBorderWidth" format="dimension" />
<!--边框颜色-->
<attr name="badgeBorderColor" format="color" />
<!--气泡背景色-->
<attr name="badgeBgColor" format="color" />
<!--徽章显示的位置-->
<attr name="badgeAnchorPosition">
<enum name="AnchorLeftTop" value="0" />
<enum name="AnchorLeftBottom" value="1" />
<enum name="AnchorRightTop" value="2" />
<enum name="AnchorRightBottom" value="3" />
</attr>
<!--徽章在水平方向的margin-->
<attr name="badgeMarginHorizon" format="dimension" />
<!--徽章在垂直方向的margin-->
<attr name="badgeMarginVertical" format="dimension" />
<!--徽章内部水平padding-->
<attr name="badgePaddingHorizon" format="dimension" />
<!--徽章内部垂直padding-->
<attr name="badgePaddingVertical" format="dimension" />
</declare-styleable>