Android 滑动解锁页

最近的一个项目里面需要使用锁屏页,实现的方法是用Activity来伪装锁屏页,网上对这个方面的教程不多,大多数都是基于这篇文章,但是这篇文章有些细节点没有关注到,所以我在这里进行一些完善和补充,并把整个完整的过程写出来,供大家参考。

我们怎么做到锁屏的时候显示Activity

首先我们在这里创建一个Activity,名字叫作LockScreenActivity,然后我们来着手解决如何知道屏幕锁屏,思路可以看下面的流程图(这里借鉴QQ音乐的资料图)😁。

通过上图的流程可知屏幕关闭会发出一个叫作SCREEN_OFF的系统广播,然后在Service里面去监听这个系统广播,一旦App启动,就启动这个Service,然后一旦系统发出SCREEN_OFF的广播,Receiver就会接受到。
接着,我们按上面得出来的步骤,来完成程序的设计,首先new一个Service,这个Service主要用来注册一个广播来监听SCREEN_OFF这一系统广播,但在此之前我们还得创建一个广播的接受器(LockScreenReceiver),其具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class LockScreenReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

if (Intent.ACTION_SCREEN_OFF.equals(action)) {
Intent mLockIntent = new Intent(context, LockScreenActivity.class);
mLockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
context.startActivity(mLockIntent);
}

}

}

接着我们来创建用来注册监听广播的ServiceLockService),其具体代码如下:

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
public class LockService extends Service {

private LockScreenReceiver lockScreenReceiver;

@Override
public void onCreate() {

lockScreenReceiver = new LockScreenReceiver();
IntentFilter mScreenOffFilte = new IntentFilter();
mScreenOffFilte.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(lockScreenReceiver,mScreenOffFilte);

}

@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(lockScreenReceiver);
}
}

当然注意了,在ServiceDestroy的时候别忘了调用unregisterReceiver来解除注册的广播。
我们只用在App启动的时候来启动这个服务,具体的代码如下:

1
2
Intent intent = new Intent(this,LockService.class);
startService(intent);

当然上面的这一些还不够,我们要加一个权限,加上使锁屏失效(当然如果你设置了密码是不能失效的)。

1
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>

同时你还得在Activity里面设置一大堆属性:

1
2
3
4
5
6
7
8
9
10
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE);

这上面的属性分别设置使布局锁屏的时候出现,去掉锁屏,全屏,去掉导航栏和状态栏等等,具体一些属性的效果有些我也说不清楚,大家有兴趣的可以自行Google一下。

实现锁屏的滑动效果

这里我们定义一个UnderView来处理滑动逻辑。在这里盗一张QQ音乐团队的图,我觉得它的图解释的很清楚。

这里把视图分为MoveViewUnderView,废话不多说,上完整的代码:

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
public class UnderView extends View {

private float mStartX;
private View mMoveView;
private int mWidth;
private OnSlideFinishListener mOnSlideFinishListener;

public UnderView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mWidth = ScreenUtils.getScreenWidth(context);

}

public void setSlideListener(OnSlideFinishListener onSlideFinishListener){
mOnSlideFinishListener = onSlideFinishListener;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getAction();
final float nx = event.getX();
switch (action) {
case MotionEvent.ACTION_DOWN:
mStartX = nx;
onAnimationEnd();
case MotionEvent.ACTION_MOVE:
handleMoveView(nx);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
doTriggerEvent(nx);
break;
}
return true;
}

private void handleMoveView(float x) {
float movex = x - mStartX;
if (movex < 0)
movex = 0;
mMoveView.setTranslationX(movex);

float mWidthFloat = (float) mWidth;//屏幕显示宽度
if(getBackground()!=null){
getBackground().setAlpha((int) ((mWidthFloat - mMoveView.getTranslationX()) / mWidthFloat * 200));//初始透明度的值为200
}
}

private void doTriggerEvent(float x) {
float movex = x - mStartX;
if (movex > (mWidth * 0.4)) {
moveMoveView(mWidth-mMoveView.getLeft(),true);//自动移动到屏幕右边界之外,并finish掉

} else {
moveMoveView(-mMoveView.getLeft(),false);//自动移动回初始位置,重新覆盖
}
}

private void moveMoveView(float to,boolean exit){

ObjectAnimator animator = ObjectAnimator.ofFloat(mMoveView, "translationX", to);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
if(getBackground()!=null){
getBackground().setAlpha((int) (((float) mWidth - mMoveView.getTranslationX()) / (float) mWidth * 200));
}
}
});//随移动动画更新背景透明度
animator.setDuration(250).start();

if(exit){
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mOnSlideFinishListener.onSlideFinish();
}
});
}//监听动画结束,利用Handler通知Activity退出
}

public void setMoveView(View moveView){
mMoveView = moveView;
}

public interface OnSlideFinishListener{
void onSlideFinish();
}
}

接下来我们来分析一下这个自定义View,在handleMoveView里面处理当手在屏幕上面滑动时mMoveView随着手指滑动,doTriggerEvent是处理松开手指时mMoveView的反应,当滑动的距离不超过屏幕的40%时,mMoveView返回到原处,超过了就直接划过去。
当然重点是要在UnderView里面获取mMoveView和设置OnSlideFinishListener来处理当锁屏划开的时候finish掉当前的Activity

细节处理

完成了上面的两步,大家可以运行一下程序,这时候会出现两个问题,滑动时,滑动过的背景不是透明的,如果你没退出Activity又反复打开屏幕关闭屏幕,会有多个LockScreenActivityActivity栈里面。
首先第二个问题比较好解决,直接在Manifest里面指定LockScreenActivitylaunchModesingleInstance,即单例模式。这样栈里面就只会有一个LockScreenActivity存在。
第二个问题就需要设置Activity的背景为透明色,接着在Activitytheme,我们需要在style文件里为LockScreenActivity指定一个theme,具体的代码如下:

1
2
3
4
5
6
7
8
9
<style name="LockScreenTheme" parent="AppTheme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">false</item>
<item name="android:windowAnimationStyle">@null</item>
<item name="android:windowContentOverlay">@null</item>
</style>

这里为止,我们就可以实现一个完整的锁屏页了(^-^)。

本文标题:Android 滑动解锁页

文章作者:袁来

发布时间:2018年05月26日 - 17:05

最后更新:2018年05月26日 - 17:05

原始链接:http://yoursite.com/2018/05/26/Android-滑动解锁页/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

显示 Gitment 评论