c)自定义控件-滑动开关
package cn.zengfansheng.sliptoggle;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
/**
* 滑动开关
*
* @author hacket
*/
public class SlipToggle extends View implements OnTouchListener {
private Bitmap bkg_btnSlip;
private Bitmap bkg_switchOn;
private Bitmap bkg_switchOff;
private Rect btnSlip_switch_on;// 开关开启时滑块坐标
private Rect btnSlip_switch_off;// 开关关闭时滑块坐标
private boolean isToggleStateOn;// 设置开关的状态
private OnToggleStatusListener toggleStatusListener;// 开关状态监听器
private boolean isToggleStatusListenerOn;// 是否开启的开关状态监听
private float slipBtnCurrentX;// 滑块当前的的位置
private boolean isSlipping;// 是否滑块正在滑行
private boolean proToggleState;// 前一个开关的状态,默认为false
// TODO 1、继承View,两个构造方法
public SlipToggle(Context context) {
super(context);
init();
}
public SlipToggle(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
// TODO 5、初始化触摸监听事件,在对象创建时注册开关触摸事件
public void init() {
setOnTouchListener(this);
}
// 6、实现触摸时onTouch的逻辑
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:// 触摸按下
slipBtnCurrentX = event.getX();// 滑块当前的的位置
isSlipping = true;// 是否滑块正在滑行
break;
case MotionEvent.ACTION_MOVE:// 触摸移动
slipBtnCurrentX = event.getX();
break;
case MotionEvent.ACTION_UP:// 触摸松手
//是否滑块在滑行
isSlipping = false;
// 滑块的位置
if (slipBtnCurrentX < bkg_switchOn.getWidth() / 2) {// 当前位置小于背景一半,关闭
isToggleStateOn = false;
} else {
isToggleStateOn = true;
}
// 如果设置了开关状态变化监听器,且和前一个状态不同
if (isToggleStatusListenerOn && isToggleStateOn != proToggleState) {
proToggleState = isToggleStateOn;// 前一个状态更改为现在的状态
toggleStatusListener.onToggleStatus(isToggleStateOn);
}
break;
}
invalidate();
return true;
}
// TODO 7、测量
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(bkg_switchOn.getWidth(), bkg_switchOn.getHeight());
setMeasuredDimension(bkg_switchOn.getWidth(), bkg_switchOn.getHeight());
// FIXME 难点:必须在onMeasure(int,int)调用该方法
}
// TODO 8、绘制
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 8-1)绘制背景
if (isToggleStateOn) {// a)开关开启
canvas.drawBitmap(bkg_switchOn, new Matrix(), null);
} else {// b)开关关闭
canvas.drawBitmap(bkg_switchOff, new Matrix(), null);
}
// 8-2)绘制滑块
float left_slip = 0;// 滑块最左边位置
if (isSlipping) {// FIXME 难点 a)滑块处于滑动状态,当前状态减去滑块的二分之一,保证每次都在滑块中间
left_slip = slipBtnCurrentX - bkg_btnSlip.getWidth() / 2;
} else {// b)滑块处于静止状态
if (isToggleStateOn) {// 如果开关为开启状态
left_slip = bkg_switchOn.getWidth() - bkg_btnSlip.getWidth();
} else {// 开关为关闭状态
left_slip = 0;
}
}
// c)健壮性判断
if (left_slip<0) {//滑块超出最左边
left_slip = 0;
}else if(left_slip>(bkg_switchOn.getWidth()-bkg_btnSlip.getWidth())){//滑块超出最右边
left_slip = bkg_switchOn.getWidth() - bkg_btnSlip.getWidth();
}
// d)开始绘制滑块
canvas.drawBitmap(bkg_btnSlip, left_slip, 0, null);
}
// TODO 2、对外提供一个设置资源的方法
public void setBkgRes(int bkgSwitchOn, int bkgSwitchOff, int bkgBtnSlip) {
bkg_btnSlip = BitmapFactory.decodeResource(getResources(), R.drawable.btn_slip);
bkg_switchOn = BitmapFactory.decodeResource(getResources(), R.drawable.bkg_switch);
bkg_switchOff = BitmapFactory.decodeResource(getResources(), R.drawable.bkg_switch);
// 1、开关开启时滑块坐标
btnSlip_switch_on = new Rect(bkg_switchOn.getWidth()-bkg_btnSlip.getWidth(),0,bkg_switchOn.getWidth(),bkg_switchOn.getHeight());
// 2、开关关闭时滑块坐标
btnSlip_switch_off = new Rect(0,0,bkg_btnSlip.getWidth(),bkg_switchOn.getHeight());
}
//TODO 3、设置开关的状态
public void setToggleState(boolean toggleStatus){
isToggleStateOn = toggleStatus;
}
public interface OnToggleStatusListener {
/**
* 开关状态变化时,执行的方法
* @param toggleState 变化后的开关状态
*/
public abstract void onToggleStatus(boolean toggleState);
}
// TODO 4、监听滑动开关状态的变化,以便于来响应不同的事件
public void setOnToggleStatusListener(OnToggleStatusListener listener) {
toggleStatusListener = listener;
isToggleStatusListenerOn = true;
}
} |