android 滑动解锁实现

刚刚跟着传智播客的黎活明老师的视频学习了android,很想做一个自己的锁屏软件

网上翻看了一些资料,自己也琢磨了一些,把心得体会写下来也算是一个回顾

1.效果图

这是我机器上的效果图

2.源码和解释(我觉得还是贴一些源码好说明问题)

2.1 主显示的LockScreenActivity.java

 

 1 package com.lihua.lockscreen;
 2 
 3 import android.os.Bundle;
 4 import android.os.Handler;
 5 import android.os.Message;
 6 import android.os.Vibrator;
 7 import android.app.Activity;
 8 import android.content.Context;
 9 import android.content.Intent;
10 import android.util.Log;
11 import android.view.KeyEvent;
12 import android.view.Window;
13 import android.view.WindowManager;
14 import android.widget.Toast;
15 
16 public class LockScreenActivity extends Activity {
17     private final String TAG = "LockScreenActivity";
18     private SliderRelativeLayout sliderRelativeLayout;
19     public static int MSG_LOCK_SUCESS = 1;
20     
21     @Override
22     protected void onCreate(Bundle savedInstanceState) {
23         super.onCreate(savedInstanceState);
24         
25         requestWindowFeature(Window.FEATURE_NO_TITLE); //不要title
26         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
27                 WindowManager.LayoutParams.FLAG_FULLSCREEN); //全屏显示
28         
29         setContentView(R.layout.activity_lock_screen);
30         
31         sliderRelativeLayout = (SliderRelativeLayout) findViewById(R.id.sliderLayout);
32         sliderRelativeLayout.setMainHandler(handler);
33         sliderRelativeLayout.getBackground().setAlpha(180); //设置背景的透明度
34         
35         startService(new Intent(LockScreenActivity.this, LockScreenService.class)); //这里要显示的调用服务
36     }
37     
38     private Handler handler = new Handler(){
39         @Override
40         public void handleMessage(Message msg) {
41             if(MSG_LOCK_SUCESS == msg.what){
42                 //Toast.makeText(getApplicationContext(), R.string.lockSuccess, 1).show();
43                 virbate();
44                 finish();
45             }
46         }
47     };
48     
49     /**
50      * 震动
51      */
52     private void virbate(){
53         Vibrator vibrator = (Vibrator) this.getSystemService(Context.VIBRATOR_SERVICE);
54         vibrator.vibrate(200);
55     }
56     
57     /**
58      * 屏蔽掉Home键
59      */
60     @Override
61     public void onAttachedToWindow() {
62         this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
63         super.onAttachedToWindow();
64     }
65     
66     /**
67      * 屏蔽掉返回键
68      */
69     @Override
70     public boolean onKeyDown(int keyCode, KeyEvent event) {
71         if(event.getKeyCode() == KeyEvent.KEYCODE_BACK){
72             return true;
73         } else {
74             return super.onKeyDown(keyCode, event);
75         }
76     }
77 }

 2.2 主布局文件activity_lock_screen.xml

 1 <RelativeLayout xmlns:tools="http://schemas.android.com/tools"
 2     xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="wrap_content"
 5     android:background="@drawable/bg"
 6     tools:context=".LockScreenActivity" >
 7     <com.lihua.lockscreen.SliderRelativeLayout 
 8         android:id="@+id/sliderLayout"
 9         android:layout_height="66dp"
