開關按鈕實現

一、原理和效果圖

總共有兩張圖片,一張背景圖片,一張遮罩圖片。背景圖片有開關字樣,經過遮住一個字來實現開關按鈕。繼承自View控件,經過Canvas和Paint結合來實現圖片的繪製。html

經過canvas的drawBitmap方法和距離左邊的位置來繪製圖片,調用invalidate方法來不斷的更新UI,就能夠實現滑動的效果。java

public class MyToggleButton extends View implements OnClickListener{
	/**
	 * 作爲背景的圖片
	 */
	private Bitmap backgroundBitmap;
	/**
	 * 能夠滑動的圖片
	 */
	private Bitmap slideBtn;
	private Paint paint;
	/**
	 * 滑動按鈕的左邊屆
	 */
	private float slideBtn_left;
	/**
	 * 當前開關的狀態
	 *  true 爲開
	 */
	private boolean currState = false;
	/**
	 * 判斷是否發生拖動,若是拖動了,就再也不響應 onclick 事件
	 */
	private boolean isDrag = false;
	/**
	 * 在代碼裏面建立對象的時候,使用此構造方法
	 */
	public MyToggleButton(Context context) {
		super(context);
	}

	/**
	 * 在佈局文件中聲名的view,建立時由系統自動調用。
	 * @param context	上下文對象
	 * @param attrs		屬性集
	 */
	public MyToggleButton(Context context, AttributeSet attrs) {
		super(context, attrs);
		initView();
	}
	
	/**
	 * 初始化
	 */
	private void initView() {
		//初始化圖片
		backgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
		slideBtn = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);
		//初始化 畫筆
		paint = new Paint();
		paint.setAntiAlias(true); // 打開抗矩齒
		
		//添加onclick事件監聽
		setOnClickListener(this);
	}

	/*
	 * view 對象顯示的屏幕上,有幾個重要步驟:
	 * 一、構造方法 建立 對象。
	 * 二、測量view的大小。	onMeasure(int,int);
	 * 三、肯定view的位置 ,view自身有一些建議權,決定權在 父view手中。  onLayout();
	 * 四、繪製 view 的內容 。 onDraw(Canvas)
	 */
	
	
	/**
	 * 測量尺寸時的回調方法 
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		/**
		 * 設置當前view的大小
		 * width  :view的寬度
		 * height :view的高度   (單位:像素)
		 */
		try {
			setMeasuredDimension(backgroundBitmap.getWidth(),backgroundBitmap.getHeight());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}


	
	@Override
	/**
	 * 繪製當前view的內容
	 */
	protected void onDraw(Canvas canvas) {
//		super.onDraw(canvas);
		
		// 繪製 背景
		/*
		 * backgroundBitmap	要繪製的圖片
		 * left	圖片的左邊屆
		 * top	圖片的上邊屆
		 * paint 繪製圖片要使用的畫筆
		 */
		canvas.drawBitmap(backgroundBitmap, 0, 0, paint);
		 
		//繪製 可滑動的按鈕
		canvas.drawBitmap(slideBtn, slideBtn_left, 0, paint);
	}

	
	@Override
	/**
	 * onclick 事件在View.onTouchEvent 中被解析。
	 * 系統對onclick 事件的解析,過於簡陋,只要有down 事件  up 事件,系統即認爲 發生了click 事件
	 * 
	 */
	public void onClick(View v) {
		if(!isDrag){ //若是沒有拖動,才執行改變狀態的動做
			currState = !currState;
			flushState();
		}
	}


	
	/**
	 * down 事件時的x值
	 */
	private int firstX;
	/**
	 * touch 事件的上一個x值
	 */
	private int lastX;
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		super.onTouchEvent(event);
		
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			firstX = lastX =(int) event.getX();
			isDrag = false;
			break;
		case MotionEvent.ACTION_MOVE:
			//判斷是否發生拖動
			if(Math.abs(event.getX()-firstX)>5){
				isDrag = true;
			}
			
			//計算 手指在屏幕上移動的距離
			int dis = (int) (event.getX() - lastX);
			
			//將本次的位置 設置給lastX
			lastX = (int) event.getX();
			
			//根據手指移動的距離,改變slideBtn_left 的值
			slideBtn_left = slideBtn_left+dis;
			break;
		case MotionEvent.ACTION_UP:
			//在發生拖動的狀況下,根據最後的位置,判斷當前開關的狀態
			if (isDrag) {
				int maxLeft = backgroundBitmap.getWidth() - slideBtn.getWidth(); // slideBtn左邊屆最大值
				/*
				 * 根據 slideBtn_left 判斷,當前應是什麼狀態
				 */
				if (slideBtn_left > maxLeft / 2) { // 此時應爲 打開的狀態
					currState = true;
				} else {
					currState = false;
				}

				flushState();
			}
			break;
		}
		
		flushView();
		
		return true; 
	}

	/**
	 * 刷新當前狀態
	 */
	private void flushState() {
		if(currState){
			slideBtn_left = backgroundBitmap.getWidth()-slideBtn.getWidth();
		}else{
			slideBtn_left = 0;
		}
		mToggleSwitch.openOrClose(currState);
		flushView(); 
	}
	
	/**
	 * 刷新當前視力
	 */
	private void flushView() {
		//對 slideBtn_left  的值進行判斷 ,確保其在合理的位置 即       0<=slideBtn_left <=  maxLeft
		int maxLeft = backgroundBitmap.getWidth()-slideBtn.getWidth();	//	slideBtn 左邊屆最大值
		
		//確保 slideBtn_left >= 0
		slideBtn_left = (slideBtn_left>0)?slideBtn_left:0;
		
		//確保 slideBtn_left <=maxLeft
		slideBtn_left = (slideBtn_left<maxLeft)?slideBtn_left:maxLeft;
		/*
		 * 刷新當前視圖  致使 執行onDraw執行
		 */
		invalidate();
	}


	public void setmToggleSwitch(ToggleSwitch mToggleSwitch) {
		this.mToggleSwitch = mToggleSwitch;
	}

	private ToggleSwitch mToggleSwitch;
	
	public interface ToggleSwitch {
		/**
		 * true 爲開 ,false 爲關
		 * @param open
		 */
		public void openOrClose(boolean open);
	}
}

二、佈局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <com.example.MyToggleButton
        android:id="@+id/my_toggle_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
         />

</RelativeLayout>

三、調用

myToggleButton = (MyToggleButton) findViewById(R.id.my_toggle_btn);

		myToggleButton.setmToggleSwitch(new ToggleSwitch() {
			@Override
			public void openOrClose(boolean open) {
				if (open) {
					Toast.makeText(MainActivity.this, "打開", Toast.LENGTH_SHORT).show();
				}else {
					Toast.makeText(MainActivity.this, "關閉", Toast.LENGTH_SHORT).show();
				}
			}
		});
相關文章
相關標籤/搜索