BadgeRadioButton -- 帶角標(biāo)的RadioButton

一、概述

本文使用上一篇文章 DrawCenterTextView 的一些知識(shí),如果想要理解,請(qǐng)查看后再看本文

在首頁導(dǎo)航菜單欄中,大多數(shù)都會(huì)有角標(biāo)表示消息的數(shù)量,在網(wǎng)上找了一下,有角標(biāo)的要么無法實(shí)現(xiàn)點(diǎn)擊事件,要么就是一個(gè)角標(biāo)樣式的 TextView,并沒有一個(gè)簡(jiǎn)單的RadioButton的角標(biāo)設(shè)置,決定自定義一個(gè)簡(jiǎn)單的 BadgeRadioButton ,==目前僅支持 drawableTop== 的按鈕,實(shí)現(xiàn)的效果如下:

二、實(shí)現(xiàn)原理

在 onDraw 方法中,根據(jù) DrawableTop 圖標(biāo)的位置,選擇右上角為中心進(jìn)行繪制圓角背景及繪制數(shù)字,很簡(jiǎn)單的一個(gè)思路,核心代碼如下:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (null != mDrawableBackground && null != mBadgeText) {
            showShadowImpl(mBadgeShowShadow, mBadgeBackgroundPaint);
            if (mBadgePadding > getOffSize()) {
                mBadgePadding = (int) getOffSize();
            }
            if (mBadgeText.length() == 0) {
                canvas.drawCircle((getWidth() + mDrawableBackground.getIntrinsicWidth()) / 2 + mBadgeOffX, mFontHeight / 2 + mBadgeOffY, mFontHeight / 2 + mBadgePadding, mBadgeBackgroundPaint);
            } else if (mBadgeText.length() <= 1) {
                canvas.drawCircle((getWidth() + mDrawableBackground.getIntrinsicWidth()) / 2 + mBadgeOffX, mFontHeight / 2 + mBadgeOffY, mFontHeight / 2 + mBadgePadding, mBadgeBackgroundPaint);
            } else {
                mBadgeBackgroundRect.left = (getWidth() + mDrawableBackground.getIntrinsicWidth()) / 2 - mFontWidth / 2 - mBadgePadding + mBadgeOffX;
                mBadgeBackgroundRect.right = (getWidth() + mDrawableBackground.getIntrinsicWidth()) / 2 + mFontWidth / 2 + mBadgePadding + mBadgeOffX;
                mBadgeBackgroundRect.top = -mBadgePadding + mBadgeOffY;
                mBadgeBackgroundRect.bottom = mFontHeight + mBadgePadding + mBadgeOffY;
                canvas.drawRoundRect(mBadgeBackgroundRect, mFontHeight / 2 + mBadgePadding, mFontHeight / 2 + mBadgePadding, mBadgeBackgroundPaint);
            }
            canvas.drawText(mBadgeText, (getWidth() + mDrawableBackground.getIntrinsicWidth()) / 2 - mFontWidth / 2 + mBadgeOffX, mFontHeight + mBadgeOffY, mBadgeTextPaint);
        }
    }

三、增加可自定義的方法

方法名 默認(rèn)值 使用效果
setBadgeTextSize null 設(shè)置角標(biāo)數(shù)字,>=0就顯示,沒有就不顯示
setBadgeTextSize 8sp 設(shè)置角標(biāo)字體大小
setBadgePadding 4dp 設(shè)置角標(biāo)的內(nèi)邊距,最大不能超過布局邊距
setBadgeShowShadow true 角標(biāo)是否顯示陰影
setBadgeColorBackground Red 設(shè)置角標(biāo)的背景顏色
setBadgeColorBadgeText White 設(shè)置角標(biāo)的字體顏色
setBadgeOffX 0 設(shè)置X偏移量
setBadgeOffY 0 設(shè)置Y偏移量
setBadgeExact true 是否截取字體,默認(rèn)截取,如 100 -> 99+

四、BadgeRadioButton

直接上代碼以供復(fù)制:

**
 * <p>帶標(biāo)記的 RadioButton,目前僅支持 drawableTop 的按鈕 right的沒測(cè)試</p><br>
 *
 * @author - lwc
 * @date - 2017/6/14
 * @note -
 * 使用時(shí)直接 setBadgeNum
 * setBadgeTextSize -- 設(shè)置字體顏色
 * setBadgePadding -- 設(shè)置內(nèi)邊距
 * setBadgeShowShadow -- 設(shè)置是否顯示陰影
 * setBadgeColorBackground -- 設(shè)置背景顏色
 * setBadgeColorBadgeText -- 設(shè)置字體顏色
 * setBadgeExact -- 設(shè)置是否截取圖標(biāo)
 * setBadgeOffX -- 設(shè)置X的偏移量
 * setBadgeOffY -- 設(shè)置Y的偏移量
 * -------------------------------------------------------------------------------------------------
 * @modified -
 * @date -
 * @note -
 */