10         android:layout_width="fill_parent"
11         android:layout_marginTop="400dp"
12         android:background="@drawable/lockbg">
13         
14         <RelativeLayout 
15             android:id="@+id/relativeLayout1"
16             android:layout_width="wrap_content"
17             android:layout_height="wrap_content"
18             android:layout_alignParentLeft="true"
19             android:layout_centerHorizontal="true"
20             android:layout_centerVertical="true">
21             <ImageView 
22                 android:id="@+id/leftRing"
23                 android:layout_width="wrap_content"
24                    android:layout_height="wrap_content"
25                    android:src="@drawable/circlebg"/>
26 
27             <TextView
28                 android:layout_width="wrap_content"
29                 android:layout_height="wrap_content"
30                 android:layout_centerHorizontal="true"
31                 android:layout_centerVertical="true"
32                 android:text="@string/li"
33                 android:textColor="#FF0000" />
34         </RelativeLayout>
35         <RelativeLayout 
36             android:layout_width="wrap_content"
37             android:layout_height="wrap_content"
38             android:layout_alignParentRight="true"
39             android:layout_centerHorizontal="true"
40             android:layout_centerVertical="true" >
41             <ImageView 
42                 android:id="@+id/rightRing"
43                 android:layout_width="wrap_content"
44                    android:layout_height="wrap_content"
45                    android:src="@drawable/circlebg"/>
46 
47             <TextView
48                 android:layout_width="wrap_content"
49                 android:layout_height="wrap_content"
50                 android:layout_centerHorizontal="true"
51                 android:layout_centerVertical="true"
52                 android:text="@string/shuang"
53                 android:textColor="#FF0000" />
54         </RelativeLayout>
55         <RelativeLayout
56             android:layout_width="222dp"
57             android:layout_height="wrap_content"
58             android:layout_marginLeft="50dp"
59             >
60 
61             <ImageView
62                 android:id="@+id/loveView"
63                 android:layout_width="wrap_content"
64                 android:layout_height="wrap_content"
65                 android:layout_alignParentLeft="true"
66                 android:layout_alignParentTop="true"
67                 android:src="@drawable/love" />
68 
69         </RelativeLayout>
70 
71         
72 
73     </com.lihua.lockscreen.SliderRelativeLayout>
74 </RelativeLayout>

2.3 自定义布局类SliderRelativeLayout.java

package com.lihua.lockscreen;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;

public class SliderRelativeLayout extends RelativeLayout {
    private final static String TAG = "SliderRelativeLayout";
    private Context context;
    private Bitmap dragBitmap = null; //拖拽图片
    private int locationX = 0; //bitmap初始绘图位置,足够大,可以认为看不见
    private ImageView heartView = null; //主要是获取相对布局的高度
    private ImageView leftRingView = null;
    private ImageView rightRingView = null;
    private Handler handler = null; //信息传递
    private static int BACK_DURATION = 10 ;   // 回退动画时间间隔值  20ms
    private static float VE_HORIZONTAL = 0.9f ;  // 水平方向前进速率 0.1dip/ms
    
    public SliderRelativeLayout(Context context) {
        super(context); 
        SliderRelativeLayout.this.context = context;
        intiDragBitmap();
    }
    
    public SliderRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
        SliderRelativeLayout.this.context = context;
        intiDragBitmap();
    }

    public SliderRelativeLayout(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        SliderRelativeLayout.this.context = context;
        intiDragBitmap();
    }

    /**
     * 得到拖拽图片
     */
    private void intiDragBitmap() {
        if(dragBitmap == null){
            dragBitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.love);
        }
    }
    
    /**
     * 这个方法里可以得到一个其他资源
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        heartView = (ImageView) findViewById(R.id.loveView);
        leftRingView = (ImageView) findViewById(R.id.leftRing);
        rightRingView = (ImageView) findViewById(R.id.rightRing);
    }

    /**
     * 对拖拽图片不同的点击事件处理
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int X = (int) event.getX();

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: 
            locationX = (int) event.getX();
            Log.i(TAG, "是否点击到位=" + isActionDown(event));
            return isActionDown(event);//判断是否点击了滑动区域
            
        case MotionEvent.ACTION_MOVE: //保存x轴方向,绘制图画
            locationX = X;
            invalidate(); //重新绘图
            return true;
            
        case MotionEvent.ACTION_UP: //判断是否解锁成功
            if(!isLocked()){ //没有解锁成功,动画应该回退
                handleActionUpEvent(event); //动画回退
            }
            return true;
        }
        return super.onTouchEvent(event);
    }
    
    /**
     * 回退动画
     * @param event
     */
    private void handleActionUpEvent(MotionEvent event) {
        int x = (int) event.getX();
        int toLeft = leftRingView.getWidth();
        
        locationX = x - toLeft;
        if(locationX >= 0){
            handler.postDelayed(ImageBack, BACK_DURATION); //回退
        }
    }

    /**
     * 未解锁时,图片回退
     */
    private Runnable ImageBack = new Runnable() {
        @Override
        public void run() {
            locationX = locationX - (int) (VE_HORIZONTAL*BACK_DURATION);
            if(locationX >= 0){
                handler.postDelayed(ImageBack, BACK_DURATION); //回退
                invalidate();
            }
        }
    };
    
    /**
     * 判断是否点击到了滑动区域
     * @param event
     * @return
     */
    private boolean isActionDown(MotionEvent event) {
        Rect rect = new Rect();
        heartView.getHitRect(rect);
        boolean isIn = rect.contains((int)event.getX()-heartView.getWidth(), (int)event.getY());
        if(isIn){
            heartView.setVisibility(View.GONE);
            return true;
        }
        return false;
    }
    
    /**
     * 绘制拖动时的图片
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        invalidateDragImg(canvas);
    }
    
    /**
     * 图片随手势移动
     * @param canvas
     */
    private void invalidateDragImg(Canvas canvas) { 
        int drawX = locationX - dragBitmap.getWidth();
        int drawY = heartView.getTop();
        
        if(drawX < leftRingView.getWidth()){ //划到最左边
            heartView.setVisibility(View.VISIBLE);
            return;
        } else {
            if(isLocked()){ //判断是否成功
                return;
            }
            heartView.setVisibility(View.GONE);
            canvas.drawBitmap(dragBitmap, drawX < 0 ? 5 : drawX,drawY,null);
        }
    }
    
    /**
     * 判断是否解锁
     */
    private boolean isLocked(){
        if(locationX > (getScreenWidth() - rightRingView.getWidth())){
            handler.obtainMessage(LockScreenActivity.MSG_LOCK_SUCESS).sendToTarget();
            return true;
        }
        return false;
    }
    
    /**
     * 获取屏幕宽度
     * @return
     */
    private int getScreenWidth(){
        WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        int width = manager.getDefaultDisplay().getWidth();
        return width;
    }
    
    /**
     * 与主activity通信
     * @param handler
     */
    public void setMainHandler(Handler handler){
        this.handler = handler;
    }
}

