热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

android九宫格滑动解锁开机实例源码学习

开机密码的样式种类多种多样,五花八门.本文接下来介绍滑动九宫格来达到开机目的,感兴趣的朋友可以了解下
效果图由于网站占时不能上传,以后补上。
NinePointLineView.java
代码如下:

package org.demo.custon_view;
import org.demo.utils.MLog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class NinePointLineView extends View {
Paint linePaint = new Paint();
Paint whiteLinePaint = new Paint();
Paint textPaint = new Paint();
// 由于两个图片都是正方形,所以获取一个长度就行了
Bitmap defaultBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.lock);
int defaultBitmapRadius = defaultBitmap.getWidth() / 2;
// 初始化被选中图片的直径、半径
Bitmap selectedBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.indicator_lock_area);
int selectedBitmapDiameter = selectedBitmap.getWidth();
int selectedBitmapRadius = selectedBitmapDiameter / 2;
// 定义好9个点的数组
PointInfo[] points = new PointInfo[9];
// 相应ACTION_DOWN的那个点
PointInfo startPoint = null;
// 屏幕的宽高
int width, height;
// 当ACTION_MOVE时获取的X,Y坐标
int moveX, moveY;
// 是否发生ACTION_UP
boolean isUp = false;
// 最终生成的用户锁序列
StringBuffer lockString = new StringBuffer();
public NinePointLineView(Context context) {
super(context);
this.setBackgroundColor(Color.WHITE);
initPaint();
}
public NinePointLineView(Context context, AttributeSet attrs) {
super(context, attrs);
this.setBackgroundColor(Color.WHITE);
initPaint();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
MLog.i("onMeasure");
// 初始化屏幕大小
width = getWidth();
height = getHeight();
if (width != 0 && height != 0) {
initPoints(points);
}
MLog.i("width、height = " + width + "、" + height);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
MLog.i("onLayout");
super.onLayout(changed, left, top, right, bottom);
}
private int startX = 0, startY = 0;
@Override
protected void onDraw(Canvas canvas) {
canvas.drawText("用户的滑动顺序:" + lockString, 0, 40, textPaint);
if (moveX != 0 && moveY != 0 && startX != 0 && startY != 0) {
// 绘制当前活动的线段
drawLine(canvas, startX, startY, moveX, moveY);
}
drawNinePoint(canvas);
super.onDraw(canvas);
}
// 记住,这个DOWN和MOVE、UP是成对的,如果没从UP释放,就不会再获得DOWN;
// 而获得DOWN时,一定要确认消费该事件,否则MOVE和UP不会被这个View的onTouchEvent接收
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean flag = true;
if (isUp) {// 如果已滑完,重置每个点的属性和lockString
finishDraw();
// 当UP后,要返回false,把事件释放给系统,否则无法获得Down事件
flag = false;
} else {// 没滑完,则继续绘制
handlingEvent(event);
// 这里要返回true,代表该View消耗此事件,否则不会收到MOVE和UP事件
flag = true;
}
return flag;
}
private void handlingEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
moveX = (int) event.getX();
moveY = (int) event.getY();
MLog.i("onMove:" + moveX + "、" + moveY);
for (PointInfo temp : points) {
if (temp.isInMyPlace(moveX, moveY) && temp.isNotSelected()) {
temp.setSelected(true);
startX = temp.getCenterX();
startY = temp.getCenterY();
int len = lockString.length();
if (len != 0) {
int preId = lockString.charAt(len - 1) - 48;
points[preId].setNextId(temp.getId());
}
lockString.append(temp.getId());
break;
}
}
invalidate(0, height - width, width, height);
break;
case MotionEvent.ACTION_DOWN:
int downX = (int) event.getX();
int downY = (int) event.getY();
MLog.i("onDown:" + downX + "、" + downY);
for (PointInfo temp : points) {
if (temp.isInMyPlace(downX, downY)) {
temp.setSelected(true);
startPoint = temp;
startX = temp.getCenterX();
startY = temp.getCenterY();
lockString.append(temp.getId());
break;
}
}
invalidate(0, height - width, width, height);
break;
case MotionEvent.ACTION_UP:
MLog.i("onUp");
startX = startY = moveX = moveY = 0;
isUp = true;
invalidate();
break;
default:
MLog.i("收到其他事件!!");
break;
}
}
private void finishDraw() {
for (PointInfo temp : points) {
temp.setSelected(false);
temp.setNextId(temp.getId());
}
lockString.delete(0, lockString.length());
isUp = false;
invalidate();
}
private void initPoints(PointInfo[] points) {
int len = points.length;
int seletedSpacing = (width - selectedBitmapDiameter * 3) / 4;
// 被选择时显示图片的左上角坐标
int seletedX = seletedSpacing;
int seletedY = height - width + seletedSpacing;
// 没被选时图片的左上角坐标
int defaultX = seletedX + selectedBitmapRadius - defaultBitmapRadius;
int defaultY = seletedY + selectedBitmapRadius - defaultBitmapRadius;
// 绘制好每个点
for (int i = 0; i if (i == 3 || i == 6) {
seletedX = seletedSpacing;
seletedY += selectedBitmapDiameter + seletedSpacing;
defaultX = seletedX + selectedBitmapRadius
- defaultBitmapRadius;
defaultY += selectedBitmapDiameter + seletedSpacing;
}
points[i] = new PointInfo(i, defaultX, defaultY, seletedX, seletedY);
seletedX += selectedBitmapDiameter + seletedSpacing;
defaultX += selectedBitmapDiameter + seletedSpacing;
}
}
private void initPaint() {
initLinePaint(linePaint);
initTextPaint(textPaint);
initWhiteLinePaint(whiteLinePaint);
}
/**
* 初始化文本画笔
* @param paint
*/
private void initTextPaint(Paint paint) {
textPaint.setTextSize(30);
textPaint.setAntiAlias(true);
textPaint.setTypeface(Typeface.MONOSPACE);
}
/**
* 初始化黑线画笔
*
* @param paint
*/
private void initLinePaint(Paint paint) {
paint.setColor(Color.GRAY);
paint.setStrokeWidth(defaultBitmap.getWidth());
paint.setAntiAlias(true);
paint.setStrokeCap(Cap.ROUND);
}
/**
* 初始化白线画笔
*
* @param paint
*/
private void initWhiteLinePaint(Paint paint) {
paint.setColor(Color.WHITE);
paint.setStrokeWidth(defaultBitmap.getWidth() - 5);
paint.setAntiAlias(true);
paint.setStrokeCap(Cap.ROUND);
}
/**
* 绘制已完成的部分
*
* @param canvas
*/
private void drawNinePoint(Canvas canvas) {
if (startPoint != null) {
drawEachLine(canvas, startPoint);
}
// 绘制每个点的图片
for (PointInfo pointInfo : points) {
if (pointInfo.isSelected()) {// 绘制大圈
canvas.drawBitmap(selectedBitmap, pointInfo.getSeletedX(),
pointInfo.getSeletedY(), null);
}
// 绘制点
canvas.drawBitmap(defaultBitmap, pointInfo.getDefaultX(),
pointInfo.getDefaultY(), null);
}
}
/**
* 递归绘制每两个点之间的线段
*
* @param canvas
* @param point
*/
private void drawEachLine(Canvas canvas, PointInfo point) {
if (point.hasNextId()) {
int n = point.getNextId();
drawLine(canvas, point.getCenterX(), point.getCenterY(),
points[n].getCenterX(), points[n].getCenterY());
// 递归
drawEachLine(canvas, points[n]);
}
}
/**
* 先绘制黑线,再在上面绘制白线,达到黑边白线的效果
*
* @param canvas
* @param startX
* @param startY
* @param stopX
* @param stopY
*/
private void drawLine(Canvas canvas, float startX, float startY,
float stopX, float stopY) {
canvas.drawLine(startX, startY, stopX, stopY, linePaint);
canvas.drawLine(startX, startY, stopX, stopY, whiteLinePaint);
}
/**
* 用来表示一个点
*
* @author zkwlx
*
*/
private class PointInfo {
// 一个点的ID
private int id;
// 当前点所指向的下一个点的ID,当没有时为自己ID
private int nextId;
// 是否被选中
private boolean selected;
// 默认时图片的左上角X坐标
private int defaultX;
// 默认时图片的左上角Y坐标
private int defaultY;
// 被选中时图片的左上角X坐标
private int seletedX;
// 被选中时图片的左上角Y坐标
private int seletedY;
public PointInfo(int id, int defaultX, int defaultY, int seletedX,
int seletedY) {
this.id = id;
this.nextId = id;
this.defaultX = defaultX;
this.defaultY = defaultY;
this.seletedX = seletedX;
this.seletedY = seletedY;
}
public boolean isSelected() {
return selected;
}
public boolean isNotSelected() {
return !isSelected();
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public int getId() {
return id;
}
public int getDefaultX() {
return defaultX;
}
public int getDefaultY() {
return defaultY;
}
public int getSeletedX() {
return seletedX;
}
public int getSeletedY() {
return seletedY;
}
public int getCenterX() {
return seletedX + selectedBitmapRadius;
}
public int getCenterY() {
return seletedY + selectedBitmapRadius;
}
public boolean hasNextId() {
return nextId != id;
}
public int getNextId() {
return nextId;
}
public void setNextId(int nextId) {
this.nextId = nextId;
}
/**
* 坐标(x,y)是否在当前点的范围内
*
* @param x
* @param y
* @return
*/
public boolean isInMyPlace(int x, int y) {
boolean inX = x > seletedX
&& x <(seletedX + selectedBitmapDiameter);
boolean inY = y > seletedY
&& y <(seletedY + selectedBitmapDiameter);
return (inX && inY);
}
}
}

