Android学习(43) -- 自定义控件(7) 滑动开关

简介

自定义控件步骤:           

1. 写类继承View           
2. 重写onDraw, 进行绘制   
3. 重新onMeasure,修改尺寸   要使用 setMeasuredDimension设置当前自定义View的大小
4. 在xml布局文件中配置    

可能需要重写的方法:

      测量:onMeasure  设置自己显示在屏幕上的宽高     在重写这个方法时,必须调用setMeasuredDimension(int, int)来存储测量得到的宽度和高度值

       布局:onLayout   设置自己显示在屏幕上的位置(只有在自定义ViewGroup中才用到)     需要调用各自的layout(int, int, int, int)方法
      绘制:onDraw     控制显示在屏幕上的样子(自定义viewgroup时不需要这个)


View和ViewGroup的区别
      1.他们都需要进行测量操作
      2.ViewGroup主要是控制子view如何摆放,所以必须实现onLayout

        View没有子view,所以不需要onLayout方法,但是必须实现onDraw


自定义控件实际操作:

1、创建类继承View  

2、重写两个构造器

3、重写 

            onMeasure并调用setMeasuredDimension方法设置控件的宽和高

           onDraw      绘制自己显示在屏幕上的样子

4、定义操作控件的方法

        a、设置开关块的图片

b、设置开关背景的图片

c、设置更改开关状态的方法

5、定义onTouchEvent事件

6、定义接口对外开关状态



效果

Android学习(43) -- 自定义控件(7) 滑动开关_第1张图片


定义View

1、创建类继承View  

2、重写两个构造器

3、重写 

            onMeasure并调用setMeasuredDimension方法设置控件的宽和高

           onDraw      绘制自己显示在屏幕上的样子

4、定义操作控件的方法

        a、设置开关块的图片

b、设置开关背景的图片

c、设置更改开关状态的方法

public class MySwitch extends View {

	private SwitchState sState; // 开关状态
	private Bitmap slideBitmap;
	private Bitmap switchBitmap;
	
	/**
	 * 如果自定义的View只是在布局文件中使用,只需要重写这个构造方法
	 * 
	 * @param context
	 * @param attrs
	 */
	public MySwitch(Context context, AttributeSet attrs) {
		super(context, attrs);

	}

	/**
	 * 如果自定义的View是在Java代码中动态的new出来,需要重写这个构造方法
	 * 
	 * @param context
	 */
	public MySwitch(Context context) {
		super(context);
	}

	/**
	 * 设置活动块的图片
	 */
	public void setSlideBackgroudResource(int slideBackground) {
		// 将资源文件转换为Bitmap
		slideBitmap = BitmapFactory.decodeResource(getResources(),
				slideBackground);
	}

	/**
	 * 设置switch的图片
	 * 
	 * @param switchBackground
	 */
	public void setSwitchBackgroundResource(int switchBackground) {
		// 将资源文件转换为Bitmap
		switchBitmap = BitmapFactory.decodeResource(getResources(),
				switchBackground);
	}

	/**
	 * Switch开关状态的枚举
	 * 
	 * @author Denny
	 * @date 2016-4-25
	 */
	public enum SwitchState {
		OPEN, CLOSE
	}

	/**
	 * 设置Switch开关状态
	 * 
	 * @param open
	 */
	public void setSwitchState(SwitchState open) {
		sState = open;
	}

	/**
	 * 设置当前控件在屏幕上的宽和高
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);

		// 设置当前View的大小 这个方法决定了当前View的大小
		setMeasuredDimension(switchBitmap.getWidth(), switchBitmap.getHeight());
	}

	/**
	 * 绘制自己显示在屏幕上的样子
	 */
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		// 1.在某一个位置 绘制背景图片
		// left:图片的左边的x坐标
		// top:图片的顶部的y坐标
		canvas.drawBitmap(switchBitmap, 0, 0, null);

		// 2.绘制滑动块图片
		
		//当抬起的时候 绘制滑动块的位置
		// 根据SwitchState 确定滑动块的位置
		// 如果滑动块在左边的话 left:0 top:0
		// 如果滑动块在右边:left : 背景的宽 - 滑动块的宽 top:0
		if (sState == SwitchState.OPEN) {
			canvas.drawBitmap(slideBitmap, switchBitmap.getWidth()
					- slideBitmap.getWidth(), 0, null);
		} else if (sState == SwitchState.CLOSE) {
			canvas.drawBitmap(slideBitmap, 0, 0, null);
		}		

	}
}


5、定义onTouchEvent事件

1、Android中有两套坐标:

Android学习(43) -- 自定义控件(7) 滑动开关_第2张图片

2、开关要有两种操作

a、根据滑动块 滑动  操作
b、根据滑动块 状态 操作

2.1定义成员

定义一个变量用于判断是根据滑动还是 根据状态进行 操作

private boolean isSliding = false;  


定义一个变量 用于获取滑动位置的x点
private int currentX; // 当前触摸点的x坐标

