Android超級好用的CheckView

前言

多選和單選是日常開發(fā)經(jīng)常用的控件,android系統(tǒng)原生的控件樣式(RadioButton 兆衅、CheckBox)不太好看,很多時候我們需要根據(jù)美工的設(shè)計自己實(shí)現(xiàn)CheckView磺陡。

我們需要自己準(zhǔn)備兩張圖片沼本。一張為checked狀態(tài),一張為unchecked狀態(tài)薪捍。如果產(chǎn)品哥哥說你這個顏色不好看笼痹,我們又需要重新修改±掖基于以上原因与倡,我們實(shí)現(xiàn)了自定義的CheckView,可以任意修改 顏色昆稿、大小纺座,形狀(圓心和方形),效果如下溉潭。

PIC.png

源碼展示

自定義CheckView:

package com.xcheng.view.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.IntRange;
import android.support.v4.content.res.ResourcesCompat;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Checkable;

import com.xcheng.view.R;
import com.xcheng.view.util.LocalDisplay;

import static com.xcheng.view.widget.ProgressView.TYPE_CIRCLE;

public class CheckView extends View implements Checkable {
    //圓框的顏色
    private int mStrokeWidth; // dp
    //圓框的尺寸
    private int mSize; // dp
    //圓框的顏色
    private int mStrokeColor;
    //圓框內(nèi)填充的顏色
    private int mbgColor;
    //選中的顏色
    private int mCheckedColor;
    private boolean mChecked;
    private Paint mStrokePaint;
    private Paint mBackgroundPaint;
    private Drawable mCheckDrawable;
    private Rect mCheckRect;
    private Rect mBgRect;
    private Rect mStrokeRect;

    private int mType;

    public CheckView(Context context) {
        this(context, null);
    }

    public CheckView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CheckView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
    }


    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CheckView, defStyleAttr, 0);
        mSize = ta.getDimensionPixelSize(R.styleable.CheckView_ev_size, LocalDisplay.dp2px(18));
        mType = ta.getInt(R.styleable.CheckView_ev_type, TYPE_CIRCLE);

        mStrokeWidth = ta.getDimensionPixelSize(R.styleable.CheckView_ev_strokeWidth, LocalDisplay.dp2px(2));
        mStrokeColor = ta.getColor(R.styleable.CheckView_ev_strokeColor, Color.parseColor("#c2c9cc"));
        mbgColor = ta.getColor(R.styleable.CheckView_ev_bgColor, Color.TRANSPARENT);
        mCheckedColor = ta.getColor(R.styleable.CheckView_ev_checkedColor, Color.parseColor("#0bd38a"));
        mChecked = ta.getBoolean(R.styleable.CheckView_android_checked, false);
        ta.recycle();

        mStrokePaint = new Paint();
        mStrokePaint.setAntiAlias(true);
        mStrokePaint.setStyle(Paint.Style.STROKE);
        mStrokePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
        mStrokePaint.setStrokeWidth(mStrokeWidth);
        mStrokePaint.setColor(mStrokeColor);
        mCheckDrawable = ResourcesCompat.getDrawable(context.getResources(),
                R.drawable.ic_check_white_18dp, context.getTheme());

        mBackgroundPaint = new Paint();
        mBackgroundPaint.setAntiAlias(true);
        mBackgroundPaint.setStyle(Paint.Style.FILL);

        mCheckRect = getSquareRect(0);
        mBgRect = getSquareRect(mStrokeWidth);
        mStrokeRect = getSquareRect(mStrokeWidth / 2);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(mSize + mStrokeWidth * 2 + getPaddingLeft() + getPaddingRight(),
                mSize + mStrokeWidth * 2 + getPaddingTop() + getPaddingBottom());
    }

    @Override
    public void setChecked(boolean checked) {
        mChecked = checked;
        invalidate();
    }

    @Override
    public boolean isChecked() {
        return mChecked;
    }

    @Override
    public void toggle() {
        setChecked(!mChecked);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mChecked) {
            mBackgroundPaint.setColor(mCheckedColor);
            if (mType == ProgressView.TYPE_CIRCLE) {
                canvas.drawCircle(getPaddingLeft() + mStrokeWidth + mSize / 2,
                        getPaddingTop() + mStrokeWidth + mSize / 2,
                        mStrokeWidth + mSize / 2, mBackgroundPaint);
            } else {
                canvas.drawRect(mBgRect, mBackgroundPaint);
            }
            mCheckDrawable.setBounds(mCheckRect);
            mCheckDrawable.draw(canvas);
        } else {
            mBackgroundPaint.setColor(mbgColor);
            if (mType == ProgressView.TYPE_CIRCLE) {
                //渲染這個圓形背景
                canvas.drawCircle(getPaddingLeft() + mStrokeWidth + mSize / 2,
                        getPaddingTop() + mStrokeWidth + mSize / 2,
                        mSize / 2 + mStrokeWidth, mBackgroundPaint);
                //渲染這個圓形邊框
                canvas.drawCircle(getPaddingLeft() + mStrokeWidth + mSize / 2,
                        getPaddingTop() + mStrokeWidth + mSize / 2,
                        (mStrokeWidth + mSize) / 2/*Paint.Style.STROKE的情況下畫筆在StrokeWidth中間*/, mStrokePaint);
            } else {
                //渲染這個方形背景
                canvas.drawRect(mBgRect, mBackgroundPaint);
                //渲染這個方形邊框
                canvas.drawRect(mStrokeRect, mStrokePaint);
            }
        }
        // enable hint
        setAlpha(isEnabled() ? 1.0f : 0.5f);
    }


    private Rect getSquareRect(@IntRange(from = 0) int offset) {
        int centerX = getPaddingLeft() + mStrokeWidth + mSize / 2;
        int centerY = getPaddingTop() + mStrokeWidth + mSize / 2;
        return new Rect(centerX - mSize / 2 - offset, centerY - mSize / 2 - offset,
                centerX + mSize / 2 + offset, centerY + mSize / 2 + offset);
    }
}

