其实九宫格解锁在Android上不是什么新鲜的东西,至今还有不少人的锁屏界面的解锁方式是九宫格解锁,但至于app九宫格解锁的要求,本人至今只使用支付宝的九宫格解锁

最近在做一个app的时候有一个需求,与支付宝有点类似 ,是牵涉到金钱支付的项目 所以有需求在app上加一个九宫格解锁(跟钱有关,小心为上或者说是避免其他人使用你的app),具体需求如下:

1、界面

具体说来可以归类为4类:splash界面、login界面、九宫格界面、主界面(包括应用的其它界面)

2、要求【程序从后台进入前台、手机熄屏后打开、点击app图标进入】

2.1、splash界面不显示解锁界面

2.2、登陆界面不显示解锁界面

2.3、其它界面需要显示解锁界面

2.4、当前app处于锁屏界面,推送消息来了,打开通知需要显示解锁界面,解锁后显示推送具体的页面,在该页面返回不需要显示解锁,直接显示以前的界面

2.5、app未启动,推送消息来时,显示解锁界面,解锁后显示推送界面,在推送界面返回,进入程序splash界面

2.6、程序第一次进入主界面时需要设置九宫格解锁,设置成功后即可进入主界面,后面只需要解锁

2.7、四次解锁失败后,程序被锁住60分钟,当然可以通过登陆界面直接登陆进入

2.8、其它地方暂定

由于Android的每个界面生命周期是单独控制的,所以统一监听程序后台进前台以及实现上面的逻辑有点晕,如下是我的实现代码,本人技术有限,代码肯定有一些逻辑误区以及不足处,请谅解

解锁画布【网上扒的,具体此处已经找不到了,自己也修改了一些】‘

