开关按钮实现

1、原理和效果图

开关按钮实现

总共有两张图片,一张背景图片,一张遮罩图片。背景图片有开关字样,通过遮住一个字来实现开关按钮。继承自View控件,通过Canvas和Paint结合来实现图片的绘制。

通过canvas的drawBitmap方法和距离左边的位置来绘制图片,调用invalidate方法来不断的更新UI,就可以实现滑动的效果。

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 对象显示的屏幕上,有几个重要步骤:

	 * 1、构造方法 创建 对象。

	 * 2、测量view的大小。	onMeasure(int,int);

	 * 3、确定view的位置 ,view自身有一些建议权,决定权在 父view手中。  onLayout();

	 * 4、绘制 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);

	}

}

2、布局文件

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

3、调用

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();

				}

			}

		});




你可能感兴趣的:(实现)