xml屬性:

<declare-styleable name="CheckView">
    <attr name="android:checked" />
    <attr name="ev_type" />
    <attr name="ev_strokeColor" format="color" />
    <attr name="ev_bgColor" format="color" />
    <attr name="ev_checkedColor" format="color" />
    <attr name="ev_size" format="dimension" />
    <attr name="ev_strokeWidth" format="dimension" />
</declare-styleable>

使用:

<com.xcheng.view.widget.CheckView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="20dp"
    android:checked="false"
    app:ev_type="rect"
    app:ev_bgColor="@color/ev_white"
    app:ev_strokeColor="@color/ev_blue_normal"
    app:ev_checkedColor="@color/colorAccent"
    app:ev_size="30dp"
    app:ev_strokeWidth="6dp" />

是不是很簡單净响,一勞永逸。再也不用擔(dān)心修改樣式了喳瓣。

源碼地址:https://github.com/xchengDroid/EasyView/blob/master/library/src/main/java/com/xcheng/view/widget/CheckView.java

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末馋贤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子畏陕,更是在濱河造成了極大的恐慌配乓,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異犹芹,居然都是意外死亡崎页,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門腰埂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來飒焦,“玉大人,你說我怎么就攤上這事屿笼∥” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵驴一,是天一觀的道長休雌。 經(jīng)常有香客問我,道長肝断,這世上最難降的妖魔是什么杈曲? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮孝情,結(jié)果婚禮上鱼蝉,老公的妹妹穿的比我還像新娘。我一直安慰自己箫荡,他們只是感情好魁亦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著羔挡,像睡著了一般洁奈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绞灼,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天利术,我揣著相機(jī)與錄音,去河邊找鬼低矮。 笑死印叁,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的军掂。 我是一名探鬼主播轮蜕,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蝗锥!你這毒婦竟也來了跃洛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤终议,失蹤者是張志新(化名)和其女友劉穎汇竭,沒想到半個月后葱蝗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡细燎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年两曼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片找颓。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡合愈,死狀恐怖叮贩,靈堂內(nèi)的尸體忽然破棺而出击狮,到底是詐尸還是另有隱情,我是刑警寧澤益老,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布彪蓬,位于F島的核電站,受9級特大地震影響捺萌,放射性物質(zhì)發(fā)生泄漏档冬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一桃纯、第九天 我趴在偏房一處隱蔽的房頂上張望酷誓。 院中可真熱鬧,春花似錦态坦、人聲如沸盐数。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玫氢。三九已至,卻和暖如春谜诫,著一層夾襖步出監(jiān)牢的瞬間漾峡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工喻旷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留生逸,地道東北人。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓且预,卻偏偏與公主長得像槽袄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子辣之,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,081評論 25 707
  • 用兩張圖告訴你掰伸,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,714評論 2 59
  • 這世界歧蕉,不只有漫山鮮花的村落灾部;不只有古樸純凈的悠悠古鎮(zhèn);不只有一望無際的蔚藍(lán)大海惯退。還有赌髓,死亡與美麗同行的生命禁區(qū),...
    change鄭慧閱讀 1,654評論 5 18
  • 隨著年紀(jì)的增長催跪,人們自我所思便愈加的少了锁蠕。其原因在于自我思想浮沉于俗世之間,多了平日瑣屑事物的困擾懊蒸,去思考和探尋未...
    斯人如斯1閱讀 747評論 0 1
  • 利潤:銷售收入與成本的差額 銷售收入:菜品銷售收入+商品銷售收入+外賣銷售收入+其他收入
    愛上小炒閱讀 411評論 0 0