android的锁屏页面有两种方法实现;
我参考了他们,写的是一个activity页面当做锁屏页面
1.程序运行后开启一个管理锁屏页面的服务
//开启服务,开启锁屏界面
startService(new Intent(MainActivity.this, LockScreenService.class));
2.在这个服务中去开启锁屏页面
public class LockScreenService extends Service {
//屏幕熄灭的广播
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() == Intent.ACTION_SCREEN_OFF) {
Intent lockScreenIntent = new Intent(LockScreenService.this,LockScreenActivity.class);
lockScreenIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (!BaseApplication.getInstance().getParam(Params.IS_FORBID, false)) {
startActivity(lockScreenIntent);
}
}
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
logger.debug("开启锁屏服务");
return START_STICKY;
};
@Override
public void onCreate() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(receiver, filter);
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onDestroy() {
unregisterReceiver(receiver);
super.onDestroy();
Intent localIntent = new Intent();
localIntent.setClass(this, LockScreenService.class); //销毁时重新启动Service
this.startService(localIntent);
}
}
3.锁屏页面
public class LockScreenActivity extends BaseActivity {
/**左右滑动的监听*/
private final class OnSildingFinishListenerImplementation implements
OnSildingFinishListener {
@Override
public void onSildingForward() {
LockScreenActivity.this.finish();
}
@Override
public void onSildingBack() {
LockScreenActivity.this.finish();
}
}
ImageView iv_right_slip_anim;
public static Handler myHandler = new Handler();
private boolean isSpeaking = false;
@Override
public int getLayoutResId() {
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);//这句话必须写在前面
return R.layout.activity_lockscreen;
}
@Override
public void initView() {
Bitmap bitmap = BitmapUtil.decodeSampledBitmapFromResource(getResources(), R.drawable.lockscreen_bg, 200, 400);
Drawable drawable = BitmapUtil.bitmapToDrawable(bitmap);
slf.setBackground(drawable);//设置了锁屏页面的背景色,根据自己的需要进行设置
slf.setEnableLeftSildeEvent(true);
slf.setEnableRightSildeEvent(false);
setRightSlipAnim();
}
@Override
public void initListener() {
slf.setOnSildingFinishListener(new OnSildingFinishListenerImplementation());
}
@Override
public void initData() {
// TODO Auto-generated method stub
}
@Override
public void doOtherDestroy() {
}
private void setRightSlipAnim() {
iv_right_slip_anim.setImageResource(R.anim.lockscreen_right_slip);
AnimationDrawable animationDrawable = (AnimationDrawable) iv_right_slip_anim.getDrawable();
animationDrawable.start();
}
@Override
public void onBackPressed() {
// 不做任何事,为了屏蔽back键
}
在这个页面注册滑动监听,需要页面跟着手指一起移动,这里用到了一个自定义的布局,作为activity的头布局
4.我的activity的布局文件,头布局要用自定义的布局
<?xml version="1.0" encoding="utf-8"?>
<***.view.SildingFinishLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sfl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/black">
。。。。。。。。。
</***.SildingFinishLayout>
5.自定义的可以滑动的布局
/**
* 自定义可以滑动的RelativeLayout, 类似于IOS的滑动删除页面效果,当我们要使用
* 此功能的时候,需要将该Activity的顶层布局设置为SildingFinishLayout,
*/
public class SildingFinishLayout extends RelativeLayout{
private final String TAG = SildingFinishLayout.class.getName();
/**
* SildingFinishLayout布局的父布局
*/
private ViewGroup mParentView;
/**
* 滑动的最小距离
*/
private int mTouchSlop;
/**
* 按下点的X坐标
*/
private int downX;
/**
* 按下点的Y坐标
*/
private int downY;
/**
* 临时存储X坐标
*/
private int tempX;
/**
* 滑动类
*/
private Scroller mScroller;
/**
* SildingFinishLayout的宽度
*/
private int viewWidth;
/**
* 记录是否正在滑动
*/
private boolean isSilding;
private OnSildingFinishListener onSildingFinishListener;
private boolean enableLeftSildeEvent = true; //是否开启左侧切换事件
private boolean enableRightSildeEvent = true; // 是否开启右侧切换事件
private int size ; //按下时范围(处于这个范围内就启用切换事件,目的是使当用户从左右边界点击时才响应)
private boolean isIntercept = false; //是否拦截触摸事件
private boolean canSwitch;//是否可切换
private boolean isSwitchFromLeft = false; //左侧切换
private boolean isSwitchFromRight = false; //右侧侧切换
public SildingFinishLayout(Context context) {
super(context);
init(context);
}
public SildingFinishLayout(Context context, AttributeSet attrs) {
super(context, attrs, 0);
init(context);
}
public SildingFinishLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
Log.i(TAG, "设备的最小滑动距离:" + mTouchSlop);
mScroller = new Scroller(context);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed) {
// 获取SildingFinishLayout所在布局的父布局
mParentView = (ViewGroup) this.getParent();
viewWidth = this.getWidth();
size = viewWidth;
}
Log.i(TAG, "viewWidth=" + viewWidth);
}
public void setEnableLeftSildeEvent(boolean enableLeftSildeEvent) {
this.enableLeftSildeEvent = enableLeftSildeEvent;
}
public void setEnableRightSildeEvent(boolean enableRightSildeEvent) {
this.enableRightSildeEvent = enableRightSildeEvent;
}
/**
* 设置OnSildingFinishListener, 在onSildingFinish()方法中finish Activity
*
* @param onSildingFinishListener
*/
public void setOnSildingFinishListener(
OnSildingFinishListener onSildingFinishListener) {
this.onSildingFinishListener = onSildingFinishListener;
}
//是否拦截事件,如果不拦截事件,对于有滚动的控件的界面将出现问题(相冲突)
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
float downX = ev.getRawX();
Log.i(TAG, "downX =" + downX + ",viewWidth=" + viewWidth);
if(enableLeftSildeEvent && downX < size){
Log.e(TAG, "downX 在左侧范围内 ,拦截事件");
isIntercept = true;
isSwitchFromLeft = true;
isSwitchFromRight = false;
return false;
}else if(enableRightSildeEvent && downX > (viewWidth - size)){
// Log.i(TAG, "downX 在右侧范围内 ,拦截事件");
isIntercept = true;
isSwitchFromRight = true;
isSwitchFromLeft = false;
return true;
}else{
// Log.i(TAG, "downX 不在范围内 ,不拦截事件");
isIntercept = false;
isSwitchFromLeft = false;
isSwitchFromRight = false;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(!isIntercept){//不拦截事件时 不处理
return false;
}
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
downX = tempX = (int) event.getRawX();
downY = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int moveX = (int) event.getRawX();
int deltaX = tempX - moveX;
tempX = moveX;
if (Math.abs(moveX - downX) > mTouchSlop && Math.abs((int) event.getRawY() - downY) < mTouchSlop) {
isSilding = true;
}
Log.e(TAG, "scroll deltaX=" + deltaX);
if(enableLeftSildeEvent){//左侧滑动
if (moveX - downX >= 0 && isSilding) {
mParentView.scrollBy(deltaX, 0);
}
}
if(enableRightSildeEvent){//右侧滑动
if (moveX - downX <= 0 && isSilding) {
mParentView.scrollBy(deltaX, 0);
}
}
Log.i(TAG + "/onTouchEvent", "mParentView.getScrollX()=" + mParentView.getScrollX());
break;
case MotionEvent.ACTION_UP:
isSilding = false;
//mParentView.getScrollX() <= -viewWidth / 2 ==>指左侧滑动
//mParentView.getScrollX() >= viewWidth / 2 ==>指右侧滑动
if (mParentView.getScrollX() <= -viewWidth / 2 || mParentView.getScrollX() >= viewWidth / 2) {
canSwitch = true;
if(isSwitchFromLeft){
scrollToRight();
}
if(isSwitchFromRight){
scrollToLeft();
}
} else {
scrollOrigin();
canSwitch = false;
}
break;
}
return true;
}
/**
* 滚动出界面至右侧
*/
private void scrollToRight() {
final int delta = (viewWidth + mParentView.getScrollX());
// 调用startScroll方法来设置一些滚动的参数,我们在computeScroll()方法中调用scrollTo来滚动item
mScroller.startScroll(mParentView.getScrollX(), 0, -delta + 1, 0, Math.abs(delta));
postInvalidate();
}
/**
* 滚动出界面至左侧
*/
private void scrollToLeft() {
final int delta = (viewWidth - mParentView.getScrollX());
// 调用startScroll方法来设置一些滚动的参数,我们在computeScroll()方法中调用scrollTo来滚动item
mScroller.startScroll(mParentView.getScrollX(), 0, delta - 1, 0, Math.abs(delta));//此处就不可用+1,也不卡直接用delta
postInvalidate();
}
/**
* 滚动到起始位置
*/
private void scrollOrigin() {
int delta = mParentView.getScrollX();
mScroller.startScroll(mParentView.getScrollX(), 0, -delta, 0,
Math.abs(delta));
postInvalidate();
}
@Override
public void computeScroll(){
// 调用startScroll的时候scroller.computeScrollOffset()返回true,
if (mScroller.computeScrollOffset()) {
mParentView.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
if (mScroller.isFinished()) {
if (onSildingFinishListener != null && canSwitch) {
Log.i(TAG, "mScroller finish");
if(isSwitchFromLeft){//回调,左侧切换事件
onSildingFinishListener.onSildingBack();
}
if(isSwitchFromRight){//右侧切换事件
onSildingFinishListener.onSildingForward();
}
}
}
}
}
public interface OnSildingFinishListener {
public void onSildingBack();
public void onSildingForward();
}
}
这个布局可以用来分别监听向左、向右滑动,根据自己的需要来写。
6.在清单文件中对锁屏的activity的注册
<activity
android:name="cn.zectec.ptt.activity.LockScreenActivity"
android:launchMode="singleInstance"
android:taskAffinity="cn.zectec.ptt.activity.lockscreen"
android:excludeFromRecents="true"
android:noHistory="false"//之前设置的是true,发现锁屏页面会一次出现一次消失,就改成了false
android:theme="@style/LockScreenBase"
android:screenOrientation="portrait" />
style的样式:
<!-- 锁屏界面样式 -->
<style name="LockScreenBase" parent="android:Theme.Light.NoTitleBar">
<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>
</style>
<!-- <item name="android:backgroundDimEnabled">false</item>
<item name="android:windowAnimationStyle">@null</item>
<item name="android:windowContentOverlay">@null</item> -->
这个样式可以根据自己的需求来设置。
思路:服务中注册屏幕熄灭广播,发现屏幕熄灭就开启锁屏页面,再次点亮屏幕,滑动锁屏页面,锁屏页面被销毁,进入程序主界面。