Material Designer的低版本兼容實現(十)—— CheckBox & RadioButton


ChekBox的用途我們就不必多說了,算是一個很古老的控件了,何其類似的還有RadioButton,這個東西因為我目前還沒寫出來,所以用了別人的一個lib,這下面會說到。順便說一句,如果你的app是在5.0環境下編譯的,那么你用傳統的checkbox時,你會發現checkbox在低版本機子上運行出來的樣子和以前不同了,雖然沒有動畫效果,但樣子和5.0以上的checkbox還是很像的。

最小尺寸

48 x 48

開源lib中對於不同的屏幕做了不同大小的對勾圖片,應該能滿足高清屏的要求。至於不可用狀態目前還沒做,其實也就是繼承下isEnable()方法,但是因為做出來的效果我不是很滿意,所以就僅僅試了試,沒真的放出來。

 

一、導入到自己的工程中

要用這個控件還是得添加開源項目的支持,開源項目地址:

我維護的:https://github.com/shark0017/MaterialDesignLibrary

原版本:https://github.com/navasmdc/MaterialDesignLibrary

大家可以選擇一個下載,反正兩個版本都是我和原作者融合后的東西,差別不大。

添加lib支持后我們就可以用這個控件了,放入布局文件前還是要寫命名空間的。

xmlns:app="http://schemas.android.com/apk/res-auto"

    <com.gc.materialdesign.views.CheckBox
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal" />

由於我沒有做可視化的效果,所以在編譯器中沒辦法實時顯示狀態,默認就是一個透明的view。如果大家想在編譯器中看個大概的樣子,可以給它通過background=“#xxxxxx”添加個背景顏色。

真實運行的效果:

 

二、在布局文件中設定各種屬性

app:checked="true"  是否被選中,默認沒被選中

android:background="#ff0000"  設定checkbox的顏色,默認是綠色

android:layout_width="100dp"  設定checkbox這個view整體的大小,和里面的方框無關。注意看圖中按壓時陰影的大小
android:layout_height="100dp"

app:checkBoxSize="40dp"  設定checkbox里面方框的大小

 

三、通過代碼設定各種屬性

public class CheckBoxTest extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.checkbox);
        
        CheckBox checkBox = (CheckBox)findViewById(R.id.checkBox01);
        checkBox.setChecked(true);// 設定初始為選中的狀態
        
        checkBox.setBackgroundColor(0xffff0000);// 設置checkbox的顏色
        
        checkBox.setBackgroundColor(getResources().getColor(R.color.orange));// 設置背景色

        checkBox.setCheckBoxSize(35.5f);// 設置方框的大小
        
        // 監聽選中的事件
        checkBox.setOncheckListener(new OnCheckListener() {
            
            @Override
            public void onCheck(boolean isChecked) {
                // TODO 自動生成的方法存根
                System.out.println("isChecked = "+ checkBox05.isChecked());
                Toast.makeText(CheckBoxTest.this, "checkbox status = "+isChecked, 0).show();
            }
        });
        
    }
}

 

四、補充:RadioButton

這個控件是從另一個開源項目中得到的,那個lib中其他的控件都做的不好,就這個做的十分精細。具體的測試和修改我沒去做,下面僅僅給出源碼,由大家自行修改吧,其實可以修改的地方還是蠻多的。

lib地址:https://github.com/keithellis/MaterialWidget

源碼如下:

dimen.xml

這里是默認的屬性,包括長寬啥的,這些值照理說都應該可以在java代碼中定制的。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- RadioButton Default -->
    <dimen name="radio_width">48dp</dimen>
    <dimen name="radio_height">48dp</dimen>
    <dimen name="radio_border_radius">10dp</dimen>
    <dimen name="radio_thumb_radius">6dp</dimen>
    <dimen name="radio_ripple_radius">24dp</dimen>
    <dimen name="radio_stroke_width">2dp</dimen>
    <color name="radio_color">#6d6d6d</color>
    <color name="radio_checked_color">#55b03d</color>
</resources>

可以定制的屬性,這里就兩個,蠻少的。請大家自行添加修改吧~

        <!-- RadioButton Attribute -->
    <declare-styleable name="RadioButton">
        <attr name="radio_color" format="color"/>
        <attr name="radio_checked_color" format="color"/>
    </declare-styleable>

 

RadioButton.java

從中我們可以看到,這個控件都是被畫出來的,和上面控件用到的lib的構建思路不同。因為是畫出來的,所以我們可以定制的東西更多,擴展性更強,值得細細品味這個類的寫法。

package com.gc.materialdesign.views;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.CompoundButton;

import com.gc.materialdesign.R;

/**
 * Created by IntelliJ IDEA.
 * User: keith.
 * Date: 14-10-8.
 * Time: 15:48.
 */
public class RadioButton extends CompoundButton {

    private static final long ANIMATION_DURATION = 200;// 動畫持續的時間
    private static final int StateNormal = 1;
    private static final int StateTouchDown = 2;
    private static final int StateTouchUp = 3;