public class BadgeRadioButton extends DrawableCenterRadioButton {
    /** 字體高度 */
    private float mFontHeight;
    /** 字體寬度 */
    private float mFontWidth;
    /** 位圖集合 */
    private Drawable[] mDrawables;
    /** 位圖 */
    private Drawable mDrawableBackground;
    /** 背景畫筆 */
    private Paint mBadgeBackgroundPaint;
    /** 數(shù)字畫筆 */
    private Paint mBadgeTextPaint;
    /** 數(shù)字字體大小 默認(rèn)8sp */
    private float mBadgeTextSize;
    /** 內(nèi)邊距 默認(rèn)4dp */
    private int mBadgePadding;
    /** x偏移量 */
    private int mBadgeOffX;
    /** Y偏移量 */
    private int mBadgeOffY;
    /** 數(shù)字 */
    private int mBadgeNumber;
    /** 數(shù)字文本 */
    private String mBadgeText;
    /** 是否存在陰影 默認(rèn)存在 */
    private boolean mBadgeShowShadow;
    /** 背景顏色 默認(rèn)紅色 */
    private int mBadgeColorBackground;
    /** 字體顏色 默認(rèn)白色 */
    private int mBadgeColorBadgeText;
    /** 是否截取數(shù)字 */
    private boolean mBadgeExact;
    /** 背景矩形 */
    private RectF mBadgeBackgroundRect;

    public BadgeRadioButton(Context context) {
        super(context);
        init();
    }