package com.lockdemo.view;import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;/*** 自定义锁屏View*/
public class GestureLockView extends View {/** 解锁密码key */private String key = "";private OnGestureFinishListener onGestureFinishListener;/** 解锁圆点数组 */private LockCircle[] cycles;/** 存储触碰圆的序列 */private List<Integer> linedCycles = new ArrayList<Integer>();// 画笔/** 空心外圆 */private Paint paintNormal;/** 点击后内部圆 */private Paint paintInnerCycle;/** 画路径 */private Paint paintLines;private Path linePath = new Path();/** 当前手指X,Y位置 */private int eventX, eventY;/** 能否操控界面绘画 */private boolean canContinue = true;/** 能否操控界面绘画 */private boolean unlockable = true;/** 设置密码模式 */private boolean setlockmode = false;/** 错误解锁的次数 */public static int LockErrorTime = 5;/** 验证结果 */private boolean result;private Timer timer;/** 未选中颜色 */private final int NORMAL_COLOR = Color.parseColor("#959BB4");/** 错误颜色 */private final int ERROE_COLOR = Color.parseColor("#FF2525"); // 正常外圆颜色/** 选中时颜色 */private final int TOUCH_COLOR = Color.parseColor("#409DE5"); // 选中内圆颜色/** 设置时颜色 */private final int SET_COLOR = Color.parseColor("#7CCD7C"); // 选中内圆颜色// =================================start=构造方法========================public GestureLockView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init();}public GestureLockView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public GestureLockView(Context context) {this(context, null);}// ===============================end=构造方法========================/** 初始化 */public void init() {paintNormal = new Paint();paintNormal.setAntiAlias(true);paintNormal.setStrokeWidth(5);paintNormal.setStyle(Paint.Style.STROKE);paintInnerCycle = new Paint();paintInnerCycle.setAntiAlias(true);paintInnerCycle.setStyle(Paint.Style.FILL);paintLines = new Paint();paintLines.setAntiAlias(true);paintLines.setStyle(Paint.Style.STROKE);paintLines.setStrokeWidth(10);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int specMode = MeasureSpec.getMode(widthMeasureSpec);int spceSize = MeasureSpec.getSize(widthMeasureSpec);heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) (spceSize * 0.85 + 0.5f), specMode);super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);int perWidthSize = getWidth() / 7;int perHeightSize = getHeight() / 6;/** 初始化圆的参数 */if (cycles == null && (perWidthSize > 0) && (perHeightSize > 0)) {cycles = new LockCircle[9];for (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++) {LockCircle lockCircle = new LockCircle();lockCircle.setNum(i * 3 + j);lockCircle.setOx(perWidthSize * (j * 2 + 1.5f) + 0.5f);lockCircle.setOy(perHeightSize * (i * 2 + 1) + 0.5f);lockCircle.setR(perWidthSize * 0.6f);cycles[i * 3 + j] = lockCircle;}}}}public void setKey(String key) {this.key = key;}public void setUnlock(boolean unlockable) {this.unlockable = unlockable;}public void setLockMode(boolean setlockmode) {this.setlockmode = setlockmode;}public void setOnGestureFinishListener(OnGestureFinishListener onGestureFinishListener) {this.onGestureFinishListener = onGestureFinishListener;}/** 手势输入完成后回调接口 */public interface OnGestureFinishListener {/** 手势输入完成后回调函数 */public void OnGestureFinish(boolean success, String key);}/** 监听手势 */@Overridepublic boolean onTouchEvent(MotionEvent event) {if (canContinue && unlockable) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:case MotionEvent.ACTION_MOVE:eventX = (int) event.getX();eventY = (int) event.getY();for (int i = 0; i < cycles.length; i++) {if (cycles[i].isPointIn(eventX, eventY)) {cycles[i].setOnTouch(true);if (!linedCycles.contains(cycles[i].getNum())) {linedCycles.add(cycles[i].getNum());}}}break;case MotionEvent.ACTION_UP:// 手指离开暂停触碰canContinue = false;StringBuffer stringBuffer = new StringBuffer();for (int i = 0; i < linedCycles.size(); i++) {stringBuffer.append(linedCycles.get(i));}result = key.equals(stringBuffer.toString());if (onGestureFinishListener != null && linedCycles.size() > 0) {onGestureFinishListener.OnGestureFinish(result, stringBuffer.toString());}timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {eventX = eventY = 0;for (int i = 0; i < 9; i++) {cycles[i].setOnTouch(false);}linedCycles.clear();linePath.reset();canContinue = true;postInvalidate();// 在非ui线程刷新界面}}, 1000);break;}invalidate();}return true;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int cycleSize = cycles.length;for (int i = 0; i < cycleSize; i++) {// 画完并且错误if (!canContinue && !result) {if (cycles[i].isOnTouch()) {if (setlockmode) {drawInnerCycle(cycles[i], canvas, SET_COLOR);drawOutsideCycle(cycles[i], canvas, SET_COLOR);} else {drawInnerCycle(cycles[i], canvas, ERROE_COLOR);drawOutsideCycle(cycles[i], canvas, ERROE_COLOR);}} elsedrawOutsideCycle(cycles[i], canvas, NORMAL_COLOR);}// 绘画中else {if (cycles[i].isOnTouch()) {drawInnerCycle(cycles[i], canvas, TOUCH_COLOR);drawOutsideCycle(cycles[i], canvas, TOUCH_COLOR);} elsedrawOutsideCycle(cycles[i], canvas, NORMAL_COLOR);}}if (!canContinue && !result) {if (setlockmode) {drawLine(canvas, SET_COLOR);} else {drawLine(canvas, ERROE_COLOR);}} else {drawLine(canvas, TOUCH_COLOR);}}/** 画空心圆 */private void drawOutsideCycle(LockCircle lockCircle, Canvas canvas, int color) {paintNormal.setColor(color);canvas.drawCircle(lockCircle.getOx(), lockCircle.getOy(), lockCircle.getR(), paintNormal);}/** 画横线 */private void drawLine(Canvas canvas, int color) {// 构建路径linePath.reset();if (linedCycles.size() > 0) {int size = linedCycles.size();for (int i = 0; i < size; i++) {int index = linedCycles.get(i);float x = cycles[index].getOx();float y = cycles[index].getOy();if (i == 0) {linePath.moveTo(x, y);} else {linePath.lineTo(x, y);}}if (canContinue) {linePath.lineTo(eventX, eventY);} else {linePath.lineTo(cycles[linedCycles.get(linedCycles.size() - 1)].getOx(), cycles[linedCycles.get(linedCycles.size() - 1)].getOy());}paintLines.setColor(color);canvas.drawPath(linePath, paintLines);}}/** 画中心圆圆 */private void drawInnerCycle(LockCircle myCycle, Canvas canvas, int color) {paintInnerCycle.setColor(color);canvas.drawCircle(myCycle.getOx(), myCycle.getOy(), myCycle.getR() / 3f, paintInnerCycle);}/*** 每个圆点类*/class LockCircle {/** 圆心横坐标 */private float ox;/** 圆心纵坐标 */private float oy;/** 半径长度 */private float r;/** 代表数值 */private Integer num;/** 是否选择:false=未选中 */private boolean onTouch;public float getOx() {return ox;}public void setOx(float ox) {this.ox = ox;}public float getOy() {return oy;}public void setOy(float oy) {this.oy = oy;}public void setOy(int oy) {this.oy = oy;}public float getR() {return r;}public void setR(float r) {this.r = r;}public Integer getNum() {return num;}public void setNum(Integer num) {this.num = num;}public boolean isOnTouch() {return onTouch;}public void setOnTouch(boolean onTouch) {this.onTouch = onTouch;}/** 判读传入位置是否在圆心内部 */public boolean isPointIn(int x, int y) {double distance = Math.sqrt((x - ox) * (x - ox) + (y - oy) * (y - oy));return distance < r;}}public void minusErrorTime() {LockErrorTime--;}public int getLockErrorTime() {return LockErrorTime;}public void resetErrorTime() {LockErrorTime = 5;}
}