2.4 开机广播 LockScreenReceiver.java

 1 package com.lihua.lockscreen;
 2 
 3 import android.app.KeyguardManager;
 4 import android.content.BroadcastReceiver;
 5 import android.content.Context;
 6 import android.content.Intent;
 7 import android.util.Log;
 8 
 9 /**
10  * 开机广播,启动activity
11  * @author lihua
12  *
13  */
14 public class LockScreenReceiver extends BroadcastReceiver {
15     private final static String TAG = "LockScreenReceiver";
16     private KeyguardManager keyguardManager = null;
17     private KeyguardManager.KeyguardLock keyguardLock = null;
18     
19     @Override
20     public void onReceive(Context context, Intent intent) {
21         if(intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)){
22             Intent mIntent = new Intent(context, LockScreenActivity.class);
23             mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
24 
25             keyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
26             keyguardLock = keyguardManager.newKeyguardLock("");
27             keyguardLock.disableKeyguard(); 
28             
29             context.startActivity(mIntent);
30         }
31     }
32 
33 }

2.5 监听服务 LockScreenService.java

 1 package com.lihua.lockscreen;
 2 
 3 import android.app.KeyguardManager;
 4 import android.app.Service;
 5 import android.content.BroadcastReceiver;
 6 import android.content.Context;
 7 import android.content.Intent;
 8 import android.content.IntentFilter;
 9 import android.os.IBinder;
10 import android.util.Log;
11 
12 public class LockScreenService extends Service {
13     private final static String TAG = "LockScreenService";
14     private Intent lockIntent;
15     private KeyguardManager keyguardManager = null;
16     private KeyguardManager.KeyguardLock keyguardLock = null;
17     
18     @Override
19     public IBinder onBind(Intent arg0) {
20         return null;
21     }
22 
23     @Override
24     public void onCreate() {
25         super.onCreate();
26 
27         lockIntent = new Intent(LockScreenService.this, LockScreenActivity.class);
28         lockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
29         
30         //注册广播
31         IntentFilter mScreenOffFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
32         LockScreenService.this.registerReceiver(mScreenOffReceiver, mScreenOffFilter);
33     }
34 
35     @Override
36     public void onDestroy() {
37         super.onDestroy();
38         LockScreenService.this.unregisterReceiver(mScreenOffReceiver);
39         //重新启动activity
40         startService(new Intent(LockScreenService.this, LockScreenService.class));
41     }
42 
43     @Override
44     public int onStartCommand(Intent intent, int flags, int startId) {
45         return Service.START_STICKY;
46     }
47     
48     /**
49      * 屏幕变亮的广播,这里要隐藏系统的锁屏界面
50      */
51     private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
52         @Override
53         public void onReceive(Context context, Intent intent) {
54             Log.i(TAG, intent.getAction());
55             if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF)
56                     || intent.getAction().equals(Intent.ACTION_SCREEN_ON)){
57                 
58                 keyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
59                 keyguardLock = keyguardManager.newKeyguardLock("");
60                 keyguardLock.disableKeyguard(); //这里就是取消系统默认的锁屏
61                 
62                 startActivity(lockIntent); //注意这里跳转的意图
63             }
64         }
65     };
66 }

