我们经常会在app中看到图案解锁的功能,所以寻思做一个,在某客视频上看到了教程,自己跟着做了一遍,记录一下,顺便理清一下思路。
首先自定义一个图案的view,其中实现onDraw方法,以及添加接口回调进行验证密码正确性。
自定义view效果如下:
首先新建一个记录点的坐标的一个bean
public class Point {
//表示图案状态
public static int STATE_NORMAL=0;
public static int STATE_PRESS=1;
public static int STATE_ERROR=2;
//坐标
float x,y;
int state=STATE_NORMAL;
public Point(float x, float y) {
this.x = x;
this.y = y;
}
//判断按下屏幕的点是否在某一个圆圈的区域内
public float distance(Point a)
{
float distance= (float) Math.sqrt((x-a.x)*(x-a.x)+(y-a.y)*(y-a.y));
return distance;
}
}
下面是自定义view代码:
public class GestureLockView extends View {
//三张不同状态圆的图片
private Bitmap error,normal,press;
//
private ArrayList pointlist=new ArrayList<>();
//设置圆的坐标位置的数组
private Point[][] points=new Point[3][3];
//画圆的画笔(后面的参数为抗锯齿的作用)
private Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);
//设置回调监听事件
private OnDrawFinsihListner listner;
//保存圆的半径
private float radius;
public GestureLockView(Context context) {
super(context);
}
public GestureLockView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public GestureLockView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//判断是否初始化
private boolean inited=false;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//ondraw方法会多次调用所以要设置标记位判断是否调用过
if (!inited){
init();
}
//画图
drawPoints(canvas);
//画线
if (pointlist.size()>0)
{ //冲重第一个点画起
Point a=pointlist.get(0);
for (int i=1;iif (isDraw)
{
drawLine(canvas,a,new Point(mouseX,mouseY));
}
}
}
//绘制圆圈背景图案
private void drawPoints(Canvas canvas){
for (int i=0;ifor (int j=0;jif (points[i][j].state==Point.STATE_NORMAL)
{
//正常状态
canvas.drawBitmap(normal,points[i][j].x-radius,points[i][j].y-radius,paint);
}
else if (points[i][j].state==Point.STATE_PRESS)
{
//按下状态
canvas.drawBitmap(press,points[i][j].x-radius,points[i][j].y-radius,paint);
}else
{
//错误状态
canvas.drawBitmap(error,points[i][j].x-radius,points[i][j].y-radius,paint);
}
}
}
}
//初始化
private void init(){
pressPaint.setColor(Color.BLUE);
//画笔宽度
pressPaint.setStrokeWidth(5);
errorPaint.setColor(Color.RED);
errorPaint.setStrokeWidth(5);
//获取图片
error= BitmapFactory.decodeResource(getResources(),R.drawable.error);
press=BitmapFactory.decodeResource(getResources(),R.drawable.press);
normal=BitmapFactory.decodeResource(getResources(),R.drawable.normal);
radius=error.getHeight()/2;
int width=getWidth();
Log.e("width",width+"");
int height=getHeight();
Log.e("height",height+"");
//显示位置的偏移量
int offset=Math.abs(width-height)/2;
//图案偏移量
int offsetX,offsetY;
//小方格偏移量
int space;
//判断横屏还是竖屏
if (width>height){
offsetX=offset;
offsetY=0;
space=height/4;
}
else {
space=width/4;
offsetX=0;
offsetY=offset;
}
//绘制圆圈
for (int i=0;i<3;i++)
{
for (int j=0;j<3;j++){
points[i][j]=new Point(offsetX+space*(j+1),offsetY+space*(i+1));
}
}
inited=true;
}
//获取触摸的点
private float mouseX,mouseY;
//是否在绘制状态
private boolean isDraw=false;
//触摸事件
@Override
public boolean onTouchEvent(MotionEvent event)
{
//得到按下坐标
mouseX=event.getX();
mouseY=event.getY();
int[] ij;
int i,j;
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
//清空绘制过程
resetPoint();
ij=getSelectionPoint();
if (ij!=null)
{
isDraw=true;
i=ij[0];
j=ij[1];
points[i][j].state=Point.STATE_PRESS;
pointlist.add(points[i][j]);
passlist.add(i*3+j);
}
break;
case MotionEvent.ACTION_MOVE:
if (isDraw)
{
ij=getSelectionPoint();
if (ij!=null)
{
i=ij[0];
j=ij[1];
if (!pointlist.contains(points[i][j]))
{
points[i][j].state=Point.STATE_PRESS;
pointlist.add(points[i][j]);
passlist.add(i*3+j);
}
}
}
break;
case MotionEvent.ACTION_UP:
boolean valid=false;
if (listner!=null&&isDraw)
{
valid=listner.OnDrawFinished(passlist);
}
if (!valid)
{
for (Point point:pointlist)
point.state=Point.STATE_ERROR;
}
isDraw=false;
break;
}
this.postInvalidate();
return true;
}
//当手指按下,判断属于那个圆圈
private int[] getSelectionPoint()
{
Point pMouse=new Point(mouseX,mouseY);
for (int i=0;ifor (int j=0;jif (points[i][j].distance(pMouse)int[] result=new int[2];
result[0]=i;
result[1]=j;
return result;
}
}
}
return null;
}
private Paint errorPaint=new Paint();
private Paint pressPaint=new Paint();
private void drawLine(Canvas canvas,Point a,Point b)
{
if (a.state==Point.STATE_PRESS)
{
canvas.drawLine(a.x,a.y,b.x,b.y,pressPaint);
}
else if (a.state==Point.STATE_ERROR){
canvas.drawLine(a.x,a.y,b.x,b.y,errorPaint);
}
}
public void resetPoint(){
pointlist.clear();
passlist.clear();
for (int i=0;ifor (int k=0;kthis.postInvalidate();
}
private ArrayList passlist=new ArrayList<>();
public interface OnDrawFinsihListner
{
boolean OnDrawFinished(List passlist);
}
public void setOnDrawFinishedListener(OnDrawFinsihListner listener)
{
this.listner=listener;
}
}
主页面布局:
<LinearLayout 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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="设置图案密码"
android:id="@+id/button"
android:layout_gravity="center_horizontal" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试图案密码"
android:id="@+id/button2"
android:layout_gravity="center_horizontal" />
LinearLayout>
主页面代码:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SettingAct.class);
startActivity(intent);
}
});
findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(MainActivity.this,LockAct.class);
startActivity(intent);
}
});
}
}
设置页面代码:
public class SettingAct extends AppCompatActivity {
private GestureLockView lockView;
private List passlist;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setting);
lockView= (GestureLockView) findViewById(R.id.view);
findViewById(R.id.btn_reset).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
lockView.resetPoint();
}
});
findViewById(R.id.btn_save).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (passlist!=null)
{
StringBuilder sb=new StringBuilder();
for (Integer i:passlist)
{
sb.append(i);
}
SharedPreferences sharedPreferences=SettingAct.this.getSharedPreferences("password", Context.MODE_PRIVATE);
SharedPreferences.Editor editor=sharedPreferences.edit();
editor.putString("password", sb.toString());
editor.commit();
Toast.makeText(SettingAct.this,"保存完成",Toast.LENGTH_SHORT).show();
Intent intent=new Intent(SettingAct.this,MainActivity.class);
startActivity(intent);
}
}
});
lockView.setOnDrawFinishedListener(new GestureLockView.OnDrawFinsihListner() {
@Override
public boolean OnDrawFinished(List passlist) {
if (passlist.size()<3)
{
Toast.makeText(SettingAct.this,"密码不能小于三个点",Toast.LENGTH_SHORT).show();
return false;
}else
{
SettingAct.this.passlist=passlist;
return true;
}
}
});
}
}
测试页面代码:
public class LockAct extends AppCompatActivity {
private String passwaord;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lock);
GestureLockView gestureLockView= (GestureLockView) findViewById(R.id.view2);
SharedPreferences sharedPreferences=getSharedPreferences("password", Context.MODE_PRIVATE);
passwaord =sharedPreferences.getString("password","");
Log.e("password",passwaord);
gestureLockView.setOnDrawFinishedListener(new GestureLockView.OnDrawFinsihListner() {
@Override
public boolean OnDrawFinished(List passlist) {
StringBuilder stringBuilder=new StringBuilder();
for (Integer i:passlist)
{
stringBuilder.append(i);
}
Log.e("sb",stringBuilder.toString());
if (stringBuilder.toString().equals(passwaord))
{
Toast.makeText(LockAct.this, "密码正确", Toast.LENGTH_SHORT).show();
return true;
}
else
{
Toast.makeText(LockAct.this, "密码错误", Toast.LENGTH_SHORT).show();
return false;
}
}
});
}
}