大家好,又见面了,我是你们的朋友全栈君。
我的视频系列 http://edu.csdn.net/course/detail/2741,一起来学习Android…
代码参考地址 https://github.com/liuzhiyuan0932/SlideUnLock代码效果图>
自定义滑动解锁的控件继承自View
public class SlideUnlockView extends View
自定义SlideUnLockView的属性
- 在values文件夹中定义属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SlideUnlockButton">
<!-- 背景图片的属性, 引用的是R.drawable.xx. -->
<attr name="slideUnlockBackgroundResource" format="reference" />
<!-- 滑动块图片的属性, 引用的是R.drawable.xx. -->
<attr name="slideUnlockBlockResource" format="reference" />
</declare-styleable>
</resources>
- 在xml布局中使用相关的属性
<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();
}
通过测量背景图的宽高设置SlideUnLockView的宽高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//设置控件的宽高为滑块背景图的宽高
setMeasuredDimension(slideUnlockBackground.getWidth(),
slideUnlockBackground.getHeight());
}
处理onTouch事件
- 判断手指是否按在滑块上
/** * 计算手指是否是落在了滑块上(默认是按照滑块在未解锁的初始位置来计算的) */
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;
}
- onTouch事件处理的主要逻辑
@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;
}
调用OnDraw方法并根据状态进行绘制
@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;
}
- 在OnTouch中解锁的时候,进行设置
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 = (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);
}
}
});
}
用户屏幕锁屏的监听
- 注册Android锁屏广播
/** * 注册一个屏幕锁屏的广播 */
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自定义控件–滑动解锁的所有代码逻辑
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/149102.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...