Android自定义控件之滑动解锁

Android自定义控件之滑动解锁代码参考地址https://github.com/liuzhiyuan0932/SlideUnLock代码效果图>自定义滑动解锁的控件继承自ViewpublicclassSlideUnlockViewextendsView自定义SlideUnLockView的属性在values文件夹中定义属性

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

我的视频系列 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账号...

(0)
blank

相关推荐

  • pychrom激活码【在线破解激活】

    pychrom激活码【在线破解激活】,https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • FAE新手上路_ra上路

    FAE新手上路_ra上路2018年夏天,因为犹豫,最终放弃了一家中意的公司,选择继续留在原公司,这是我到目前为止进入互联网行业做的最错误的决定,网上无数血的教训,同事委婉的劝告,都没改变我跟随新领导的“决心”,另外自己也没有做好换一个新环境的准备,所以就留下来了,换来的是兑现不了的大饼和离职时差点闹开的不堪经历,过去的是是非非我就不作评价了,只是以我的之前的经历告诫各位,一、不要去外包公司。二、提了离职,绝…

    2022年10月28日
  • class文件和dex文件「建议收藏」

    class文件和dex文件「建议收藏」Class文件1、什么是class文件能够被JVM识别,加载并执行的文件格式。2、class文件的生成![这里写图片描述](https://img-blog.csdn.net/20180817160829200?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0RldmVsb3BBbmRyb2lk/font/5a6L5L2T/f…

  • Python 基础问题大全

    Python 基础问题大全前言Python现在依托大数据,AI人工智能等等这些最火的项目,俨然已经成为了当下最火的一门编程语言之一。所以,近来也是有非常非常多的工程师来进修python这么语言。但是实际上,对于0代码基础

  • python的安装包安装教程_如何安装python

    python的安装包安装教程_如何安装pythonpip是Python包管理工具,该工具提供了对Python包的查找、下载、安装、卸载的功能。一般情况pip对应的是Python2.7,pip3对应的是Python3.x。部分Linux发行版可直接用包管理器安装pip,如Debian和Ubuntu:sudoapt-getinstallpython-pip安装包pipinstallSomePackage…

    2022年10月30日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号