我的视频系列 http://edu.csdn.net/course/detail/2741,一起来学习Android…
代码参考地址 https://github.com/liuzhiyuan0932/SlideUnLock
public class SlideUnlockView extends View
<resources>
<declare-styleable name="SlideUnlockButton">
<attr name="slideUnlockBackgroundResource" format="reference" />
<attr name="slideUnlockBlockResource" format="reference" />
declare-styleable>
resources>
<com.zhiyuan.slideunlockdemo.view.SlideUnlockView
android:id="@+id/slideUnlockView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
test:slideUnlockBackgroundResource="@drawable/jiesuo_bg"
test:slideUnlockBlockResource="@drawable/jiesuo_button" />
/**
* 滑块当前的状态
*/
public int currentState;
/**
* 未解锁
*/
public static final int STATE_LOCK = 1;
/**
* 解锁
*/
public static final int STATE_UNLOCK = 2;
/**
* 正在拖拽
*/
public static final int STATE_MOVING = 3;
public SlideUnlockView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 默认滑动解锁为未解锁状态
currentState = STATE_LOCK;
// 命名空间
String namespace = "http://schemas.android.com/apk/res/com.zhiyuan.slideunlockdemo";
// 取出自定义属性中背景图片
int slideUnlockBackgroundResource = attrs.getAttributeResourceValue(
namespace, "slideUnlockBackgroundResource", -1);
// 取出自定义属性中滑块图片
int slideUnlockBlockResource = attrs.getAttributeResourceValue(
namespace, "slideUnlockBlockResource", -1);
// 取出自定义属性中当前状态
// 如果解锁状态是true,说明已经解锁
/**
* 当取出自定义属性的背景时,设置背景
*/
setSlideUnlockBackground(slideUnlockBackgroundResource);
/**
* 当取出自定义属性的滑块时,设置滑块的图片
*/
setSlideUnlockBlock(slideUnlockBlockResource);
/**
* 执行onDraw方法,进行界面绘制
*/
postInvalidate();
}
/**
* 设置背景图
* @param slideUnlockBackgroundResource
*/
public void setSlideUnlockBackground(int slideUnlockBackgroundResource) {
slideUnlockBackground = BitmapFactory.decodeResource(getResources(),
slideUnlockBackgroundResource);
// 获取背景图的宽和高
blockBackgoundWidth = slideUnlockBackground.getWidth();
}
/**
* 设置滑块图
* @param slideUnlockBlockResource
*/
public void setSlideUnlockBlock(int slideUnlockBlockResource) {
slideUnlockBlock = BitmapFactory.decodeResource(getResources(),
slideUnlockBlockResource);
// 获取滑块的宽和高
blockWidth = slideUnlockBlock.getWidth();
blockHeight = slideUnlockBlock.getHeight();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//设置控件的宽高为滑块背景图的宽高
setMeasuredDimension(slideUnlockBackground.getWidth(),
slideUnlockBackground.getHeight());
}
/**
* 计算手指是否是落在了滑块上(默认是按照滑块在未解锁的初始位置来计算的)
*/
public boolean isDownOnBlock(float x1, float x2, float y1, float y2) {
float sqrt = FloatMath.sqrt(Math.abs(x1 - x2) * Math.abs(x1 - x2)
+ Math.abs(y1 - y2) * Math.abs(y1 - y2));
if (sqrt <= blockWidth / 2) {
return true;
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
// 当手指按下的时候,判断手指按下的位置是否在滑块上边
case MotionEvent.ACTION_DOWN:
if (currentState != STATE_MOVING) {
// 判断一下,如果当前正在移动,则不执行触摸操作
// 获取相对于背景的左上角的x,y值
x = event.getX();
y = event.getY();
// 先计算出滑块的中心点的x,y坐标
float blockCenterX = blockWidth * 1.0f / 2;
float blockCenterY = blockHeight * 1.0f / 2;
downOnBlock = isDownOnBlock(blockCenterX, x, blockCenterY, y);
Log.i(TAG, "down......................");
// 调用onDraw方法
postInvalidate();
}
break;
case MotionEvent.ACTION_MOVE:
// 如果手指确定按在滑块上,就视为开始拖拽滑块
if (downOnBlock) {
// 获取相对于背景的左上角的x,y值
x = event.getX();
y = event.getY();
currentState = STATE_MOVING;
Log.i(TAG, "move......................");
// 调用onDraw方法
postInvalidate();
}
break;
case MotionEvent.ACTION_UP:
if (currentState == STATE_MOVING) {
// 当手指抬起的时候,应该是让滑块归位的
// 说明未解锁
if (x < blockBackgoundWidth - blockWidth) {
handler.sendEmptyMessageDelayed(0, 10);
// 通过回调设置已解锁
onUnLockListener.setUnLocked(false);
} else {
currentState = STATE_UNLOCK;
// 通过回调设置未解锁
onUnLockListener.setUnLocked(true);
}
downOnBlock = false;
// 调用onDraw方法
postInvalidate();
}
break;
default:
break;
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 在一开始的使用将背景图绘制出来
canvas.drawBitmap(slideUnlockBackground, 0, 0, null);
/**
* 判断当前状态
*/
switch (currentState) {
// 如果是未解锁,就将滑块绘制到最左端
case STATE_LOCK:
canvas.drawBitmap(slideUnlockBlock, 0, 0, null);
break;
// 已解锁,计算出
case STATE_UNLOCK:
int unlockX = blockBackgoundWidth - blockWidth;
canvas.drawBitmap(slideUnlockBlock, unlockX, 0, null);
break;
case STATE_MOVING:
if (x < 0) {
x = 0;
} else if (x > blockBackgoundWidth - blockWidth) {
x = blockBackgoundWidth - blockWidth;
}
canvas.drawBitmap(slideUnlockBlock, x, 0, null);
break;
default:
break;
}
}
/**
* 通过handler来控制滑块在未解锁的时候,平缓的滑动到左端
*/
Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == 0) {
// 如果x还大于0,就人为的设置缓慢移动到最左端,每次移动距离设置为背景宽的/100
if (x > 0) {
x = x - blockBackgoundWidth * 1.0f / 100;
// 刷新界面
postInvalidate();
// 设置继续移动
handler.sendEmptyMessageDelayed(0, 10);
} else {
handler.removeCallbacksAndMessages(null);
currentState = STATE_LOCK;
Log.i(TAG, "state---lock.....");
}
}
};
};
case MotionEvent.ACTION_UP:
if (currentState == STATE_MOVING) {
// 当手指抬起的时候,应该是让滑块归位的
// 说明未解锁
if (x < blockBackgoundWidth - blockWidth) {
handler.sendEmptyMessageDelayed(0, 10);
// 通过回调设置已解锁
onUnLockListener.setUnLocked(false);
} else {
currentState = STATE_UNLOCK;
// 通过回调设置未解锁
onUnLockListener.setUnLocked(true);
}
downOnBlock = false;
// 调用onDraw方法
postInvalidate();
}
break;
public interface OnUnLockListener {
public void setUnLocked(boolean lock);
}
public void setOnUnLockListener(OnUnLockListener onUnLockListener) {
this.onUnLockListener = onUnLockListener;
}
if (currentState == STATE_MOVING) {
// 当手指抬起的时候,应该是让滑块归位的
// 说明未解锁
if (x < blockBackgoundWidth - blockWidth) {
handler.sendEmptyMessageDelayed(0, 10);
// 通过回调设置已解锁
onUnLockListener.setUnLocked(false);
} else {
currentState = STATE_UNLOCK;
// 通过回调设置未解锁
onUnLockListener.setUnLocked(true);
}
downOnBlock = false;
// 调用onDraw方法
postInvalidate();
}
// 获取系统振动器服务
vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
// 启动震动器 100ms
vibrator.vibrate(100);
slideUnlockView = (SlideUnlockView) findViewById(R.id.slideUnlockView);
// 设置滑动解锁-解锁的监听
slideUnlockView.setOnUnLockListener(new OnUnLockListener() {
@Override
public void setUnLocked(boolean unLock) {
// 如果是true,证明解锁
if (unLock) {
// 启动震动器 100ms
vibrator.vibrate(100);
// 当解锁的时候,执行逻辑操作,在这里仅仅是将图片进行展示
imageView.setVisibility(View.VISIBLE);
// 重置一下滑动解锁的控件
slideUnlockView.reset();
// 让滑动解锁控件消失
slideUnlockView.setVisibility(View.GONE);
}
}
});
}
/**
* 注册一个屏幕锁屏的广播
*/
private void registScreenOffReceiver() {
// TODO Auto-generated method stub
receiver = new ScreenOnOffReceiver();
// 创建一个意图过滤器
IntentFilter filter = new IntentFilter();
// 添加屏幕锁屏的广播
filter.addAction("android.intent.action.SCREEN_OFF");
// 在代码里边来注册广播
this.registerReceiver(receiver, filter);
}
class ScreenOnOffReceiver extends BroadcastReceiver {
private static final String TAG = "ScreenOnOffReceiver";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// 关屏的操作
if ("android.intent.action.SCREEN_OFF".equals(action)) {
// 当手机关屏时,我们同时也锁屏
slideUnlockView.setVisibility(View.VISIBLE);
// 设置图片消失
imageView.setVisibility(View.GONE);
}
}
}
以上是Android自定义控件–滑动解锁的所有代码逻辑