首页 > 代码库 > 仿 惠锁屏 侧滑锁屏的原理

仿 惠锁屏 侧滑锁屏的原理


上面是效果图。

锁屏 总体来说 注意的地方 就两点  一个是  关闭电源 重启 的时候 保证  锁屏界面可以出现, 另一个就是  按home键的时候 不要返回 桌面。


对于  唤醒 电源键  和重启手机时候 弹出锁屏界面 ,可以通过监听 电源 唤醒的 广播,开机广播。
1) 待机:
广播消息:android.intent.action.SCREEN_OFF
2) 唤醒:
广播消息:android.intent.action.SCREEN_ON 

3) 开机
广播消息:android.intent.action.BOOT_COMPLETED


对于屏蔽home 键   我在网上找了一些方法 大致如下,但是很遗憾 都有问题。
在2.3版本以下重写下面方法就能重写home键
public void onAttachedToWindow() {
      this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);
      super.onAttachedToWindow();
}
在4.0以上的版本中需要利用以下方法屏蔽和重写Home键,代码如下:
public static final int FLAG_HOMEKEY_DISPATCHED = 0x80000000; //需要自己定义标志
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.getWindow().setFlags(FLAG_HOMEKEY_DISPATCHED, FLAG_HOMEKEY_DISPATCHED);//关键代码
    setContentView(R.layout.main);
}
再重写onKey事件即可。
@Override
      public boolean onKeyDown( int keyCode, KeyEvent event) {
             // TODO Auto-generated method stub
             if (keyCode == event. KEYCODE_HOME) {
                   return true;
            }
             return super.onKeyDown(keyCode, event);

      }

PS:

在AndroidMainfest.xml需要加权限:  
<uses-permission android:name = "android.permission.DISABLE_KEYGUARD"/><!-- 屏蔽HOME键需要的权限 -->

在配置文件中,在你使用了Notification的activity中加一个属性android: android:launchMode="singleInstance"


很遗憾 上面的方法 会导致  手机黑屏 。。。。 


而且 home键 监听 我们的权限不够,只能想办法 绕过去了,我的思路是 在 点击 home 键 的时候 

 在加载一次当前的界面。 保证 不被 退回到后台中。 稍后 代码中解释。


上面两点  就是 我认为 锁屏 的 关键地方。


下面 在说一下   侧滑界面的实现。 先说原理    中间 是一个大的○  左边 右边 各一个图片。


滑动图片  主要就是 图片的 touch 事件, 图片随着手指落下的位置 移动,当移动到左边图片相交时,我选择让其 直接 以左边图片的中心 为圆心  ,不在让其跟随手指滑动。 同理 右边。 




这里左右图片的半径 其实就是图片宽度的 1/2   (说半径不合适 因为都不是○。记得 是宽度 1/2 就OK)

当○ 往左滑动, 一旦与左边图片相交 也就是绿色线的地方,

让中间的○以 左边图片的中心  。并且此时在往左滑动,也不让中间的○移动, 左边界就是 左图 的中心, 同理 中间大圆环 能滑到右边的 最远距离  就是右图 的 中心的 ○。



原理 就说这些。。。。。。。。。。。。。。。


======================================================================================================


下面稍微介绍下项目 。首先  先实现左右滑动的效果。 那么先把布局做出来,布局就是上面图片中的 三个图片


很简单的布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:background="#000000"
    tools:context=".MainActivity" >

 
        <ImageView 
            android:id="@+id/iv_drag"
            android:layout_centerInParent="true"
            android:src=http://www.mamicode.com/"@drawable/lock_slide_icon_normal_no_quick_launcher">

 下面看怎么用这个布局 , 这里定义 一个 LockView  继承  RelativeLayout ,在构造方法中 找到三个图片的id , 并  实现  中间○的 touch 事件,  

 
