# 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>