LockActivity:

package com.lockdemo.activity;import com.lidroid.xutils.ViewUtils;
import com.lidroid.xutils.util.PreferencesUtils;
import com.lidroid.xutils.util.StringUtils;
import com.lidroid.xutils.view.annotation.ViewInject;
import com.lockdemo.application.LockApplication;
import com.lockdemo.view.GestureLockView;
import com.lockdemo.view.GestureLockView.OnGestureFinishListener;import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.text.Html;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.TextView;public class LockActivity extends BaseActivity {@ViewInject(R.id.gesture_tv_tips)private TextView gesture_tv_tips;@ViewInject(R.id.gestureLockView)private GestureLockView gestureLockView;@ViewInject(R.id.gesture_tv_forget)private TextView gesture_tv_forget;@ViewInject(R.id.gesture_btn_reset)private TextView gesture_btn_reset;private Animation animation;private boolean flag = false;private String key;private String keystore;private int count = 0;private MyCount counttime;@Overrideprotected void onCreate(Bundle arg0) {super.onCreate(arg0);setContentView(R.layout.activity_lock);LockApplication.getInstance().addActivity(this);ViewUtils.inject(this);init();}@Overrideprotected void onDestroy() {super.onDestroy();gestureLockView.resetErrorTime();stopCountTime();LockApplication.isShowLock = false;}@Overrideprotected void onResume() {super.onResume();LockApplication.isShowLock = true;}private void init() {animation = new TranslateAnimation(-20, 20, 0, 0);animation.setDuration(50);animation.setRepeatCount(2);animation.setRepeatMode(Animation.REVERSE);key = PreferencesUtils.getString(LockActivity.this, PreferencesUtils.getString(LockActivity.this, "UserUid") + "_Lockkey", "");if (!StringUtils.isEmpty(key)) {flag = true;// 设置密码gestureLockView.setKey(key);startCountTime(countTimeBollean());} else {gesture_tv_tips.setTextColor(Color.parseColor("#FFFFFF"));gesture_tv_tips.setVisibility(View.VISIBLE);gesture_tv_tips.setText("请先设置应用解锁密码\n[至少4位]");gesture_tv_forget.setVisibility(View.GONE);gestureLockView.setLockMode(true);}// 手势完成后回调gestureLockView.setOnGestureFinishListener(new OnGestureFinishListener() {@Overridepublic void OnGestureFinish(boolean success, String key) {if (flag) {if (success) {LockApplication.getInstance().toFinish(LockActivity.class);finish();} else {gestureLockView.minusErrorTime();if (gestureLockView.getLockErrorTime() > 0) {gesture_tv_tips.setTextColor(Color.parseColor("#FF2525"));gesture_tv_tips.setVisibility(View.VISIBLE);gesture_tv_tips.setText("密码错误\n还可以再解锁" + gestureLockView.getLockErrorTime() + "次");gesture_tv_tips.startAnimation(animation);} else {setLockTime(System.currentTimeMillis());startCountTime((long) 3600000);}}} else {if (key.length() > 3) {count++;if (count == 1) {keystore = key;gesture_tv_tips.setTextColor(Color.parseColor("#FFFFFF"));gesture_tv_tips.setText("请再次设置解锁密码");gesture_btn_reset.setText(Html.fromHtml("<u>" + "重新设置" + "</u>"));gesture_btn_reset.setVisibility(View.VISIBLE);} else if (count == 2) {if (keystore.equals(key)) {showToast("解锁密码设置成功");// 此处密码请自行加密PreferencesUtils.putString(LockActivity.this, PreferencesUtils.getString(LockActivity.this, "UserUid") + "_Lockkey", keystore);LockApplication.getInstance().toFinish(LockActivity.class);finish();} else {count = 0;gesture_tv_tips.setText("请先设置应用解锁密码\n[至少4位]");gesture_tv_tips.startAnimation(animation);showToast("两次密码设置不一致,请重新设置");gesture_btn_reset.setVisibility(View.GONE);}}} else {if (count == 1) {count = 0;gesture_tv_tips.setText("请先设置应用解锁密码\n[至少4位]");gesture_tv_tips.startAnimation(animation);showToast("两次密码设置不一致,请重新设置");gesture_btn_reset.setVisibility(View.GONE);} else {count = 0;gesture_tv_tips.setText("请先设置应用解锁密码\n[至少4位]");gesture_tv_tips.startAnimation(animation);showToast("解锁密码太短,请重新设置");}}}}});gesture_tv_forget.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View view) {Intent intent = new Intent(LockActivity.this, LoginActivity.class);startActivity(intent);finish();}});gesture_btn_reset.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View view) {keystore = null;count = 0;gesture_tv_tips.setText("请先设置应用解锁密码\n[至少4位]");gesture_tv_tips.startAnimation(animation);gesture_btn_reset.setVisibility(View.GONE);}});}/*** 开始计时工作*/private void startCountTime(Long count) {if (count != 0) {gestureLockView.setUnlock(false);gesture_tv_tips.setTextColor(Color.parseColor("#ED6C00"));gesture_tv_tips.setVisibility(View.VISIBLE);counttime = new MyCount(count, 1000);counttime.start();}}/*** 停止计时*/private void stopCountTime() {if (counttime != null) {counttime.cancel();counttime = null;}}/*** * @Title: countTimeBollean* @Description: TODO(计算解锁时间)* @param @return 设定文件* @return long 返回类型* @throws*/private long countTimeBollean() {long cnt = PreferencesUtils.getLong(LockActivity.this, PreferencesUtils.getString(LockActivity.this, "UserUid") + "_DataNum", 0);if (cnt == 0) {return 0;} else {long spass = System.currentTimeMillis() - cnt;if (spass < 0 || spass > 3600000) {return 0;} else {return (3600000 - spass);}}}private class MyCount extends CountDownTimer {public MyCount(long millisInFuture, long countDownInterval) {super(millisInFuture, countDownInterval);}@Overridepublic void onFinish() {gestureLockView.setUnlock(true);gestureLockView.resetErrorTime();gesture_tv_tips.setTextColor(Color.parseColor("#FFFFFF"));gesture_tv_tips.setText("请解锁应用");setLockTime(0);}@Overridepublic void onTick(long millisUntilFinished) {long minutes = millisUntilFinished / (60 * 1000);long seconds = (millisUntilFinished % (60 * 1000)) / 1000;if (minutes > 0) {if (seconds > 0) {gesture_tv_tips.setText("请" + minutes + "分" + seconds + "秒后尝试解锁");} else {gesture_tv_tips.setText("请" + minutes + "分后尝试解锁");}} else {gesture_tv_tips.setText("请" + seconds + "秒后尝试解锁");}}}private void setLockTime(long time) {PreferencesUtils.putLong(LockActivity.this, PreferencesUtils.getString(LockActivity.this, "UserUid") + "_DataNum", time);}private void back() {LockApplication.getInstance().exit();}@Overridepublic void onBackPressed() {back();}
}

LockApplication:

package com.lockdemo.application;import java.util.ArrayList;
import java.util.List;import com.lockdemo.recall.ScreenListener;import android.app.Activity;
import android.app.Application;public class LockApplication extends Application {public static LockApplication instance = null;/** 程序活动列表 */private List<Activity> activityList = new ArrayList<Activity>();public static LockApplication getInstance() {if (instance == null) {instance = new LockApplication();}return instance;}@Overridepublic void onCreate() {super.onCreate();}/** 程序在前台 */public static boolean isActive = false;/** 程序从后台到前台 */public static boolean isBtoF = false;/** 正在显示lock界面 */public static boolean isShowLock = false;/** 不显示显示lock界面【splash界面和login界面】 */public static boolean notShowLock = false;/** 显示亮屏的次数 */public static int ligthCount = 0;/** main界面resume次数 */public static int mainCount = 0;/** 屏幕锁屏监听 */public static ScreenListener sl;public void addActivity(Activity activity) {activityList.add(activity);}public void exit() {sl.unregisterListener();for (Activity activity : activityList) {activity.finish();}System.exit(0);}public void finishAll() {for (Activity activity : activityList) {activity.finish();}activityList.clear();}@SuppressWarnings("rawtypes")public void finishOthers(Class clazz) {for (int i = 0; i < activityList.size(); i++) {if (!clazz.getName().equals(activityList.get(i).getClass().getName())) {activityList.get(i).finish();activityList.remove(i);}}}@SuppressWarnings("rawtypes")public void toFinish(Class clazz) {for (int i = 0; i < activityList.size(); i++) {if (clazz.getName().equals(activityList.get(i).getClass().getName())) {activityList.get(i).finish();activityList.remove(i);}}}@SuppressWarnings("rawtypes")public boolean hasClazz(Class clazz) {boolean flag = false;for (int i = 0; i < activityList.size(); i++) {if (clazz.getName().equals(activityList.get(i).getClass().getName())) {flag = true;}}return flag;}}

Activity基类:

package com.lockdemo.activity;import java.util.List;import com.lidroid.xutils.util.LogUtils;
import com.lockdemo.application.LockApplication;
import com.lockdemo.recall.ScreenListener;
import com.lockdemo.recall.ScreenListener.ScreenStateListener;import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.widget.Toast;public class BaseActivity extends FragmentActivity {private final static int TOASTTIME = 1000;private Intent intent = null;@Overridepublic void onBackPressed() {super.onBackPressed();}@Overrideprotected void onCreate(Bundle arg0) {super.onCreate(arg0);}@Overrideprotected void onDestroy() {super.onDestroy();}@Overrideprotected void onPause() {super.onPause();}@Overrideprotected void onResume() {super.onResume();if (!LockApplication.isActive) {// app 从后台唤醒,进入前台LockApplication.isActive = true;if (LockApplication.isBtoF) {LockApplication.isBtoF = false;if (!LockApplication.isShowLock && !LockApplication.notShowLock) {intent = new Intent(getApplicationContext(), LockActivity.class);intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);startActivity(intent);}}}if (LockApplication.sl == null) {LockApplication.sl = new ScreenListener(this);LockApplication.sl.begin(new ScreenStateListener() {@Overridepublic void onUserPresent() {LogUtils.d("onUserPresent");}@Overridepublic void onScreenOn() {LogUtils.d("onScreenOn");/** 排除第一次监听 显示亮屏 */LockApplication.ligthCount++;if (LockApplication.isActive && !LockApplication.isShowLock && (LockApplication.ligthCount > 1) && !LockApplication.notShowLock) {intent = new Intent(getApplicationContext(), LockActivity.class);intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);startActivity(intent);}}@Overridepublic void onScreenOff() {LogUtils.d("onScreenOff");}});}}@Overrideprotected void onStart() {super.onStart();}@Overrideprotected void onStop() {super.onStop();if (!isAppOnForeground()) {// app 进入后台LockApplication.isActive = false;LockApplication.isBtoF = true;}}@Overridepublic void startActivityForResult(Intent intent, int requestCode) {super.startActivityForResult(intent, requestCode);}@Overrideprotected void onRestart() {super.onRestart();}public void showToast(String msg) {Toast.makeText(getApplicationContext(), msg, TOASTTIME).show();}/*** 程序是否在前台运行* * @return*/public boolean isAppOnForeground() {ActivityManager activityManager = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);String packageName = getApplicationContext().getPackageName();List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();if (appProcesses == null)return false;for (RunningAppProcessInfo appProcess : appProcesses) {if (appProcess.processName.equals(packageName) && appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {return true;}}return false;}}

demo下载地址:http://download.csdn.net/detail/u011566000/8391257

软件九宫格解锁之逻辑以及界面控制相关推荐

  1. 9宫格解锁 android_Android实现九宫格解锁的实例代码

    当年感觉九宫格解锁很是高大上,一脸懵逼,今天正好要做解锁这一块业务,回头来看九宫格,这特么简单啊 首先理清一下逻辑,我们要做NxN的九宫格 下图是3x3的简单图例 // -(--)-(--)-(--) ...

  2. Unity3d 修改编辑界面控制图标大小 修改相机图标显示大小

    在 Unity3d 会显示一些控制图标,如相机图标和光照图标.而在编辑界面我发现这些图标太大了,影响我编辑,可以通过界面控制修改图标显示大小 在用户端玩游戏的小伙伴是看不到编辑端的控制图标的,但是在开 ...

  3. Android九宫格解锁

    当年感觉九宫格解锁很是高大上,一脸懵逼,今天正好要做解锁这一块业务,回头来看九宫格,这特么简单啊 首先理清一下逻辑,我们要做NxN的九宫格 下图是3x3的简单图例 // -(–)-(–)-(–)- / ...

  4. 逻辑人渴望控制那些让他们感兴趣的东西

    逻辑人渴望控制那些让他们感兴趣的东西,而那些让他们感兴趣的都是些复杂的确定性系统.人是复杂的,但他们不像机器,他们的行为不具有逻辑性和可预见性.最好的机器是数字的,因为这样它就能变得最为复杂.精细,并 ...

  5. 九宫格解锁的完全实现

    前言 不记得在使用诺基亚的那些日子,为了一个九宫格解锁,在应用商城里下了多少流氓软件.最后无功而返的时候,那种郁闷的心情恨不得把手机给砸了!不得不承认,九宫格解锁的一时风靡,以致于Android阵营的 ...

  6. android 锁屏显示音乐播放器,Android锁屏界面控制音乐播放

    目前,在锁屏界面控制音乐播放有两种常用方式. 第一种方式:原生Android系统及自带音乐播放器. 锁屏界面端: 原生Android中,锁屏界面相关的UI由KeyguardHostView提供,Key ...

  7. 大疆睿炽Tello EDU无人机python操控之三——使用easyGUI模拟操控界面控制Tello EDU

    使用easyGUI模拟操控界面控制Tello EDU 说到easyGUI这个模块,大家应该都不陌生了,模块名中有个"easy",是的,这代表它用起来很简单:这个模块就是一个能够轻易 ...

  8. Android11 九宫格解锁流程

    在我们分析完锁屏的一整个显示流程后,我们接着来分析一下上滑解锁的流程. 流程 首先,我们手指在锁屏界面上滑将会调用StatusBar中的onTrackingStopped方法 public void ...

  9. Android之手势登陆(九宫格解锁)

    前言 上一篇我们介绍了Fragment的使用<Android碎片化布局fragment的实战应用>,其中在登陆的时候会有账号登陆和手势登陆,今天我们就来介绍一下手势登陆的使用,其实这个在网 ...

最新文章

  1. 腾讯云 短信服务 【学习记录 】
  2. python可以干什么工作-python到底能做什么
  3. flex 读取外部txt文件时候出现中文乱码现象
  4. 计算机应用与技术网上测试题答案,计算机应用与技术网上测试题.doc
  5. Boost:bind绑定visit测试程序
  6. Android开发--源码学习
  7. oracle游标多线程,多线程jdbc游标分页查询原理 oracle和mysql分页
  8. 技术沙龙 | 深度赋能AI全场景,揭秘你不知道的移动云
  9. html查看器缩字数,在线字数统计工具-统计字符字节汉字数字标点符号-计算word文章字数-使用帮助-字的区别...
  10. 求1000以内的素数c语言5个一行,求1000以内的素数用C语言 ,并按每行5个的方式输出...
  11. [R] R语言删除字符串中的空值““
  12. 数据结构的形式定义、数据的逻辑结构、数据的存储结构
  13. Python基础学习笔记【廖雪峰】
  14. Variance Reduction Methods: a Quick Introduction to Quasi Monte Carlo——完结
  15. 小程序、APP Store 需要的 SSL 证书是个什么东西?
  16. JavaScript如何查找和访问HTML页面中的HTML元素
  17. Google缩进40%搜索结果,微信公众号/今日头条开放搜索引擎
  18. 逆---LanSet.exe
  19. steam有什么适合程序员玩的游戏
  20. STC8H1K08 - 掉电模式

热门文章

  1. 微信小程序自学(五)-- 基础能力
  2. Opencv学习笔记 - 使用opencvsharp和期望最大化
  3. 如何在SQL Server 2005 中存储立方米
  4. php 对象的操作符,php面向对象之操作符'::'的用法简述
  5. Udig开发环境搭建/入门教程
  6. w计算机二级word单选题,2017全国计算机二级MS-Office选择题题库大全.pdf
  7. 针对 this()方法的找错题
  8. 说说摩拜单车的骑后感
  9. 程序员玩跨界,路子有多野?网友:太疯狂!
  10. 7.Hystrix断路器