超级机甲:源能觉醒 - 新版本资料库

Android自定义控件之滑动解锁

大家好,又见面了,我是你们的朋友全栈君。

我的视频系列 http://edu.csdn.net/course/detail/2741,一起来学习Android…

代码参考地址 https://github.com/liuzhiyuan0932/SlideUnLock

代码效果图>

自定义滑动解锁的控件继承自View代码语言:javascript复制public class SlideUnlockView extends View 自定义SlideUnLockView的属性在values文件夹中定义属性代码语言:javascript复制

在xml布局中使用相关的属性代码语言:javascript复制

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" />定义滑块的几种状态代码语言:javascript复制/** * 滑块当前的状态 */

public int currentState;

/** * 未解锁 */

public static final int STATE_LOCK = 1;

/** * 解锁 */

public static final int STATE_UNLOCK = 2;

/** * 正在拖拽 */

public static final int STATE_MOVING = 3;获取图片资源,并进行初始绘制在构造方法中获取属性值代码语言:javascript复制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();

}设置图片的方法,设置好图片之后,进行界面的初始 绘制代码语言:javascript复制 /** * 设置背景图 * @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的宽高代码语言:javascript复制@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

//设置控件的宽高为滑块背景图的宽高

setMeasuredDimension(slideUnlockBackground.getWidth(),

slideUnlockBackground.getHeight());

}处理onTouch事件判断手指是否按在滑块上代码语言:javascript复制 /** * 计算手指是否是落在了滑块上(默认是按照滑块在未解锁的初始位置来计算的) */

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事件处理的主要逻辑代码语言:javascript复制@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方法并根据状态进行绘制代码语言:javascript复制@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;

}

}设置手指抬起未解锁时滑块缓慢回到初始位置代码语言:javascript复制 /** * 通过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.....");

}

}

};

};代码语言:javascript复制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;设置滑动解锁的监听定义一个解锁监听的接口代码语言:javascript复制public interface OnUnLockListener {

public void setUnLocked(boolean lock);

}对外听设置监听的方法代码语言:javascript复制public void setOnUnLockListener(OnUnLockListener onUnLockListener) {

this.onUnLockListener = onUnLockListener;

}在OnTouch中解锁的时候,进行设置代码语言:javascript复制 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();

}定义滑动解锁时手机震动的震动器代码语言:javascript复制 // 获取系统振动器服务

vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);

// 启动震动器 100ms

vibrator.vibrate(100);在类中使用SlideUnLockView代码语言:javascript复制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锁屏广播代码语言:javascript复制/** * 注册一个屏幕锁屏的广播 */

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);

}定义广播接收器代码语言:javascript复制 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自定义控件–滑动解锁的所有代码逻辑

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/149102.html原文链接:https://javaforall.cn