上面是效果图。
锁屏 总体来说 注意的地方 就两点 一个是 关闭电源 重启 的时候 保证 锁屏界面可以出现, 另一个就是 按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="@drawable/lock_slide_icon_normal_no_quick_launcher" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <ImageView android:layout_alignParentLeft="true" android:id="@+id/iv_left" android:layout_centerInParent="true" android:src="@drawable/lock_left_download_icon_normal" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <ImageView android:layout_alignParentRight="true" android:id="@+id/iv_right" android:layout_centerInParent="true" android:src="@drawable/lock_right_icon_normal" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </RelativeLayout>
下面看怎么用这个布局 , 这里定义 一个 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
最后 上代码 : 下载地址----------*******************-------------