NinePointView.java
代码如下:

package org.demo.custon_view;
import org.demo.utils.MLog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Path;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class NinePointView extends View {
Paint linePaint = new Paint();
Paint textPaint = new Paint();
Path path = new Path();
// 由于两个图片都是正方形,所以获取一个长度就行了
Bitmap defaultBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.lock);
int defaultBitmapRadius = defaultBitmap.getWidth() / 2;
// 初始化被选中图片的直径、半径
Bitmap selectedBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.indicator_lock_area);
int selectedBitmapDiameter = selectedBitmap.getWidth();
int selectedBitmapRadius = selectedBitmapDiameter / 2;
// 初始化指示器的图片
Bitmap indicateBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.indicator_lock_area_next);
Bitmap tempBitmap = null;
// 定义好9个点的数组
PointInfo[] points = new PointInfo[9];
// 屏幕的宽高
int width, height;
// 当ACTION_MOVE时获取的X,Y坐标
int moveX, moveY;
// 是否发生ACTION_UP
boolean isUp = false;
// 最终生成的用户锁序列
StringBuffer lockString = new StringBuffer();
Matrix matrix = new Matrix();
public NinePointView(Context context) {
super(context);
this.setBackgroundColor(Color.WHITE);
initLinePaint(linePaint);
initTextPaint(textPaint);
}
public NinePointView(Context context, AttributeSet attrs) {
super(context, attrs);
this.setBackgroundColor(Color.WHITE);
initLinePaint(linePaint);
initTextPaint(textPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
MLog.i("onMeasure");
width = getWidth();
height = getHeight();
if (width != 0 && height != 0) {
initPoints(points);
}
MLog.i("width、height = " + width + "、" + height);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
MLog.i("onLayout");
super.onLayout(changed, left, top, right, bottom);
}
private int startX = 0, startY = 0;
@Override
protected void onDraw(Canvas canvas) {
canvas.drawText("用户的滑动顺序:" + lockString, 0, 40, textPaint);
if (moveX != 0 && moveY != 0 && startX != 0 && startY != 0) {
// 绘制当前活动的线段
canvas.drawLine(startX, startY, moveX, moveY, linePaint);
}
drawNinePoint(canvas, linePaint);
super.onDraw(canvas);
}
// 记住,这个DOWN和MOVE、UP是成对的,如果没从UP释放,就不会再获得DOWN;
// 而获得DOWN时,一定要确认消费该事件,否则MOVE和UP不会被这个VIEW的onTouchEvent接收
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean flag = true;
if (isUp) {// 如果已滑完,则把整个Canvas重置
finishDraw();
// 当UP后,要返回false,把事件释放给系统,否则无法获得Down事件
flag = false;
} else {// 没滑完,则继续绘制
handlingEvent(event);
// 这里要返回true,否则代表该View不消耗此事件,交给系统处理,则不会再收到MOVE和UP事件
flag = true;
}
return flag;
}
private void handlingEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
moveX = (int) event.getX();
moveY = (int) event.getY();
MLog.i("onMove:" + moveX + "、" + moveY);
for (PointInfo temp : points) {
if (temp.isInMyPlace(moveX, moveY) && temp.isNotSelected()) {
temp.setSelected(true);
startX = temp.getCenterX();
startY = temp.getCenterY();
int len = lockString.length();
if (len != 0) {
int preId = lockString.charAt(len - 1) - 48;
points[preId].setNextId(temp.getId());
}
lockString.append(temp.getId());
break;
}
}
invalidate(0, height - width, width, height);
break;
case MotionEvent.ACTION_DOWN:
int downX = (int) event.getX();
int downY = (int) event.getY();
MLog.i("onDown:" + downX + "、" + downY);
for (PointInfo temp : points) {
if (temp.isInMyPlace(downX, downY)) {
temp.setSelected(true);
startX = temp.getCenterX();
startY = temp.getCenterY();
lockString.append(temp.getId());
break;
}
}
invalidate(0, height - width, width, height);
break;
case MotionEvent.ACTION_UP:
MLog.i("onUp");
startX = startY = moveX = moveY = 0;
isUp = true;
invalidate();
break;
default:
MLog.i("收到其他事件!!");
break;
}
}
private void finishDraw() {
for (PointInfo temp : points) {
temp.setSelected(false);
temp.setNextId(temp.getId());
}
lockString.delete(0, lockString.length());
isUp = false;
invalidate();
}
private void initPoints(PointInfo[] points) {
int len = points.length;
int seletedSpacing = (width - selectedBitmapDiameter * 3) / 4;
// 被选择时显示图片的左上角坐标
int seletedX = seletedSpacing;
int seletedY = height - width + seletedSpacing;
// 没被选时图片的左上角坐标
int defaultX = seletedX + selectedBitmapRadius - defaultBitmapRadius;
int defaultY = seletedY + selectedBitmapRadius - defaultBitmapRadius;
for (int i = 0; i if (i == 3 || i == 6) {
seletedX = seletedSpacing;
seletedY += selectedBitmapDiameter + seletedSpacing;
defaultX = seletedX + selectedBitmapRadius
- defaultBitmapRadius;
defaultY += selectedBitmapDiameter + seletedSpacing;
}
points[i] = new PointInfo(i, defaultX, defaultY, seletedX, seletedY);
seletedX += selectedBitmapDiameter + seletedSpacing;
defaultX += selectedBitmapDiameter + seletedSpacing;
}
}
private void initTextPaint(Paint paint) {
textPaint.setTextSize(30);
textPaint.setAntiAlias(true);
textPaint.setTypeface(Typeface.MONOSPACE);
}
/**
* 初始化线画笔
*
* @param paint
*/
private void initLinePaint(Paint paint) {
paint.setColor(Color.GRAY);
paint.setStrokeWidth(defaultBitmap.getWidth());
paint.setAntiAlias(true);
paint.setStrokeCap(Cap.ROUND);
}
/**
* 绘制已完成的部分
*
* @param canvas
*/
private void drawNinePoint(Canvas canvas, Paint paint) {
// 先把用户画出的线绘制好
for (PointInfo pointInfo : points) {
if (pointInfo.hasNextId()) {
int n = pointInfo.getNextId();
canvas.drawLine(pointInfo.getCenterX(), pointInfo.getCenterY(),
points[n].getCenterX(), points[n].getCenterY(), paint);
}
}
// 绘制每个点的图片
for (PointInfo pointInfo : points) {
if (pointInfo.isSelected()) {
if (pointInfo.hasNextId()) {
matrix.reset();
int i = (int) Math.abs(Math.random() * 1000 - 640);
MLog.i("随机到的角度:" + i);
matrix.setRotate(i);
tempBitmap = Bitmap.createBitmap(indicateBitmap, 0, 0,
indicateBitmap.getWidth(),
indicateBitmap.getHeight(), matrix, false);
canvas.drawBitmap(tempBitmap, pointInfo.getSeletedX(),
pointInfo.getSeletedY(), paint);
} else {
canvas.drawBitmap(selectedBitmap, pointInfo.getSeletedX(),
pointInfo.getSeletedY(), paint);
}
}
canvas.drawBitmap(defaultBitmap, pointInfo.getDefaultX(),
pointInfo.getDefaultY(), paint);
}
}
private class PointInfo {
// 一个点的ID
private int id;
// 当前点所指向的下一个点的ID,当没有时为自己ID
private int nextId;
// 是否被选中
private boolean selected;
// 默认时图片的左上角X坐标
private int defaultX;
// 默认时图片的左上角Y坐标
private int defaultY;
// 被选中时图片的左上角X坐标
private int seletedX;
// 被选中时图片的左上角Y坐标
private int seletedY;
public PointInfo(int id, int defaultX, int defaultY, int seletedX,
int seletedY) {
this.id = id;
this.nextId = id;
this.defaultX = defaultX;
this.defaultY = defaultY;
this.seletedX = seletedX;
this.seletedY = seletedY;
}
public boolean isSelected() {
return selected;
}
public boolean isNotSelected() {
return !isSelected();
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public int getId() {
return id;
}
public int getDefaultX() {
return defaultX;
}
public int getDefaultY() {
return defaultY;
}
public int getSeletedX() {
return seletedX;
}
public int getSeletedY() {
return seletedY;
}
public int getCenterX() {
return seletedX + selectedBitmapRadius;
}
public int getCenterY() {
return seletedY + selectedBitmapRadius;
}
public boolean hasNextId() {
return nextId != id;
}
public int getNextId() {
return nextId;
}
public void setNextId(int nextId) {
this.nextId = nextId;
}
/**
* 坐标(x,y)是否在当前点的范围内
*
* @param x
* @param y
* @return
*/
public boolean isInMyPlace(int x, int y) {
boolean inX = x > seletedX
&& x <(seletedX + selectedBitmapDiameter);
boolean inY = y > seletedY
&& y <(seletedY + selectedBitmapDiameter);
if (inX && inY) {
return true;
} else {
return false;
}
}
}
}

