android仿iso7扁平开关按钮

CSDN博客已经不在使用,转载请注明出处:http://my.oschina.net/witype716/blog/412738

其实平时研究的东西挺多的,只是没有找时间将他们记录下来,这几天过端午节时间很充裕,所以没事来做了一个switch button。当让如果只是纯写一个这样的自定义View并没有什么难度,只是要搞明白这其中的原理,下面附一篇博文,讲的是android自定义view的原理,深入浅出,有一定基础的同学可以去看看,有4个部分,看完了在理解本文应该就没什么问题了。

Android LayoutInflater原理分析,带你一步步深入了解View(一) 

先附图:

android仿iso7扁平开关按钮_第1张图片android仿iso7扁平开关按钮_第2张图片

实现是效果就是在拨动开关是时候,有一个加长的趋势,左边为false,右边为true,用户通过拖动按钮,拖动过程当中,拖动的按钮会变成一个圆角矩形,在背景的圆角矩形中移动,当移动到要靠近用户手势的趋势位置的时候,会自动靠拢,并且背景颜色会更具当前的true和false渐变的改变颜色。

下面先看一下设计原理

android仿iso7扁平开关按钮_第3张图片

图中

1:true状态的中心点,false状态是对称的。

2:为一个圆角矩形,圆角度数为height/2,也可以根据自己的喜好设计。

3:黑框为中心圆形按钮和外圆角矩形的间隔,可以自己调整,看着舒服就行。


在贴代码之前吧程序中几点需要注意的贴出来下。

//switch按钮状态发生改变的借口
public interface onCheckChangeListener{
		
		void onCheckChanged(View view,boolean isChecked);
	}
// 设置监听器
public void setOnCheckChangeListener(onCheckChangeListener l){
		if(null!=l)
			this.checkChange = l;
	}
//覆盖父类的方法,这样空间的大小就可以锁定了,不然会填充所有的父视图
@Override
		protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
			// TODO Auto-generated method stub
			int measuredWidth = MeasureSpec.getSize((int) mRect.width());
			int measuredHeight = MeasureSpec.getSize((int) mRect.height());
			setMeasuredDimension(measuredWidth, measuredHeight);
		}


package open.witype.slidingSwitch;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * 
 * @author WiType716
 * 
 */
public class SlidingButton extends View {

    public SlidingButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // TODO Auto-generated constructor stub
        init();
    }

    public SlidingButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