    public BadgeRadioButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public BadgeRadioButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (null != mDrawableBackground && null != mBadgeText) {
            showShadowImpl(mBadgeShowShadow, mBadgeBackgroundPaint);
            float maxPadding = getOffSize();
            if (mBadgePadding > maxPadding) {
                mBadgeOffY = (int) (mBadgePadding - maxPadding);
            }
            if (mBadgeText.length() == 0) {
                canvas.drawCircle((getWidth() + mDrawableBackground.getIntrinsicWidth()) / 2 + mBadgeOffX, mFontHeight / 2 + mBadgeOffY, mFontHeight / 2 + mBadgePadding, mBadgeBackgroundPaint);
            } else if (mBadgeText.length() <= 1) {
                canvas.drawCircle((getWidth() + mDrawableBackground.getIntrinsicWidth()) / 2 + mBadgeOffX, mFontHeight / 2 + mBadgeOffY, mFontHeight / 2 + mBadgePadding, mBadgeBackgroundPaint);
            } else {
                mBadgeBackgroundRect.left = (getWidth() + mDrawableBackground.getIntrinsicWidth()) / 2 - mFontWidth / 2 - mBadgePadding + mBadgeOffX;
                mBadgeBackgroundRect.right = (getWidth() + mDrawableBackground.getIntrinsicWidth()) / 2 + mFontWidth / 2 + mBadgePadding + mBadgeOffX;
                mBadgeBackgroundRect.top = -mBadgePadding + mBadgeOffY;
                mBadgeBackgroundRect.bottom = mFontHeight + mBadgePadding + mBadgeOffY;
                canvas.drawRoundRect(mBadgeBackgroundRect, mFontHeight / 2 + mBadgePadding, mFontHeight / 2 + mBadgePadding, mBadgeBackgroundPaint);
            }
            canvas.drawText(mBadgeText, (getWidth() + mDrawableBackground.getIntrinsicWidth()) / 2 - mFontWidth / 2 + mBadgeOffX, mFontHeight + mBadgeOffY, mBadgeTextPaint);
        }
    }

    /**
     * 設(shè)置顯示數(shù)字
     *
     * @param badgeNumber 標(biāo)記數(shù)字
     */
    public BadgeRadioButton setBadgeNumber(int badgeNumber) {
        mBadgeNumber = badgeNumber;
        if (mBadgeNumber < 0) {
            mBadgeText = null;
        } else if (mBadgeNumber > 99) {
            mBadgeText = mBadgeExact ? String.valueOf(mBadgeNumber) : "99+";
        } else if (mBadgeNumber > 0 && mBadgeNumber <= 99) {
            mBadgeText = String.valueOf(mBadgeNumber);
        } else if (mBadgeNumber == 0) {
            mBadgeText = "";
        }
        if (!TextUtils.isEmpty(mBadgeText)) {
            measureText();
        }
        invalidate();
        return this;
    }

    /**
     * 測(cè)量文本高度和寬度
     */
    private void measureText() {
        mFontHeight = Math.abs(mBadgeTextPaint.getFontMetrics().descent + mBadgeTextPaint.getFontMetrics().ascent);
        mFontWidth = mBadgeTextPaint.measureText(mBadgeText);
    }

    /**
     * 為畫筆設(shè)置陰影
     *
     * @param showShadow 是否顯示
     * @param badgeBackgroundPaint 畫筆
     */
    private void showShadowImpl(boolean showShadow, Paint badgeBackgroundPaint) {
        int x = dp2px(1);
        int y = dp2px(1.5f);
        badgeBackgroundPaint.setShadowLayer(showShadow ? dp2px(2f) : 0, x, y, 0x33000000);
    }

    @Override
    void init() {
        super.init();
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);

        mBadgeTextSize = dp2px(10);
        mBadgePadding = dp2px(4);
        mBadgeShowShadow = true;
        mBadgeColorBackground = Color.RED;
        mBadgeColorBadgeText = Color.WHITE;
        mBadgeOffX = 0;
        mBadgeOffY = 0;
        mFontWidth = 0;
        mFontHeight = 0;
        mBadgeBackgroundRect = new RectF(0, 0, 0, 0);

        //目前只支持drawableTop的RadioButton
        mDrawables = getCompoundDrawables();
        if (null != mDrawables[1]) {
            mDrawableBackground = mDrawables[1];
        }
        /* 理論上可以支持drawableRight,但是沒測(cè)試
       else if (null != mDrawables[2]) {
            mDrawableBackground = mDrawables[2];
        }*/

        mBadgeTextPaint = new TextPaint();
        mBadgeTextPaint.setAntiAlias(true);
        mBadgeTextPaint.setSubpixelText(true);
        mBadgeTextPaint.setFakeBoldText(true);
        mBadgeTextPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        mBadgeTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
        mBadgeTextPaint.setDither(true);
        mBadgeTextPaint.setColor(mBadgeColorBadgeText);
        mBadgeTextPaint.setTextSize(mBadgeTextSize);

        mBadgeBackgroundPaint = new Paint();
        mBadgeBackgroundPaint.setAntiAlias(true);
        mBadgeBackgroundPaint.setStyle(Paint.Style.FILL);
        mBadgeBackgroundPaint.setDither(true);
        mBadgeBackgroundPaint.setColor(mBadgeColorBackground);
        showShadowImpl(mBadgeShowShadow, mBadgeBackgroundPaint);
    }

    /**
     * 設(shè)置字體大小,默認(rèn)8dp
     *
     * @param badgeTextSize 內(nèi)邊距
     */
    public BadgeRadioButton setBadgeTextSize(float badgeTextSize) {
        mBadgeTextSize = badgeTextSize;
        mBadgeTextPaint.setTextSize(mBadgeTextSize);
        return setBadgeNumber(mBadgeNumber);
    }

    /**
     * 設(shè)置內(nèi)邊距,默認(rèn)4dp
     *
     * @param badgePadding 內(nèi)邊距
     */
    public BadgeRadioButton setBadgePadding(int badgePadding) {
        mBadgePadding = badgePadding;
        return setBadgeNumber(mBadgeNumber);
    }

    /**
     * 設(shè)置是否顯示陰影,默認(rèn)顯示
     *
     * @param badgeShowShadow true - 顯示
     */
    public BadgeRadioButton setBadgeShowShadow(boolean badgeShowShadow) {
        mBadgeShowShadow = badgeShowShadow;
        return setBadgeNumber(mBadgeNumber);
    }

    /**
     * 設(shè)置背景顏色,默認(rèn)紅色
     *
     * @param badgeColorBackground 背景顏色
     */
    public BadgeRadioButton setBadgeColorBackground(@ColorInt int badgeColorBackground) {
        mBadgeColorBackground = badgeColorBackground;
        mBadgeBackgroundPaint.setColor(mBadgeColorBackground);
        return setBadgeNumber(mBadgeNumber);
    }

    /**
     * 設(shè)置標(biāo)記字體顏色,默認(rèn)白色
     *
     * @param badgeColorBadgeText 字體顏色
     */
    public BadgeRadioButton setBadgeColorBadgeText(int badgeColorBadgeText) {
        mBadgeColorBadgeText = badgeColorBadgeText;
        mBadgeTextPaint.setColor(mBadgeColorBadgeText);
        return setBadgeNumber(mBadgeNumber);
    }

    /**
     * 設(shè)置X偏移量
     *
     * @param badgeOffX x偏移量
     */
    public BadgeRadioButton setBadgeOffX(int badgeOffX) {
        mBadgeOffX = badgeOffX;
        return setBadgeNumber(mBadgeNumber);
    }

    /**
     * 設(shè)置Y偏移量
     *
     * @param badgeOffY Y偏移量
     */
    public BadgeRadioButton setBadgeOffY(int badgeOffY) {
        mBadgeOffY = badgeOffY;
        return setBadgeNumber(mBadgeNumber);
    }

    /**
     * 是否截取字體,默認(rèn)截取,如 100 -> 99+
     *
     * @param badgeExact true - 截取
     */
    public BadgeRadioButton setBadgeExact(boolean badgeExact) {
        mBadgeExact = badgeExact;
        return setBadgeNumber(mBadgeNumber);
    }

    /**
     * dp轉(zhuǎn)px
     *
     * @param dpValue dp值
     * @return px值
     */
    public int dp2px(float dpValue) {
        final float scale = getContext().getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}

轉(zhuǎn)載注意出處:http://www.itdecent.cn/p/e09cbe635f1a

Github 地址為,https://github.com/lwcye/BadgeRadioButton
如果覺得喜歡就點(diǎn)star

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容