Android自定义控件之滑动解锁

来源:互联网 发布:uploadify.php 漏洞 编辑:程序博客网 时间:2024/05/06 08:42

转载自;http://blog.csdn.net/zhiyuan0932/article/details/51472289

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

代码效果图> 
这里写图片描述 
这里写图片描述

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

public class SlideUnlockView extends View 
  • 1

自定义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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 在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" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

定义滑块的几种状态

/**     * 滑块当前的状态     */    public int currentState;    /**     * 未解锁     */    public static final int STATE_LOCK = 1;    /**     * 解锁     */    public static final int STATE_UNLOCK = 2;    /**     * 正在拖拽     */    public static final int STATE_MOVING = 3;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

获取图片资源,并进行初始绘制

  • 在构造方法中获取属性值
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();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 设置图片的方法,设置好图片之后,进行界面的初始 绘制
    /**     * 设置背景图     * @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();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

通过测量背景图的宽高设置SlideUnLockView的宽高

@Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //设置控件的宽高为滑块背景图的宽高        setMeasuredDimension(slideUnlockBackground.getWidth(),                slideUnlockBackground.getHeight());    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

处理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;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 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;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

调用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;        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

设置手指抬起未解锁时滑块缓慢回到初始位置

    /**     * 通过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.....");                }            }        };    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

设置滑动解锁的监听

  • 定义一个解锁监听的接口
public interface OnUnLockListener {        public void setUnLocked(boolean lock);    }
  • 1
  • 2
  • 3
  • 对外听设置监听的方法
public void setOnUnLockListener(OnUnLockListener onUnLockListener) {        this.onUnLockListener = onUnLockListener;    }
  • 1
  • 2
  • 3
  • 在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();            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

定义滑动解锁时手机震动的震动器

    // 获取系统振动器服务        vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);        // 启动震动器 100ms        vibrator.vibrate(100);
  • 1
  • 2
  • 3
  • 4

在类中使用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);                }            }        });    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

用户屏幕锁屏的监听

  • 注册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);    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 定义广播接收器
    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);            }        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

以上是Android自定义控件–滑动解锁的所有代码逻辑

原创粉丝点击