//        cPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//        cPaint.setStyle(Paint.Style.FILL);
//        cPaint.setColor(Color.rgb(255, 255, 255));
//
//        tPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//        tPaint.setStyle(Paint.Style.FILL);
//        tPaint.setColor(Color.rgb(98, 195, 208));
//
//        fPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//        fPaint.setStyle(Paint.Style.FILL);
//        fPaint.setColor(Color.rgb(220, 220, 220));
//        TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.sliding_switch);
//        c_color = ta.getColor(R.styleable.sliding_switch_slideColor,Color.rgb(255, 255, 255));
//        t_color = ta.getColor(R.styleable.sliding_switch_backgroundOn,Color.rgb(98, 195, 208));
//        f_color = ta.getColor(R.styleable.sliding_switch_backgroundOff, Color.rgb(220, 220, 220));
        init();
    }

    public SlidingButton(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        init();
    }

    private int width = 128;

    private int height = width / 2;

    private int oofset = height;

    private RectF mRect = new RectF(0, 0, width, height);

    private Paint cPaint;

    private Paint tPaint;

    private Paint fPaint;
    
    private int c_color;
    
    private int t_color;
    
    private int f_color;
    // 间隔
    private int space = 2;
    // 半径(等于圆角矩形的圆角度数 - space)
    private float circelRadius = mRect.height() / 2 - space;
    // 左边的中心X点(等于矩形圆角度数+space)
    private float leftCenter = mRect.height() / 2 + space;
    // 右边的中心X点(等于矩形的宽 - 圆的半径 - space)
    private float rightCneter = mRect.width() - (circelRadius + space);
    // Y轴的中心,始终不变
    private float lrCenterY = mRect.height() / 2;
    // 标识现在中间圆圈的状态LEFT = false,RIGHT = true;
    private STATE state = STATE.LEFT;
    // 是否被选中
    private boolean isChoise = false;
    // 点击后的时间监听
    private onCheckChangeListener checkChange;

    public void setOnCheckChangeListener(onCheckChangeListener l) {
        if (null != l)
            this.checkChange = l;
    }

    public interface onCheckChangeListener {

        void onCheckChanged(View view, boolean isChecked);
    }

    enum STATE {
        LEFT, RIGHT, MOVE
    }

    public boolean isChecked() {
        // TODO Auto-generated method stub
        return isChoise;
    }

    public void setChecked(boolean checked) {
        // TODO Auto-generated method stub
        this.isChoise = checked;
        switch (state) {
        case LEFT:
            if (checked) {
                state = STATE.RIGHT;
                invalidate();
            }
            break;
        case RIGHT:
            if (!checked) {
                state = STATE.LEFT;
                invalidate();
            }
            break;
        default:
            break;
        }
    }

    private void init() {
        c_color = Color.rgb(255, 255, 255);
        t_color = Color.rgb(98, 195, 208);
        f_color = Color.rgb(220, 220, 220);
        // 三个画笔分别是,按钮,背景true,和背景false
        cPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        cPaint.setStyle(Paint.Style.FILL);
        cPaint.setColor(c_color);

        tPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        tPaint.setStyle(Paint.Style.FILL);
        tPaint.setColor(t_color);

        fPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        fPaint.setStyle(Paint.Style.FILL);
        fPaint.setColor(f_color);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);
        switch (state) {
        case LEFT:
            fPaint.setColor(Color.rgb(220, 220, 220));
            canvas.drawRoundRect(mRect, mRect.height() / 2, mRect.height() / 2,
                    fPaint);
            canvas.drawCircle(leftCenter, lrCenterY, circelRadius, cPaint);
            break;
        case RIGHT:
            tPaint.setColor(Color.rgb(98, 195, 208));
            canvas.drawRoundRect(mRect, mRect.height() / 2, mRect.height() / 2,
                    tPaint);
            canvas.drawCircle(rightCneter, lrCenterY, circelRadius, cPaint);
            break;
        case MOVE:
            // 处理当前按下的点,始终保持X轴在left和right之间
            if (nowX < leftCenter) {
                nowX = leftCenter;
            } else if (nowX > rightCneter) {
                nowX = rightCneter;
            }
            // 绘制背景的渐变,其实颜色的改变就是设置true背景的透明度,
            float x = (nowX - circelRadius - space)
                    / (rightCneter - leftCenter + space);
            canvas.drawRoundRect(mRect, mRect.height() / 2, mRect.height() / 2,
                    fPaint);
            tPaint.setColor(Color.argb((int) (255 * x), 98, 195, 208));
            RectF truebg = new RectF(mRect);
            canvas.drawRoundRect(truebg, mRect.height() / 2,
                    mRect.height() / 2, tPaint);
            RectF temp = new RectF();
            float right = 0;
            float left = space;
            /*
             * 检查按钮是否越过了中线 如果越过了中线, 向右移动:那么按钮左边应该收缩,右边应该向背景的右边靠拢
             * 向左移动:反之,右边收缩,左边向向背景左边靠拢
             */
            // 越过了中线 toRight
            if (nowX > mRect.width() / 2) {
                // 保证圆角按钮的右边开始收缩,按钮充椭圆向圆形变形
                right = (nowX + circelRadius) + oofset * (1 - x);
                // 按钮左边趋势不变
            }
            // toLeft
            else {
                right = (nowX + circelRadius) + oofset * x;
            }
            if (right > mRect.width() / 3) {
                left = nowX - circelRadius - oofset * (1 - x);
            }
            if (right > mRect.width() - space)
                right = mRect.width() - space;
            if (left < space)
                left = space;
            if (nowX <= leftCenter) {
                if (right - left > circelRadius * 2) {
                    right = right - ((right - left) - circelRadius * 2) / 2;
                    left = left + ((right - left) - circelRadius * 2) / 2;
                }
            }
            // 按钮是上和下可以不用改变,始终是space是距离
            temp.set(left, space, right, mRect.height() - space);
            canvas.drawRoundRect(temp, temp.height() / 2, temp.height() / 2,
                    cPaint);
            // circelMehtonB(canvas);
            break;
        }
    }

    public void circelMehtonB(Canvas canvas) {
        RectF rect = new RectF();
        float left = nowX - circelRadius - space;
        float right = nowX + circelRadius;
        float length = mRect.width() / 2;
        float x = mRect.width() / 2 - nowX / length;
        float temp = length - Math.abs((mRect.width() / 2 - nowX));
        Log.d("switch", length - Math.abs((mRect.width() / 2 - nowX)) + " / "
                + length);
        left = (float) (left - temp * 0.1);
        right = (float) (right + temp * 0.1);
        if (right >= mRect.width() / 10 * 9) {
            right = mRect.width() - space;
        }
        if (left <= mRect.width() / 10) {
            left = space;
        }
        rect.set(left, space, right, mRect.height() - space);
        canvas.drawRoundRect(rect, rect.height() / 2, rect.height() / 2, cPaint);
    }

    /**
     * 
     * @param canvas
     * @param x
     */
    public void circelMethonA(Canvas canvas, float x) {
        // 当中间圆圈移动后,绘制椭圆

    }

    private float oldX;

    private float nowX;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            oldX = event.getX();
            break;
        case MotionEvent.ACTION_MOVE:
            state = STATE.MOVE;
            nowX = event.getX();
            break;
        case MotionEvent.ACTION_UP:
            if (event.getX() > mRect.width() / 2) {
                state = STATE.RIGHT;
                isChoise = true;
            } else {
                state = STATE.LEFT;
                isChoise = false;
            }
            if (null != checkChange)
                checkChange.onCheckChanged(this, isChoise);
            break;
        }
        invalidate();
        return true;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // TODO Auto-generated method stub
        int measuredWidth = MeasureSpec.getSize((int) mRect.width());
        int measuredHeight = MeasureSpec.getSize((int) mRect.height());
        setMeasuredDimension(measuredWidth, measuredHeight);
    }
}


后续有时间了在改下,改的更智能化和个性化,现在就这样子吧,


你可能感兴趣的:(android,switch,自定义,button)