1. 程式人生 > >android仿IOS選擇(switch)開關

android仿IOS選擇(switch)開關

       最近看見很多應用用這種仿IOS的開關控制元件,最近專案組也有要用到這個控制元件的需要,實際上最簡單的方法是,直接讓UI提供兩張圖片就可以了,分別代表開啟和關閉的狀態,但是UI實在是不給力,圖片遲遲不到,所以,作為一個勤奮好學,自力更生的android程式設計師來說,好吧,果斷自己自定義一個。

    其實,要實現這個功能,也不是很難,可以說非常easy。就是通過canvas畫一個底層橢圓形的矩形,然後上面畫一個開關的小圓圈,底層顏色和小圓圈所處位置根據開關狀態不同顯示。好了,先上圖。


最後效果圖就是這樣的。程式碼如下:

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

程式碼中各個方法都註釋的比較詳細,具體的我就不介紹了。最後附上專案原始碼