2.2当onTouchEvent事件中处理 滑动块滑动 操作

     a、在ACTION_DOWN中  isSliding 设置为   true; 表示要滑动
     b、 当ACTION_UP事件中  判断  判断当前x值和中间线的大小  更改SwitchState :
如果大于等于 SwitchState 则设置为OPEN  ,否则设置为CLOSE
            
  
            不要忘记,调用invalidate()方法,请求重新draw()

	@Override
	public boolean onTouchEvent(MotionEvent event) {

		// 获取当前的x点
		currentX = (int) event.getX();

		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			isSliding = true;
			break;
		case MotionEvent.ACTION_MOVE:

			break;
		case MotionEvent.ACTION_UP:
			isSliding = false;
			//获取中间线
			int centernX = switchBitmap.getWidth() / 2;
			//判断当前x值和中间线的大小  更改SwitchState
			if( currentX >= centernX){
				//open
				if(sState != SwitchState.OPEN){
					sState = SwitchState.OPEN;
				}
			}else{
				//close
				if(sState != SwitchState.CLOSE){
					sState = SwitchState.CLOSE;
				}
			}
			
			break;
		}

		// 调用invalidate()方法,请求重新draw()
		invalidate();
		return true;
	}


2.3在onDraw中根据 isSliding来 根据 滑动还是 状态 来绘制
protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		// 1.在某一个位置 绘制背景图片
		// left:图片的左边的x坐标
		// top:图片的顶部的y坐标
		canvas.drawBitmap(switchBitmap, 0, 0, null);

		// 2.绘制滑动块图片
		//如果是滑动的话 则根据currentX来进行操作
		if(isSliding ){
			
			//当鼠标移动到slideBitmap一半的时候才会有响应
			int left = currentX - slideBitmap.getWidth() / 2;
			//如果left
			if (left < 0) {
				left = 0;
			}
			int maxX = switchBitmap.getWidth() - slideBitmap.getWidth();
			if (left > (maxX)) {
				left = maxX;
			}
			canvas.drawBitmap(slideBitmap, left, 0, null);
		}else{
			//当抬起的时候 绘制滑动块的位置
			// 根据SwitchState 确定滑动块的位置
			// 如果滑动块在左边的话 left:0 top:0
			// 如果滑动块在右边:left : 背景的宽 - 滑动块的宽 top:0
			if (sState == SwitchState.OPEN) {
				canvas.drawBitmap(slideBitmap, switchBitmap.getWidth()
						- slideBitmap.getWidth(), 0, null);
			} else if (sState == SwitchState.CLOSE) {
				canvas.drawBitmap(slideBitmap, 0, 0, null);
			}
		}

	}




 
  

6、定义接口对外开关状态

a、定义接口对外开关状态的方法

b、定义根据接口来更改状态的方法

	public interface OnSwitchStateChangedListern{
		void onSwitchStateChenged(SwitchState state);
	}
	
	private OnSwitchStateChangedListern  listern;

	public void setOnSwitchStateChangedListern(OnSwitchStateChangedListern listern) {
		this.listern = listern;
	}


c、将监听 添加到 滑动时候

	public boolean onTouchEvent(MotionEvent event) {

		// 获取当前的x点
		currentX = (int) event.getX();

		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			isSliding = true;
			break;
		case MotionEvent.ACTION_MOVE:

			break;
		case MotionEvent.ACTION_UP:
			isSliding = false;
			//获取中间线  
			int centernX = switchBitmap.getWidth() / 2;
			//判断当前x值和中间线的大小  更改SwitchState
			if( currentX >= centernX){
				//open
				if(sState != SwitchState.OPEN){
					sState = SwitchState.OPEN;
					if(listern != null){
						listern.onSwitchStateChenged(sState);
					}					
				}
			}else{
				//close
				if(sState != SwitchState.CLOSE){
					sState = SwitchState.CLOSE;
					if(listern != null){
						listern.onSwitchStateChenged(sState);
					}	
				}
			}
			
			break;
		}

		// 调用invalidate()方法,请求重新draw()
		invalidate();
		return true;
	}
	



使用

布局文件

<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.togbutton.view.MySwitch
        android:id="@+id/ms_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

</RelativeLayout>

Java代码

public class MainActivity extends Activity {

	private MySwitch mySwitch;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		mySwitch = (MySwitch) findViewById(R.id.ms_btn);

		// 设置滑动块的背景图片
		mySwitch.setSlideBackgroudResource(R.drawable.slide_button);
		// 设置Switch背景图片
		mySwitch.setSwitchBackgroundResource(R.drawable.switch_background);
		// 设置更改Switch的开关状态
		mySwitch.setSwitchState(SwitchState.OPEN);
		// 设置Switch的开关状态监听器
		mySwitch.setOnSwitchStateChangedListern(new OnSwitchStateChangedListern() {

			@Override
			public void onSwitchStateChenged(SwitchState state) {
				Toast.makeText(MainActivity.this,
						state == SwitchState.OPEN ? "开启" : "关闭", 0).show();
			}
		});
	}
}



你可能感兴趣的:(Android学习(43) -- 自定义控件(7) 滑动开关)