Android自定义控件之滑动解锁

Android自定义控件之滑动解锁我的视频系列 http edu csdn net course detail 2741 一起来学习 Android 代码参考地址 https github com liuzhiyuan09 SlideUnLock 代码效果图 自定义滑动解锁的控件继承自 View public class SlideUnlockV extends View

我的视频系列 http://edu.csdn.net/course/detail/2741,一起来学习Android…
代码参考地址 https://github.com/liuzhiyuan0932/SlideUnLock
代码效果图>

自定义滑动解锁的控件继承自View

public class SlideUnlockView extends View 

自定义SlideUnLockView的属性

在values文件夹中定义属性













在xml布局中使用相关的属性

    
        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自定义控件–滑动解锁的所有代码逻辑
编程小号
上一篇 2025-01-18 07:01
下一篇 2025-01-17 23:51

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/hz/148577.html