前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android自定义控件之滑动解锁

Android自定义控件之滑动解锁

作者头像
全栈程序员站长
发布2022-09-12 16:46:35
1.8K0
发布2022-09-12 16:46:35
举报

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

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

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

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

代码语言:javascript
复制
public class SlideUnlockView extends View 

自定义SlideUnLockView的属性

  • 在values文件夹中定义属性
代码语言:javascript
复制
<?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布局中使用相关的属性
代码语言:javascript
复制
    <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" />

定义滑块的几种状态

代码语言: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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 自定义滑动解锁的控件继承自View
  • 自定义SlideUnLockView的属性
  • 定义滑块的几种状态
  • 获取图片资源,并进行初始绘制
  • 通过测量背景图的宽高设置SlideUnLockView的宽高
  • 处理onTouch事件
  • 调用OnDraw方法并根据状态进行绘制
  • 设置手指抬起未解锁时滑块缓慢回到初始位置
  • 设置滑动解锁的监听
  • 定义滑动解锁时手机震动的震动器
  • 在类中使用SlideUnLockView
  • 用户屏幕锁屏的监听
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档