推荐阅读
  • 猫猫分享,必须精品原文地址:http:blog.csdn.netu013357243articledetails44571163素材地址:http:download.csdn.n ... [详细]
  • Android性能优化检测App卡顿
    在移动APP性能评测-流畅度评测中,我们介绍了如何准确客观评价APP的流畅度,最终采用SM指标来评价应用的流畅度,在知道如何评价流畅度之后 ... [详细]
  • 这一篇主要总结一下jQuery这个js在引入的时候做的一些初始化工作第一句window.undefinedwindow.undefined;是为了兼容低版本的IE而写的因为在低版本 ... [详细]
  • spotify engineering culture part 1
    原文,因为原视频说的太快太长,又没有字幕,于是借助youtube,把原文听&打出来了。中文版日后有时间再翻译。oneofthebigsucceessfactorshereatSpo ... [详细]
  • MyBatis模糊查询和多条件查询一、ISmbmsUserDao层根据姓名模糊查询publicListgetUser();多条件查询publicList ... [详细]
  • 载波|等份_NR SRS时频域位置
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了NRSRS时频域位置相关的知识,希望对你有一定的参考价值。微信同步更新欢迎关注同名modem协议笔记S ... [详细]
  • Mac下Flutter安装AndroidStudio配置
    补一个Mac下Flutter安装AndroidStudio配置(官网地址:https:flutter.devdocsget-startedinstallmacos)1.下载安装包; ... [详细]
  • vscode里的html标签导航的一系列问题
    哈喽,我今天带来的经验是,vscode在18年10月更新后的1.29以后,编辑html文档时,会发现最上面有个类似于HTML标签导航的玩意儿,可能部分同学和我一样不习惯用它们,现在 ... [详细]
  • Android Rxbus事件总线
    我的视频课程:《FFmpeg打造Android万能音频播放器》最近在项目中使用了Rxjava和RxAndroid,确实感觉挺不错的,然后听说可以用RxBus来替换 ... [详细]
  • Illustrator绘制逼真的愤怒的小鸟实例教程
    Illustrator教程: ... [详细]
  • Android 自定义控件基础 canvas paint
    1、首先说一下canvas类:ClassOverviewTheCanvasclassholdsthedrawcalls.Todrawsomething,youne ... [详细]
  • 抓取百万知乎用户设计之实体设计
    一.实体的关系实体是根据返回的Json数据来设计的教育经历方面用户可以有很多教育经理,USER和education是一对多的关系,一个education对应一个education一 ... [详细]
  • iOS之富文本
    之前做项目时遇到一个问题:使用UITextView显示一段电影的简介,由于字数比较多,所以字体设置的很小,行间距和段间距也很小,一大段文字挤在一起看起来很别扭,想要把行间距调大,结 ... [详细]
  • Xib九宫格应用管理使用xib封装一个自定义view的步骤1新建一个继承UIView的自定义view,假设类名叫做(AppView)2新建一个AppView.xib文件来描述 ... [详细]
  • 【自制小工具】代码生成器
    【自制小工具】代码生成器陆陆续续接触过好几款代码生成工具,发现确实好用,但都会有那么点不完善的地方,所以索性就自己做一个吧。界面非常简单,反正是自己用的,简单点用起来也方便上图:左 ... [详细]
author-avatar
懒懒加菲猫爱小狐狸
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有