img.setOnTouchListener(new OnTouchListener() {
			private int height;

			public boolean onTouch(View v, MotionEvent event) {

				switch (event.getAction()) {

				case MotionEvent.ACTION_DOWN:
					// leftImageView_left:32rightImageView_right:688
					leftImageView_left = leftImageView.getLeft();<span style="font-family: KaiTi_GB2312;">① 左边图片的左边界 距离屏幕左边距离</span>
				        leftImageView_right = leftImageView.getRight();<span style="font-family: KaiTi_GB2312;">① 左边图片 右边界 距离屏幕左边的距离</span>
					rightImageView_right = rightImageView.getRight();<span style="font-family: KaiTi_GB2312;">① 右两边图片的右边界距离屏幕左边的距离</span>
					rightImageView_left = rightImageView.getLeft();<span style="font-family: KaiTi_GB2312;">① 右两边图片的左边 距离屏幕左边的距离</span>
					System.out.println("leftImageView_left:" + leftImageView_left + "rightImageView_right:" + rightImageView_right);
					img.setImageDrawable(getResources().getDrawable(R.drawable.lock_slide_icon_pressed));//改一下 圆环  大的 变成小的
					System.out.println("event.getRawX()" + event.getRawX() + "event.getRawY()" + event.getRawY());
					System.out.println("event.getX()" + event.getX() + "event.getY()" + event.getY());
					height = (int) (event.getRawY() - 50);
					System.out.println("v.getTop()" + v.getTop() + "event.getBottom()" + v.getBottom() + "v.getLeft()" + v.getLeft() + "v.getRight" + v.getRight());
					left = v.getLeft();
					right = v.getRight();
					top = v.getTop();
					bottom = v.getBottom();
					break;
				case MotionEvent.ACTION_MOVE:
					System.out.println("----------event.getRawX()" + event.getRawX() + "event.getRawY()" + event.getRawY());
					System.out.println("----------event.getX()" + event.getX() + "event.getY()" + event.getY());
					mx = (int) (event.getRawX()); //② 记录 中间圆环距离屏幕左边界距离 
					my = (int) (event.getRawY() - 50);//<span style="font-family:KaiTi_GB2312;">② 记录 中间圆环距离屏幕上边界距离</span>
					Log.i(TAG1, "  mx " + mx + "   my" + my + "  img.getWidth()/2" + img.getWidth() / 2 + "   img.getHeight()/2" + img.getHeight() / 2);
					if (mx < width / 2) {// ②这里的 with 是手机屏幕的宽度,如果 圆环距离屏幕左边距离小于手机屏幕宽度的二分之一  说明向左滑动 
						if (mx < leftImageView_right) {// ②这里是判断  有没有滑动到左边图片的右边,如果 小于 说明 圆环 跟左边的图片 已经发生了接触,一旦接触 让 圆环移动到已左边图片中心的位置。
							v.layout(leftImageView_left, top, leftImageView_right, bottom);
							left_flag = true //② 标志  如果到了这个位置 代表滑到最左边了,此时松手 会解锁屏幕
						} else {// 没有接触 那就 按移动的位置去 重新绘制 圆环 layout(l ,t, r, b)   // ②左  上 右 下 四个坐标
							v.layout(mx - img.getWidth() / 2, top, mx + img.getWidth() / 2, bottom);
							left_flag = false;
						}

					} else if (mx > width / 2) {//②<span style="font-family: KaiTi_GB2312;">这里的 with 是手机屏幕的宽度,如果 圆环距离屏幕左边距离大于手机屏幕宽度的二分之一  说明向右滑动 </span>

						if ((mx + img.getWidth() / 2) < rightImageView_right) { // 右边跟左边同理,。。。
							v.layout(mx - img.getWidth() / 2, top, mx + img.getWidth() / 2, bottom);
							Log.i(TAG2, "  int l " + (mx - img.getWidth() / 2) + "   int top" + (my - img.getHeight() / 2) + "    int right" + (mx + img.getWidth() / 2)
									+ "   int bottom" + (my + img.getHeight() / 2));
						}// 688

						if (mx > rightImageView_left) {
							v.layout(rightImageView_left, top, rightImageView_right, bottom);
							right_flag = true;
						} else {
							v.layout(mx - img.getWidth() / 2, top, mx + img.getWidth() / 2, bottom);
							right_flag = false;
						}
					}
					break;

				case MotionEvent.ACTION_UP:

					if (right_flag) {// ③  右边解锁
						Toast.makeText(mContext, "解锁右边", 0).show();
						Intent i = new Intent(mContext, MyService.class);
						i.setAction(MyService.UNLOCK_ACTION); // ***********************这里 是解锁的关键。 到服务里面详细说*************
						mContext.startService(i);
					
					} else if (left_flag) {
						Toast.makeText(mContext, "解锁左边", 0).show();                                                                                                                                                                                                                              
						Intent i2 = new Intent(mContext, MyService.class);
						i2.setAction(MyService.UNLOCK_ACTION);
						mContext.startService(i2);
					}
					right_flag = false;
					left_flag = false;
					v.layout(left, top, right, bottom);  // ③恢复圆环的初始位置
					img.setImageDrawable(getResources().getDrawable(R.drawable.lock_slide_icon_normal_no_quick_launcher));// ③将圆环 换回原来的 大圆环
					break;
				}

				return true;
			}
		});


touch  事件 主要 就是  三个动作 手  按下    手移动   手 抬起 。

对应  
MotionEvent.ACTION_DOWN     
MotionEvent.ACTION_MOVE         
<strong style="font-family: KaiTi_GB2312; background-color: rgb(255, 255, 255);"></strong><pre name="code" class="java" style="display: inline !important;">MotionEvent.ACTION_UP
<strong style="font-family: KaiTi_GB2312; background-color: rgb(255, 255, 255);"></strong><pre name="code" class="java" style="display: inline !important;">
<strong style="font-family: KaiTi_GB2312; background-color: rgb(255, 255, 255);"></strong><pre name="code" class="java" style="display: inline !important;"><span style="font-family: KaiTi_GB2312;"></span>
<strong style="font-family: KaiTi_GB2312; background-color: rgb(255, 255, 255);"></strong><pre name="code" class="java" style="display: inline !important;"><span style="font-family: KaiTi_GB2312;">
</span>
这里要介绍一下 get
RawX()
与getX() 区别。 一张图

 很明白的一张图, R 是 取得 距离 屏幕 边距的距离 不带Raw 的是取得距离父布局 的边界距离。



