BadgeRadioButton -- 帶角標的RadioButton

一、概述

本文使用上一篇文章 DrawCenterTextView 的一些知識婉弹,如果想要理解睬魂,請查看后再看本文

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

二、實現(xiàn)原理

在 onDraw 方法中出牧,根據(jù) DrawableTop 圖標的位置穴肘,選擇右上角為中心進行繪制圓角背景及繪制數(shù)字,很簡單的一個思路舔痕,核心代碼如下:

    @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);
        }
    }

三评抚、增加可自定義的方法

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

四侍匙、BadgeRadioButton

直接上代碼以供復制:

**
 * <p>帶標記的 RadioButton,目前僅支持 drawableTop 的按鈕 right的沒測試</p><br>
 *
 * @author - lwc
 * @date - 2017/6/14
 * @note -
 * 使用時直接 setBadgeNum
 * setBadgeTextSize -- 設(shè)置字體顏色
 * setBadgePadding -- 設(shè)置內(nèi)邊距
 * setBadgeShowShadow -- 設(shè)置是否顯示陰影
 * setBadgeColorBackground -- 設(shè)置背景顏色
 * setBadgeColorBadgeText -- 設(shè)置字體顏色
 * setBadgeExact -- 設(shè)置是否截取圖標
 * 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ù)字字體大小 默認8sp */
    private float mBadgeTextSize;
    /** 內(nèi)邊距 默認4dp */
    private int mBadgePadding;
    /** x偏移量 */
    private int mBadgeOffX;
    /** Y偏移量 */
    private int mBadgeOffY;
    /** 數(shù)字 */
    private int mBadgeNumber;
    /** 數(shù)字文本 */
    private String mBadgeText;
    /** 是否存在陰影 默認存在 */
    private boolean mBadgeShowShadow;
    /** 背景顏色 默認紅色 */
    private int mBadgeColorBackground;
    /** 字體顏色 默認白色 */
    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 標記數(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;
    }

    /**
     * 測量文本高度和寬度
     */
    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叮雳,但是沒測試
       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è)置字體大小想暗,默認8dp
     *
     * @param badgeTextSize 內(nèi)邊距
     */
    public BadgeRadioButton setBadgeTextSize(float badgeTextSize) {
        mBadgeTextSize = badgeTextSize;
        mBadgeTextPaint.setTextSize(mBadgeTextSize);
        return setBadgeNumber(mBadgeNumber);
    }

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

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

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

    /**
     * 設(shè)置標記字體顏色,默認白色
     *
     * @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);
    }

    /**
     * 是否截取字體寞焙,默認截取储狭,如 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.reibang.com/p/e09cbe635f1a

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捣郊,一起剝皮案震驚了整個濱河市辽狈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌模她,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件懂牧,死亡現(xiàn)場離奇詭異侈净,居然都是意外死亡,警方通過查閱死者的電腦和手機僧凤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進店門畜侦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人躯保,你說我怎么就攤上這事旋膳。” “怎么了途事?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵验懊,是天一觀的道長擅羞。 經(jīng)常有香客問我,道長义图,這世上最難降的妖魔是什么减俏? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮碱工,結(jié)果婚禮上娃承,老公的妹妹穿的比我還像新娘。我一直安慰自己怕篷,他們只是感情好历筝,可當我...
    茶點故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著廊谓,像睡著了一般梳猪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蹂析,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天舔示,我揣著相機與錄音,去河邊找鬼电抚。 笑死惕稻,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蝙叛。 我是一名探鬼主播俺祠,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼借帘!你這毒婦竟也來了蜘渣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤肺然,失蹤者是張志新(化名)和其女友劉穎蔫缸,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體际起,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡拾碌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了街望。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片校翔。...
    茶點故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖灾前,靈堂內(nèi)的尸體忽然破棺而出防症,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布蔫敲,位于F島的核電站饲嗽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏燕偶。R本人自食惡果不足惜喝噪,卻給世界環(huán)境...
    茶點故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望指么。 院中可真熱鬧酝惧,春花似錦、人聲如沸伯诬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盗似。三九已至哩陕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赫舒,已是汗流浹背悍及。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留接癌,地道東北人心赶。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像缺猛,于是被迫代替她去往敵國和親缨叫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內(nèi)容