天天看点

android仿IOS选择(switch)开关

       最近看见很多应用用这种仿IOS的开关控件,最近项目组也有要用到这个控件的需要,实际上最简单的方法是,直接让UI提供两张图片就可以了,分别代表打开和关闭的状态,但是UI实在是不给力,图片迟迟不到,所以,作为一个勤奋好学,自力更生的android程序员来说,好吧,果断自己自定义一个。

    其实,要实现这个功能,也不是很难,可以说非常easy。就是通过canvas画一个底层椭圆形的矩形,然后上面画一个开关的小圆圈,底层颜色和小圆圈所处位置根据开关状态不同显示。好了,先上图。

android仿IOS选择(switch)开关

android仿IOS选择(switch)开关

最后效果图就是这样的。代码如下:

package com.lyq.customSwitch;

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.view.View;
import android.view.View.OnClickListener;

/**
 * 仿IOS选择开关
 * @author mufeng
 *
 */
public class Switch extends View implements OnClickListener{

	private Context mContext;
	private Paint mPaint;
	private float width,height;
	private boolean isOpen=true;
	private RectF oval;

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

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

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

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

	private void init(Context context) {
		mContext=context;
		//设置宽高 
		width=DensityUtils.dip2px(mContext, 80);
		height=width/2;
		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		setOnClickListener(this);
		oval = new RectF(0, 0, width, height);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		
		//根据控件当前状态设置画笔颜色
		if(isOpen){
			mPaint.setColor(getResources().getColor(R.color.select));
		}else{
			mPaint.setColor(Color.GRAY);
		}
		mPaint.setStyle(Paint.Style.FILL);// 充满
		
		//画底层圆角矩形
		canvas.drawRoundRect(oval,height/2 , width/4, mPaint);// 第二个参数是x半径,第三个参数是y半径
		
		//画开关圆圈 将画笔颜色设为白色 
		mPaint.setColor(Color.WHITE);
		//根据控件当前状态判断将圆圈画在左边还是右边
		if(isOpen){
			canvas.drawCircle(width/4*3, height/2, height/2-DensityUtils.dip2px(mContext, 2), mPaint);
		}else{
			canvas.drawCircle(width/4, height/2, height/2-DensityUtils.dip2px(mContext, 2), mPaint);
		}
	}
	
	@Override  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
        //重新测量控件的大小,主要在控件宽高属性设置为wrap_content时,将控件大小设置为实际大小
		setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));  
    }  
  
	//测量宽度
    private int measureWidth(int measureSpec) {  
        int result = 0;  
        int specMode = MeasureSpec.getMode(measureSpec);  
        int specSize = MeasureSpec.getSize(measureSpec);  
  
        if (specMode == MeasureSpec.EXACTLY) {  
            result = specSize;  
        } else {  
            result = (int) DensityUtils.dip2px(mContext, 80) + getPaddingLeft() + getPaddingRight();  
            if (specMode == MeasureSpec.AT_MOST) {  
                result = Math.min(result, specSize);  
            }  
        }  
  
        return result;  
    }  
  
    //测量高度
    private int measureHeight(int measureSpec) {  
        int result = 0;  
        int specMode = MeasureSpec.getMode(measureSpec);  
        int specSize = MeasureSpec.getSize(measureSpec);  
  
        if (specMode == MeasureSpec.EXACTLY) {  
            result = specSize;  
        } else {  
            result = (int) DensityUtils.dip2px(mContext, 80)/2 + getPaddingTop() + getPaddingBottom();  
            if (specMode == MeasureSpec.AT_MOST) {  
                result = Math.min(result, specSize);  
            }  
        }
        return result;  
    }  
	
    /**
     * 点击切换isOpen值,调用postInvalidate重绘view,可用于异步线程
     */
	@Override
	public void onClick(View view) {
		isOpen=!isOpen;
		postInvalidate();
	}
	
	/**
	 * 打开控件开关
	 */
	public void open(){
		if(!isOpen){
			isOpen=true;
			postInvalidate();
		}
	}
	
	/**
	 * 关闭控件开关
	 */
	public void close(){
		if(isOpen){
			isOpen=false;
			postInvalidate();
		}
	}
	
	/**
	 * 获取控件状态
	 * @return 
	 */
	public boolean isOpen(){
		return isOpen;
	}
}
           

代码中各个方法都注释的比较详细,具体的我就不介绍了。最后附上项目 源码。

继续阅读