按下 的动作中我们需要做什么? 按下时 主要操作 看代码 中的① 注释

在 手移动 的动作中我们需要做什么? 按下时 主要操作 看代码 中的② 注释

抬起 的动作中我们需要做什么? 按下时 主要操作 看代码 中的③ 注释


OK 实现 手可以控制 圆环 左右滑动后, 我们去实现 解锁屏幕

这个功能在服务里面实现

关键代码如下 :

public int onStartCommand(Intent intent, int flags, int startId) {
	
		if(intent!=null){
			System.out.println("intent------------intent.getAction()-==null?????--"+(intent==null));
			String action = intent.getAction();
			if(TextUtils.equals(action, LOCK_ACTION)) // 这是屏蔽 home 键的关键
				addView();
			else if(TextUtils.equals(action, UNLOCK_ACTION))   // 这里是解锁屏幕
			{
				removeView();
//				stopSelf();
			}
		}
		return Service.START_STICKY;
	}

 屏蔽home键的原理  上面说过  是  在加载一次 当前布局。   也就是通过action 判断的。

 在 我们上面 手滑动到左右两边的时候 我们 做的操作是


Intent i = new Intent(mContext, MyService.class);
i.setAction(MyService.UNLOCK_ACTION); // ***********************这里 是解锁的关键。 到服务里面详细说*************
mContext.startService(i);
传过去一个 Action 代表 是解锁

其他情况下 的Action 都是 锁定。


那么 还剩下一个问题 就是保持  手机    唤醒屏幕时候能用弹出锁屏界面



同样 在服务里面 注册两个广播保证 手机唤醒的时候  开启服务

public void onCreate() {
		super.onCreate();
		
		mContext = getApplicationContext();
		mWinMng = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
		
		
		i = new Intent(mContext, MyService.class);
		i.setAction(MyService.LOCK_ACTION);
		zdLockIntent = new Intent(MyService.this , MyService.class);
		zdLockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		
		/*注册广播*/
		IntentFilter mScreenOnFilter = new IntentFilter("android.intent.action.SCREEN_ON");
		MyService.this.registerReceiver(mScreenOnReceiver, mScreenOnFilter);
		
		/*注册广播*/
		IntentFilter mScreenOffFilter = new IntentFilter("android.intent.action.SCREEN_OFF");
		MyService.this.registerReceiver(mScreenOffReceiver, mScreenOffFilter);
	}


广播 中 判断 当Action  是  唤醒屏幕的时候   去开启一下服务。


	
	//屏幕变暗/变亮的广播 , 我们要调用KeyguardManager类相应方法去解除屏幕锁定
	private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver(){
		@Override
		public void onReceive(Context context , Intent intent) {
			String action = intent.getAction() ;
			
		    Log.i(TAG, intent.toString());
		    
			if(action.equals("android.intent.action.SCREEN_OFF")
					|| action.equals("android.intent.action.SCREEN_ON") ){
				mKeyguardManager = (KeyguardManager)context.getSystemService(Context.KEYGUARD_SERVICE);
				mKeyguardLock = mKeyguardManager.newKeyguardLock("zdLock 1"); 
				mKeyguardLock.disableKeyguard();
//				startService(zdLockIntent);
			
		        //Intent.FLAG_ACTIVITY_NEW_TASK. This flag is generally used by activities that want to present a "launcher" style behavior
				startService(i);
			}
		}
		
	};


	//屏幕变亮的广播,我们要隐藏默认的锁屏界面
	private BroadcastReceiver mScreenOnReceiver = new BroadcastReceiver(){

		@Override
		public void onReceive(Context context , Intent intent) {
			
            Log.i(TAG, intent.getAction());

			if(intent.getAction().equals("android.intent.action.SCREEN_ON")){
				Log.i(TAG, "----------------- android.intent.action.SCREEN_ON------");
				mKeyguardManager = (KeyguardManager)context.getSystemService(Context.KEYGUARD_SERVICE);
				mKeyguardLock = mKeyguardManager.newKeyguardLock("zdLock 1"); 
				mKeyguardLock.disableKeyguard();
			
		        //Intent.FLAG_ACTIVITY_NEW_TASK. This flag is generally used by activities that want to present a "launcher" style behavior
				startService(i);
			
			}
		}
		
	};


// 这里注意把 手机系统自带的 锁屏 屏蔽掉。


最后别忘了 权限, 看下 清单文件:

<uses-permission android:name = "android.permission.DISABLE_KEYGUARD"/><!-- 屏蔽HOME键需要的权限 --> 
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:theme="@android:style/Theme.Translucent" 
            android:name="com.example.mylock.MainActivity"
            android:label="@string/app_name" >
          <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name=".BootCompletedReciever" android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>
            <service android:name=".MyService" >
        </service>
    </application>



OK 最后 上代码 : 下载地址----------*******************-------------









仿 惠锁屏 侧滑锁屏的原理