2.6 主配置文件AndroidManifest.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 3     package="com.lihua.lockscreen"
 4     android:versionCode="1"
 5     android:versionName="1.0" >
 6 
 7     <uses-sdk
 8         android:minSdkVersion="8"
 9         android:targetSdkVersion="16" />
10 
11     <application
12         android:allowBackup="true"
13         android:icon="@drawable/ic_launcher"
14         android:label="@string/app_name"
15         android:theme="@style/AppTheme" >
16         <activity
17             android:name="com.lihua.lockscreen.LockScreenActivity"
18             android:label="@string/app_name" 
19             android:launchMode="singleTask">
20             <intent-filter>
21                 <action android:name="android.intent.action.MAIN" />
22 
23                 <category android:name="android.intent.category.LAUNCHER" />
24             </intent-filter>
25         </activity>
26         <service android:name=".LockScreenService"></service>
27         <receiver android:name=".LockScreenReceiver">
28             <intent-filter>
29                 <action android:name="android.intent.action.BOOT_COMPLETED"></action>
30                 <category android:name="android.intent.category.HOME"/>
31             </intent-filter>
32         </receiver>
33     </application>
34     
35     <uses-permission android:name="android.permission.DISABLE_KEYGUARD"></uses-permission>
36     <uses-permission android:name="android.permission.VIBRATE"></uses-permission>
37     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
38 </manifest>

3. 锁屏思路

整个锁屏的思路是:

注册监听开机的广播

1 <receiver android:name=".LockScreenReceiver">
2             <intent-filter>
3                 <action android:name="android.intent.action.BOOT_COMPLETED"></action>
4                 <category android:name="android.intent.category.HOME"/>
5             </intent-filter>
6 </receiver>

接收开机广播开启activity,activity里开启服务

 <service android:name=".LockScreenService"></service>

服务里监听屏幕off和on的广播,然后关闭系统锁屏,开启自己的锁屏,最后的就是展示自己的锁屏界面

4.软件难点

4.1 怎么保证软件坚决不能被关闭(关闭了就是系统锁屏了),特别是内存管理软件(貌似网上的说法是通过各种广播把自己启动起来,比如监听电池电量变化广播等)

4.2 怎么有良好的锁屏效果,我的这个滑动解锁也是参考了别人的源码,针对不同的局部具体的方法会有所不同

4.3 滑动效果的实现

     大概说一下思路,自定义一个布局类SliderRelativeLayout,处理不同的onTouchEvent方法

@Override
    public boolean onTouchEvent(MotionEvent event) {
        int X = (int) event.getX();

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: 
            locationX = (int) event.getX();
            Log.i(TAG, "是否点击到位=" + isActionDown(event));
            return isActionDown(event);//判断是否点击了滑动区域
            
        case MotionEvent.ACTION_MOVE: //保存x轴方向,绘制图画
            locationX = X;
            invalidate(); //重新绘图
            return true;
            
        case MotionEvent.ACTION_UP: //判断是否解锁成功
            if(!isLocked()){ //没有解锁成功,动画应该回退
                handleActionUpEvent(event); //动画回退
            }
            return true;
        }
        return super.onTouchEvent(event);
    }

三种状态:点击,滑动,离开点击

点击的时候判断是否是心形点击区域,滑动的时候通过Bitmap在canvas里重绘,判断是否到达右边可解锁区域,离开点击判断是否达到解锁区域,没有到达就动画回滚到原来的状态

大概就是这个流程了,具体的就要各位自己去理解了,通过不同的布局,效果和实现也不一样

 

5. 心得体会

六月份就要出去实习了,感觉有时间还是要多学习学习新的技术,业余时间把android学了一下,正好这学期也是有这个课程

很多人都说面向国内用户做android开发赚不了钱,原因是国人没有很好的付费习惯,但总的来说android还是个很好的东西,蛮有意思的

(其实这个程序就是我做给我妹子的,嘿嘿!)

6. 源代码

这里下载

我也是看了别人的源码,所以也分享我的源码

转载于:https://www.cnblogs.com/lihuabest/archive/2013/03/08/2950070.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值