Android自定義View-SwitchView(自定義開關)

Android自定義View-SwitchView(自定義開關)

Android自定義開關,效果圖如圖:

  

一個是關的狀態,一個是開的狀態,通過監聽回調將滑塊滑動狀態返回到調用界面。

實質上底層是一個背景,然後在這個背景之上增加了一個可移動滑塊,通過判斷滑塊滑動之後的位置,在背景圖中心點左邊表示開關是開,在右邊表示是關。

      

1.自定義view類

SwitchView:主要是用來繪製開關背景及滑塊,並通過滑塊移動位置來判斷狀態。

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * @author M.xang
 * @時間 2019年4月22日
 * @描述 自定義開關控件
 */
public class SwitchView extends View {

	private Bitmap switchBackgroupBitmap = null; // 背景圖片
	private Bitmap slideButtonBitmap = null; // 滑塊圖片
	private Paint paint = null; // 畫筆
	private boolean mSwitchState = false; // 開關狀態, 默認false
	private float currentX;
	private int width_bg = 0, height_bg = 0;
	@SuppressWarnings("unused")
	private int width_slide = 0, height_slide = 0;

	/**
	 * 用於代碼創建控件
	 * 
	 * @param context
	 */
	public SwitchView(Context context) {
		super(context);
		init();
	}

	/**
	 * 用於在xml裏使用, 可指定自定義屬性
	 *
	 * @param context
	 * @param attrs
	 */
	public SwitchView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
		// 獲取配置的自定義屬性
		setSwitchBackgroundResource(R.drawable.switch_bg);// 開關背景
		setSlideButtonResource(R.drawable.switch_control);// 滑塊背景
	}

	private void init() {
		paint = new Paint();
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// 依據背景圖片來確定控件大小
		width_bg = switchBackgroupBitmap.getWidth();
		height_bg = switchBackgroupBitmap.getHeight();
		if (slideButtonBitmap != null) {
			width_slide = slideButtonBitmap.getWidth();
			height_slide = slideButtonBitmap.getHeight();
		}
		setMeasuredDimension(width_bg, height_bg);
	}

	// Canvas 畫布, 畫板. 在上邊繪製的內容都會顯示到界面上.
	@Override
	protected void onDraw(Canvas canvas) {
		// 1. 繪製背景
		canvas.drawBitmap(switchBackgroupBitmap, 0, 0, paint);
		// 2. 繪製滑塊
		if (isTouchMode) {
			// 根據當前用戶觸摸到的位置畫滑塊
			// 讓滑塊向左移動自身一半大小的位置
			float newLeft = currentX - width_slide / 2.0f;
			int maxLeft = width_bg - width_slide;
			// 限定滑塊範圍
			if (newLeft < 0) {
				newLeft = 0; // 左邊範圍
			} else if (newLeft > maxLeft) {
				newLeft = maxLeft; // 右邊範圍
			}
			canvas.drawBitmap(slideButtonBitmap, newLeft, 0, paint);
		} else {
			// 根據開關狀態boolean, 直接設置圖片位置
			if (mSwitchState) {// 開,開關滑塊置於最右邊,顯示ON
				canvas.drawBitmap(slideButtonBitmap, 0, 0, paint);
			} else {// 關,開關滑塊置於最左邊,顯示OFF
				int newLeft = width_bg - width_slide;
				if (slideButtonBitmap != null) {
					canvas.drawBitmap(slideButtonBitmap, newLeft, 0, paint);
				}
			}
		}
	}

	boolean isTouchMode = false;
	private OnSwitchStateUpdateListener onSwitchStateUpdateListener;

	// 重寫觸摸事件, 響應用戶的觸摸.
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			isTouchMode = true;
			currentX = event.getX();
			break;
		case MotionEvent.ACTION_MOVE:
			currentX = event.getX();
			break;
		case MotionEvent.ACTION_UP:
			isTouchMode = false;
			currentX = event.getX();
			float center = width_bg / 2.0f;
			// 根據當前按下的位置, 和控件中心的位置進行比較.
			boolean state = currentX < center;// 離開位置小於中心位置,點擊了關,true
			// 如果開關狀態變化了, 通知界面. 裏邊開關狀態更新了.
			if (state != mSwitchState && onSwitchStateUpdateListener != null) {
				// 把最新的boolean, 狀態傳出去了
				onSwitchStateUpdateListener.onStateUpdate(state);
			}
			mSwitchState = state;
			break;
		}
		// 重繪界面
		invalidate(); // 會引發onDraw()被調用, 裏邊的變量會重新生效.界面會更新
		return true; // 消費了用戶的觸摸事件, 纔可以收到其他的事件.
	}

	/**
	 * 設置背景圖
	 *
	 * @param switchBackground
	 */
	public void setSwitchBackgroundResource(int switchBackground) {
		if (switchBackground > 0) {
			switchBackgroupBitmap = BitmapFactory.decodeResource(getResources(), switchBackground);
		} else {
			Log.e("---SlideSwitchView--->", "沒有設置開關背景圖,應設置app:switch_background=\"@drawable/xxx\"");
		}
	}

	/**
	 * 設置滑塊圖片資源
	 *
	 * @param slideButton
	 */
	public void setSlideButtonResource(int slideButton) {
		if (slideButton > 0) {
			slideButtonBitmap = BitmapFactory.decodeResource(getResources(), slideButton);
		} else {
			Log.e("---SlideSwitchView--->", "沒有設置滑動按鈕圖,應設置app:slide_button=\"@drawable/xxx\"");
		}
	}

	/**
	 * 設置開關初始狀態
	 * 
	 * @param mSwitchState true:默認開,false:默認關
	 */
	public void setSwitchState(boolean mSwitchState) {
		this.mSwitchState = mSwitchState;
	}

	/**
	 * 設置開關初始狀態
	 * 
	 * @param state true:開,false:關
	 */
	public void setSwitchOpen(boolean state) {
		mSwitchState = state;
		invalidate(); // 會引發onDraw()被調用, 裏邊的變量會重新生效.界面會更新
	}

	/**
	 * @author M.xang
	 * @時間 2019年4月22日
	 * @描述 開關狀態回調
	 */
	public interface OnSwitchStateUpdateListener {
		/**
		 * 狀態回調, 開關當前狀態
		 * 
		 * @param state
		 */
		void onStateUpdate(boolean state);
	}

	/**
	 ** 將回調對象傳到控件
	 * 
	 * @param onSwitchStateUpdateListener
	 */
	public void setOnSwitchStateUpdateListener(OnSwitchStateUpdateListener onSwitchStateUpdateListener) {
		this.onSwitchStateUpdateListener = onSwitchStateUpdateListener;
	}

}

2.使用

再佈局中的使用:

<com.view.SwitchView
            android:id="@+id/sw_computer"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

在Activity中調用:

// 進行實例化
SwitchView sw_computer = sw_computer = UIUtil.findView(this, R.id.sw_computer);
// 設置開關的初始狀態,默認是關閉的
sw_computer.setSwitchState(false);

// 開關點擊事件
sw_computer.setOnSwitchStateUpdateListener(new OnSwitchStateUpdateListener() {
    @Override
    public void onStateUpdate(boolean state) {
	
        // state 爲 true是開,false是關

    }
});

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章