如何通过onTouchEvent方法实现锁屏页滑动解锁功能?setAlpha与AlphaAnimation冲突的踩坑解决方案

开篇

一开始的需求是将锁屏界面从现有的左滑解锁(利用viewpager实现)改为上滑解锁,后来发现上滑解锁改动过大且实现较为困难


综合网上所有解决方案

一 使用WindowManager(较难实现)
二 使用scrollview实现—尝试后发现效果十分差劲且仍然较难实现
最终在网上所有方法都不适用的情况下,决定自己独立使用onTouchEvent方法写出
滑动解锁的效果,以下记录此次的开发经历及一路上的坑。

第一步 使用onTouchEvent方法

onTouchEvent方法和onTouch方法实在是太像啦
关于他们的区别不想阐述太多,onTouch方法可以在onTouchEvent方法执行前进行操作或者拦截事件。
onTouchEvent方法的常用使用格式
@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN:
            break;
        case MotionEvent.ACTION_MOVE:
            break;
        case MotionEvent.ACTION_UP:
            break;
    }
    return true;
}
onTouchEvent方法中的MotionEvent最常用的便是三种情况:
手指放下—手指移动—手指抬起
因此最好用的方式还是使用swich方法分别对这三种情况进行处理

 

思路(伪代码)

在手指放下时记录初次坐标点X Y
在手指移动时不断记录并比较与初次坐标点的距离,通过相对距离判断是纵向滑动还是横向滑动,然后计算透明度并设置(实现随手指移动 UI界面欲解锁的动效)
在手指移开时判断相对距离是否达到预设值,如果达到则finish界面进行解锁,如果没有达到则透明度缓缓回到初始状态(动效)并初始化所有值待下次解锁。

 

代码

private int firstX = 0;//记录初次触摸点x坐标
private int firstY = 0;//记录初次触摸点y坐标
private int moveX = 0;//移动时x坐标
private int moveY = 0;//移动时y坐标
private int fromX = 0;//x距离绝对值
private int fromY = 0;//y距离绝对值
private float alpha = 1.0f;//初始化透明度
private int limit = 3;//表示解锁距离为屏幕的1/3
private float limitAlpha = 1.0f;//表示最大透明度

private Handler handler = new Handler();
private Runnable runnable;

private int screenWidth;
private int screenHeight;

WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
screenHeight = dm.heightPixels;         // 屏幕宽度(像素)
screenWidth = dm.widthPixels;       // 屏幕高度(像素)

@Override
    public boolean onTouchEvent(MotionEvent event) {
        moveX = (int) event.getRawX();//移动时x坐标
        moveY = (int) event.getRawY();//移动时y坐标
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                firstX = (int) event.getRawX();
                firstY = (int) event.getRawY();
                LogUtils.d(TAG, "流程--按下");
                break;
            case MotionEvent.ACTION_MOVE:
                LogUtils.d(TAG, "screenWidth:" + screenWidth + "--screenHeight:" + screenHeight);
                LogUtils.d(TAG, "流程--移动");
                fromX = Math.abs(moveX - firstX);//移动点x坐标值距初次触摸点x坐标的绝对值
                fromY = Math.abs(moveY - firstY);//移动点y坐标值距初次触摸点y坐标的绝对值
                if (fromX >= fromY) {//此时只通过横向移动距离计算alpha透明度
                    alpha = 1.0f - ((1 / (float) (screenWidth / limit)) * fromX);//计算透明度,3表示取屏幕宽度1/3作为解锁值
                    if (alpha > limitAlpha) {//给定最大极限alpha值
                        alpha = limitAlpha;
                    }
                    if (alpha < 0) {
                        alpha = 0;
                    }
                    ll_ac_lock_screen.setAlpha(alpha);
                    LogUtils.d(TAG, "firstX:" + firstX + "--firstY:" + firstY + "--moveX:" + moveX + "--moveY:" + moveY + "--alphaX:" + alpha + "--fromX:" + fromX);
                } else {//此时只通过纵向移动距离计算alpha透明度
                    alpha = 1.0f - ((1 / (float) (screenHeight / limit)) * fromY);//计算透明度,3表示取屏幕宽度1/3作为解锁值
                    if (alpha > limitAlpha) {//给定最大极限alpha值
                        alpha = limitAlpha;
                    }
                    ll_ac_lock_screen.setAlpha(alpha);
                    LogUtils.d(TAG, "firstX:" + firstX + "--firstY:" + firstY + "--moveX:" + moveX + "--moveY:" + moveY + "--alphaY:" + alpha + "--fromY:" + fromY);
                }
                break;
            case MotionEvent.ACTION_UP:
                LogUtils.d(TAG, "流程--抬起");
                LogUtils.d(TAG, "screenWidth/limit:" + (screenWidth / limit) + "  screenHeight/limit:" + (screenHeight / limit) + "  fromY:" + fromY + "  fromX:" + fromX);
                if ((fromX < (screenWidth / limit)) && (fromY < (screenHeight / limit))) {
                    //此时滑动距离不够,不解锁
                    LogUtils.d(TAG, "--alpha:" + alpha);
                    runnable = () -> {
                        if (alpha > 1.0f) {
                            alpha = 1.0f;
                            handler.removeCallbacks(runnable);
                        } else {
                            alpha = alpha + 0.05f;
                            ll_ac_lock_screen.setAlpha(alpha);
                            LogUtils.d(TAG,"alpha线程:"+alpha);
                            handler.postDelayed(runnable, 25);
                        }
                    };
                    handler.postDelayed(runnable, 0);
                    firstX = 0;
                    firstY = 0;
                    moveX = 0;//移动时x坐标
                    moveY = 0;//移动时y坐标
                    fromX = 0;
                    fromY = 0;
                } else
                {
                    handler.removeCallbacks(runnable);
                    LockScreenActivity.this.finish();
                }
                break;
        }
        return true;
    }

踩过去的坑:

一 在网上参考代码时一定要仔细辨别

获取屏幕尺寸的代码用到最后打了无数log才发现写的人居然写反了!

 

二 定义小数类型进行计算时(例如float f1 = i1/i2;)要注意类型转换

倘若i1/i2小于0他并不会如同想的一样直接转为float运算,而是直接等于0。所以要在运算前加上类型转换float f1 = (float)(i1/i2);这个坑也是苦思冥想好久最终通过分步打log才发现的问题。

 

三 setAlpha方法与AlphaAnimation冲突 setAlpha与getBackground().setAlpha()的区别

首先一开始想设置透明度的时候看到有人说推荐getBackground后再setAlpha
后来发现getBackground再设置透明度是用于实现单个view显隐,而实现连同子view一起显隐只能直接使用setAlpha()方法。
需要注意的是,在尝试过程中发现倘若xml布局文件中background属性使用的是@color的格式的话,使用getBackground().setAlpha()方法会对全局所有调用该布局中该颜色代码的控件生效,如果不得不用的话推荐使用后将其恢复原值。

setAlpha方法与AlphaAnimation冲突

需求中setAlpha之后由于想实现透明度缓缓回到初始状态的动效,一开始便用了Animation类中的AlphaAnimation透明度动画,结果发现AlphaAnimation的构造方法中传入的值是类似百分比的含义
例如先前你设置透明度为0.5,再之后使用AlphaAnimation alphaAnimation = new AlphaAnimation(0.5f,1.0f);最终达到的效果只是alpha值从0.25到0.5,并不能实现恢复到原状态的需求
解决方案:利用子线程,在线程中每隔25ms刷新一次alpha值并缓慢增加,alpha值达到1时停止子线程便可达到逐渐恢复原透明度的动效

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值