    private int mState = StateNormal;
    private long mStartTime;
    private int mColor;
    private int mCheckedColor;
    private int mRadioWidth;// 寬度
    private int mRadioHeight;// 高度
    private int mBorderRadius;
    private int mThumbRadius;
    private int mRippleRadius;
    private int mStrokeWidth;
    private Rect mFingerRect;
    private boolean mMoveOutside;

    private Paint borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Paint thumbPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Paint ripplePaint = new Paint(Paint.ANTI_ALIAS_FLAG);

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

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

    public RadioButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.RadioButton);
        mColor = attributes.getColor(R.styleable.RadioButton_radio_color, getResources().getColor(R.color.radio_color));
        mCheckedColor = attributes.getColor(R.styleable.RadioButton_radio_checked_color, getResources().getColor(R.color.radio_checked_color));
        attributes.recycle();
        mRadioWidth = getResources().getDimensionPixelSize(R.dimen.radio_width);
        mRadioHeight = getResources().getDimensionPixelSize(R.dimen.radio_height);
        mBorderRadius = getResources().getDimensionPixelSize(R.dimen.radio_border_radius);
        mThumbRadius = getResources().getDimensionPixelSize(R.dimen.radio_thumb_radius);
        mRippleRadius = getResources().getDimensionPixelSize(R.dimen.radio_ripple_radius);
        mStrokeWidth = getResources().getDimensionPixelSize(R.dimen.radio_stroke_width);

        thumbPaint.setColor(mCheckedColor);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(measureWidth(widthMeasureSpec), MeasureSpec.EXACTLY);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(measureHeight(heightMeasureSpec), MeasureSpec.EXACTLY);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private int measureWidth(int measureSpec) {
        int result;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            if (specSize < mRadioWidth) {
                result = mRadioWidth;
            } else {
                result = specSize;
            }
        } else {
            result = mRadioWidth;
        }
        return result;
    }

    private int measureHeight(int measureSpec) {
        int result;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            if (specSize < mRadioHeight) {
                result = mRadioHeight;
            } else {
                result = specSize;
            }
        } else {
            result = mRadioHeight;
        }
        return result;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (isEnabled()) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mMoveOutside = false;
                    mState = StateTouchDown;
                    mFingerRect = new Rect(getLeft(), getTop(), getRight(), getBottom());
                    mStartTime = System.currentTimeMillis();
                    invalidate();
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (!mFingerRect.contains(getLeft() + (int) event.getX(), getTop() + (int) event.getY())) {
                        mMoveOutside = true;
                        mState = StateNormal;
                        mStartTime = System.currentTimeMillis();
                        invalidate();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    if (!mMoveOutside) {
                        mState = StateTouchUp;
                        setChecked(!isChecked());
                        mStartTime = System.currentTimeMillis();
                        invalidate();
                    }
                    break;
                case MotionEvent.ACTION_CANCEL:
                    mState = StateNormal;
                    invalidate();
                    break;
            }
        }
        return true;
    }

    private int rippleColor(int color) {
        int alpha = Math.round(Color.alpha(color) * 0.2f);
        int red = Color.red(color);
        int green = Color.green(color);
        int blue = Color.blue(color);
        return Color.argb(alpha, red, green, blue);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int rippleRadius = 0;
        int thumbRadius = isChecked() ? mThumbRadius : 0;
        long elapsed = System.currentTimeMillis() - mStartTime;
        switch (mState) {
            case StateNormal:
                break;
            case StateTouchDown:
                ripplePaint.setAlpha(255);
                if (elapsed < ANIMATION_DURATION) {
                    rippleRadius = Math.round(elapsed * mRippleRadius / ANIMATION_DURATION);
                } else {
                    rippleRadius = mRippleRadius;
                }
                postInvalidate();
                break;
            case StateTouchUp:
                if (elapsed < ANIMATION_DURATION) {
                    int alpha = Math.round((ANIMATION_DURATION - elapsed) * 255 / ANIMATION_DURATION);
                    ripplePaint.setAlpha(alpha);
                    rippleRadius = Math.round((ANIMATION_DURATION - elapsed) * mRippleRadius / ANIMATION_DURATION);
                    if (isChecked()) {
                        thumbRadius = Math.round(elapsed * mThumbRadius / ANIMATION_DURATION);
                    } else {
                        thumbRadius = Math.round((ANIMATION_DURATION - elapsed) * mThumbRadius / ANIMATION_DURATION);
                    }
                } else {
                    mState = StateNormal;
                    rippleRadius = 0;
                    ripplePaint.setAlpha(0);
                }
                postInvalidate();
                break;
        }
        if (isChecked()) {
            ripplePaint.setColor(rippleColor(mCheckedColor));

            borderPaint.setColor(mCheckedColor);
            borderPaint.setStyle(Paint.Style.STROKE);
            borderPaint.setStrokeWidth(mStrokeWidth);
        } else {
            ripplePaint.setColor(rippleColor(mColor));

            borderPaint.setColor(mColor);
            borderPaint.setStyle(Paint.Style.STROKE);
            borderPaint.setStrokeWidth(mStrokeWidth);
        }
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, rippleRadius, ripplePaint);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, borderPaint);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, thumbRadius, thumbPaint);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM