慕课网图形锁学习笔记

程序结构:


代码:

MainActivity.java

package com.lw.patternlock;

import com.lw.patternlock.LockPatternView.Point.OnPatternChangeListener;

import android.app.Activity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements OnPatternChangeListener{

	private LockPatternView lockPatternView  = null;
	
	private TextView title = null;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		this.title = (TextView) super.findViewById(R.id.title);
		this.lockPatternView = (LockPatternView) super.findViewById(R.id.patternView);
		this.lockPatternView.setPatternChangeListener(this);
	}
	@Override
	public void onPatternChange(String passwordStr) {
		// TODO Auto-generated method stub
		if(TextUtils.isEmpty(passwordStr))
		{
			this.title.setText("图案绘制失败");
			this.lockPatternView.reset();
		}
		else
		{
			this.title.setText("密码为:"+passwordStr);
		}
	}
	@Override
	public void onPatternStart(boolean isStart) {
		// TODO Auto-generated method stub
		if(isStart)
		{
			this.title.setText("绘制图形锁");
		}
	}
	
}

LockPatternView.java

package com.lw.patternlock;

import java.util.ArrayList;
import java.util.List;

import com.lw.patternlock.LockPatternView.Point.OnPatternChangeListener;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class LockPatternView extends View {
	
	private Matrix matrix = new Matrix();//用于设置线条的缩放
	private static final int POINTSIZE = 4;//设置构成一个锁的点的数量
	private Point[][] points = new Point[3][3];//9个点的
	private List<Point> pointList = new ArrayList<Point>();//用于放置连接的点
	private int width = 0,height = 0;//屏幕的宽高
	private float movingX,movingY;//触屏时移动的X,Y坐标,用于判断是否在点上
	private float offsetsX = 0,offsetsY = 0;//偏移量
	private int bitmapR ;//这是图片资源的半径,此处是由于画笔绘制时是在这个点处开始的,所以绘制的偏移度太多 
	private boolean isInit = false;//表明是否初始化点了
	private boolean isSelect,isFinish ;//这是表明是否开始选中点,然后连线结束
	private boolean movingNoPoint ;//判断是否不是重复点
	
	private Bitmap PointsNormal,PointsError,PointsPressed,lineError,linePressed;
	private Paint paint = null;//创建的画笔用于绘画
	
	private OnPatternChangeListener onPatternListener;//监听密码的监听器
	
	
	public LockPatternView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}
	public LockPatternView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		// TODO Auto-generated constructor stub
	}
	
	/**
	 * 重写这个方法,是用与绘制点的
	 */
	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		if(!isInit)//没有初始化点时
		{
			initPoints();
		}
		//画点
		this.Points2Canvas(canvas);
		//画线
		if(this.pointList.size()>0)
		{
			
			Point a = this.pointList.get(0);
			//画图形锁的线
			for(int i=0;i<this.pointList.size();i++)
			{
				Point b = this.pointList.get(i);
				this.line2Canvas(canvas, a, b);
				//a点变为b点是为了下一个连接的点可以成为b点,然后开始可以连线
				a = b;
			}
			//画鼠标的线
			if(this.movingNoPoint)
			{
				this.line2Canvas(canvas, a, new Point(this.movingX,this.movingY));
			}
		}
	}
	/**
	 * 重写touch事件来设置触屏时点和线的情况
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		this.movingNoPoint = false;
		this.movingX = event.getX();
		this.movingY = event.getY();
		this.isFinish = false;
		Point point = null;
		switch(event.getAction())
		{
		case MotionEvent.ACTION_DOWN://触屏时
			if(this.onPatternListener!=null)
			{
				this.onPatternListener.onPatternStart(true);
			}
			this.reset();//清空List中保存的点
			point = this.checkPoint();
			if(point!=null)
			{
				this.isSelect = true;
			}
			break;
		case MotionEvent.ACTION_MOVE://触屏移动时
			if(this.isSelect)
			{
				point = this.checkPoint();
				if(point==null)
				{
					this.movingNoPoint = true;
				}
			}
			break;
		case MotionEvent.ACTION_UP://松开时
			this.isFinish = true;
			this.isSelect = false;
			break;
		}
		//点还在连线当中,判断是否连接的点重复了
		if(this.isSelect&&!this.isFinish&&point!=null)
		{
			//是一个重复点
			if(this.crossPointCheck(point))
			{
				this.movingNoPoint = true;
			}
			else //是一个新点
			{
				point.state = Point.STATE_PRESSED;
				this.pointList.add(point);
			}
		}
		//点已经连线完毕
		if(isFinish)
		{
			//绘制图形锁不成立
			if(this.pointList.size()==1)
			{
				this.reset();//清空保存的点
			}
			//绘制的点太少,不能成为密码锁
			else if(this.pointList.size()<this.POINTSIZE&&this.pointList.size()>1)
			{
				this.pointError();
				if(this.onPatternListener!=null)
				{
					this.onPatternListener.onPatternChange(null);
				}
			}
			else //绘制成功
			{
				if(this.onPatternListener!=null)
				{
					String passwordStr = "";
					for(int i=0;i<this.pointList.size();i++)
					{
						passwordStr = passwordStr+this.pointList.get(i).index;
					}
					if(!TextUtils.isEmpty(passwordStr))
					{
						this.onPatternListener.onPatternChange(passwordStr);;
					}					
				}
			}
		}
		//调用onDraw(),刷新View
		postInvalidate();
		return true;
	}
	/**
	 * 检查两个以上的点时是否重复连接
	 */
	private boolean crossPointCheck(Point point)
	{
		if(this.pointList.contains(point))
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	/**
	 * 清空选中的点
	 */
	public void reset()
	{
		for(Point point:this.pointList)
		{
			point.state = Point.STATE_NORMAL;
		}
		this.pointList.clear();
	}
	
	/**
	 * 连线的点太少,不能成为一个图形锁
	 */
	private void pointError()
	{
		for(Point point:this.pointList )
		{
			point.state = Point.STATE_ERROR;
		}
	}
	
	/**
	 * 用于检查鼠标的坐标与绘制的点的坐标是否重合
	 */
	private Point checkPoint()
	{
		//因为要判断是否与鼠标的坐标重合,所以只有通过便利所有的点的坐标来判断
		for(int i=0;i<this.points.length;i++)
		{
			for(int j=0;j<this.points[i].length;j++)
			{
				Point point = this.points[i][j];
				boolean withIt = this.with(point.x, point.y,this.bitmapR,this.movingX,this.movingY);
				if(withIt)
				{
					return point;
				}
			}
		}
		return null;
	}
	
	/**
	 * 这个方法是计算鼠标与点的距离是否在一定范围内,如果是则认为是重合
	 */
	private boolean with(float pointx,float pointy,float r,float movingX,float movingY)
	{
		//这里是如果鼠标的坐标距离点的坐标在一定范围内,则认为已经重合了
		boolean withIt = Math.sqrt(Math.pow(pointx-movingX, 2)+Math.pow(pointy-movingY, 2))<r;
		return withIt;
	}
	/**
	 * 画线的方法
	 */
	private void line2Canvas(Canvas canvas,Point a,Point b)
	{
		float degree = this.getDegrees(a, b);
		//旋转画布,以a.x,a.y的坐标为参考点(原点)
		canvas.rotate(degree, a.x, a.y);
		float lineLength = (float) this.distance(a, b);
		if(a.state==Point.STATE_PRESSED)
		{
			//设置线的缩放比率,第一参数是X轴的缩放比率,第二参数是Y轴的
			this.matrix.setScale(lineLength/linePressed.getWidth(),1);
			//对线条进行平移,因为不确定线条是在哪里开始画的
			this.matrix.postTranslate(a.x-this.linePressed.getWidth()/2, a.y-this.linePressed.getHeight()/2);
			//画线
			canvas.drawBitmap(this.linePressed, matrix, paint);
		}
		else//画错误的线
		{
			//设置线的缩放比率,第一参数是X轴的缩放比率,第二参数是Y轴的
			this.matrix.setScale(lineLength/lineError.getWidth(),1);
			//对线条进行平移,因为不确定线条是在哪里开始画的
			this.matrix.postTranslate(a.x-this.lineError.getWidth()/2, a.y-this.lineError.getHeight()/2);
			//画线
			canvas.drawBitmap(this.lineError, matrix, paint);
		}
		//此处是将画布重新转回来,其实我们看的是旋转线条,但实际上是画布在旋转
		canvas.rotate(-degree, a.x, a.y);
	}
	/**
	 * 两点之间的距离
	 */
	public static double distance(Point a,Point b)
	{
		double result = Math.sqrt(Math.pow((a.x-b.x), 2)+Math.pow((a.y-b.y),2));
		return result;
	}
	/**
	 * 计算线旋转的角度
	 */
	public float getDegrees(Point a,Point b)
	{
		float ax = a.x;
		float ay = a.y;
		float bx = b.x;
		float by = b.y;
		float degree = 0;//表示要返回的角度
		if(bx==ax)//表示这两点的连线与Y轴平行
		{
			if(by>ay)//b点在a点的下面,那么两点的连线旋转角度就是90度,手机是顺时针旋转,从X轴到Y轴的旋转
			{
				degree = 90;
			}
			else if(ay>by)//b点在a点上面,那么从a点旋转到b点就要经过270度
			{
				degree = 270;
			}
		}
		else if(by==ay)//两点连线与X轴平行
		{
			if(bx>ax)//b点在a点右边,从a到b点的连线角度为0度
			{
				degree = 0;
			}
			else if(ax>bx)
			{
				degree = 180;
			}
		}
		else 
		{
			degree = (float) Math.toDegrees(Math.atan2(b.y - a.y, b.x - a.x));
		}
		return degree;
	}
	
	/**
	 * 用于绘制图形在画布上的方法
	 * @param canvas
	 */
	private void Points2Canvas(Canvas canvas) {

		this.paint = new Paint();
		//开始绘制点在画布上
		for(int i=0;i<this.points.length;i++)
		{
			for(int j=0;j<this.points[i].length;j++)
			{
				Point point = this.points[i][j];
				if(point.state==Point.STATE_PRESSED)
				{
					canvas.drawBitmap(this.PointsPressed, point.x-this.bitmapR, point.y-this.bitmapR, paint);
				}

				else if(point.state==Point.STATE_NORMAL)
				{
					canvas.drawBitmap(this.PointsNormal,point.x-this.bitmapR, point.y-this.bitmapR, paint);
				}
				else
				{
					canvas.drawBitmap(this.PointsError, point.x-this.bitmapR, point.y-this.bitmapR, paint);
				}
			}
		}
	}
	/**
	 * 用于初始化点的函数
	 */
	private void initPoints() {
		//1.得到屏幕宽高
		this.width = this.getWidth();
		this.height = this.getHeight();
		
		//2. 判断手机是横屏还是竖屏,设置偏移量
		if(this.width>this.height)//横屏
		{
			//因为此时是横屏,所以在X轴上要有偏移量,以便于绘制图形在中心
			//由于Y轴上是平分为四份,(三个点分四份),所以在Y轴上是不需要偏移的
			offsetsX = (this.width-this.height)/2;
			//因为这是图形锁的宽高,而图形锁是一个正方形,但是此时width太大,不能成为正方形
			this.width = this.height ;
		}
		else//竖屏
		{
			offsetsY = (this.height-this.width)/2;
			this.height = this.width;
		}
		//3.加载图片资源
		this.PointsNormal = BitmapFactory.decodeResource(getResources(), R.drawable.point_normal);
		this.PointsPressed = BitmapFactory.decodeResource(getResources(), R.drawable.point_pressed);
		this.PointsError = BitmapFactory.decodeResource(getResources(), R.drawable.point_error);
		
		this.linePressed = BitmapFactory.decodeResource(getResources(), R.drawable.line_pressed);
		this.lineError = BitmapFactory.decodeResource(getResources(), R.drawable.line_error);
		
		//4.创建点
		//第一行
		//此处这里加上width/4是因为如果是竖屏则宽被分成四等份,同样由于图形锁是一个正方形,所以在Y轴上也要加上width/4
		this.points[0][0] = new Point(this.offsetsX+this.width/4,this.offsetsY+this.width/4);
		this.points[0][1] = new Point(this.offsetsX+this.width/2,this.offsetsY+this.width/4);
		this.points[0][2] = new Point(this.offsetsX+this.width*3/4,this.offsetsY+this.width/4);
		//第二行
		this.points[1][0] = new Point(this.offsetsX+this.width/4,this.offsetsY+this.width/2);
		this.points[1][1] = new Point(this.offsetsX+this.width/2,this.offsetsY+this.width/2);
		this.points[1][2] = new Point(this.offsetsX+this.width*3/4,this.offsetsY+this.width/2);
		//第三行
		this.points[2][0] = new Point(this.offsetsX+this.width/4,this.offsetsY+this.width*3/4);
		this.points[2][1] = new Point(this.offsetsX+this.width/2,this.offsetsY+this.width*3/4);
		this.points[2][2] = new Point(this.offsetsX+this.width*3/4,this.offsetsY+this.width*3/4);
		
		//5. 图片资源半径
		this.bitmapR = this.PointsNormal.getWidth()/2;
		
		//6.设置密码,其实就是把point的index初始化,那么我们连接的点在内部表示就是一堆数字,也就是设置的密码
		int index = 1;
		for(Point[] points : this.points)
		{
			for(Point point :points)
			{
				point.index = index;
				index++;
			}
		}
		
		this.isInit = true;
	}

	/**
	 * 自定义的点,用于绘制图形点
	 */
	public static class Point
	{
		//正常状态的点形状,就是用户还没有点击图形锁的时候
		public static int STATE_NORMAL = 0;
		//点击图形锁点的时候,就是开始绘制图形时
		public static int STATE_PRESSED = 1;
		//绘制图形锁错误时
		public static int STATE_ERROR = 2;
		
		//点的坐标
		public float x,y;
		public int index = 0,state = 0;
		
		//CRT
		public Point()
		{}
		
		public Point(float x,float y)
		{
			this.x = x;
			this.y = y;
		}
		
		/***
		 * 图案的监听器,这个其实就是要Activity继承这个接口,然后就可以返回数据到Activity中
		 */
		public static interface OnPatternChangeListener
		{
			/**
			 * 图案改变的方法
			 * @param passwordStr 是图案的密码,这个是图案改变的方法
			 */
			void onPatternChange(String passwordStr);
			/**
			 * 图案开始绘制
			 * @param isStart 表示是否重新开始绘制图案了
			 */
			void onPatternStart(boolean isStart);
		}
		
	}
	
	/**
	 * 设置图案监听器
	 */
	public void setPatternChangeListener(OnPatternChangeListener onPatternListener)
	{
		if(onPatternListener!=null)
		{
			this.onPatternListener = onPatternListener;
		}
	}
}

activity_main.xml

<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" >

    <TextView 
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:text="绘制图形锁"/>
    
    <com.lw.patternlock.LockPatternView
        android:id="@+id/patternView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

代码解释:

首先来看自定义组件的画图代码:(就是画那个图形锁界面)

/**
	 * 用于初始化点的函数
	 */
	private void initPoints() {
		//1.得到屏幕宽高
		this.width = this.getWidth();
		this.height = this.getHeight();
		
		//2. 判断手机是横屏还是竖屏,设置偏移量
		if(this.width>this.height)//横屏
		{
			//因为此时是横屏,所以在X轴上要有偏移量,以便于绘制图形在中心
			//由于Y轴上是平分为四份,(三个点分四份),所以在Y轴上是不需要偏移的
			offsetsX = (this.width-this.height)/2;
			//因为这是图形锁的宽高,而图形锁是一个正方形,但是此时width太大,不能成为正方形
			this.width = this.height ;
		}
		else//竖屏
		{
			offsetsY = (this.height-this.width)/2;
			this.height = this.width;
		}
		//3.加载图片资源
		this.PointsNormal = BitmapFactory.decodeResource(getResources(), R.drawable.point_normal);
		this.PointsPressed = BitmapFactory.decodeResource(getResources(), R.drawable.point_pressed);
		this.PointsError = BitmapFactory.decodeResource(getResources(), R.drawable.point_error);
		
		this.linePressed = BitmapFactory.decodeResource(getResources(), R.drawable.line_pressed);
		this.lineError = BitmapFactory.decodeResource(getResources(), R.drawable.line_error);
		
		//4.创建点
		//第一行
		//此处这里加上width/4是因为如果是竖屏则宽被分成四等份,同样由于图形锁是一个正方形,所以在Y轴上也要加上width/4
		this.points[0][0] = new Point(this.offsetsX+this.width/4,this.offsetsY+this.width/4);
		this.points[0][1] = new Point(this.offsetsX+this.width/2,this.offsetsY+this.width/4);
		this.points[0][2] = new Point(this.offsetsX+this.width*3/4,this.offsetsY+this.width/4);
		//第二行
		this.points[1][0] = new Point(this.offsetsX+this.width/4,this.offsetsY+this.width/2);
		this.points[1][1] = new Point(this.offsetsX+this.width/2,this.offsetsY+this.width/2);
		this.points[1][2] = new Point(this.offsetsX+this.width*3/4,this.offsetsY+this.width/2);
		//第三行
		this.points[2][0] = new Point(this.offsetsX+this.width/4,this.offsetsY+this.width*3/4);
		this.points[2][1] = new Point(this.offsetsX+this.width/2,this.offsetsY+this.width*3/4);
		this.points[2][2] = new Point(this.offsetsX+this.width*3/4,this.offsetsY+this.width*3/4);
		
		//5. 图片资源半径
		this.bitmapR = this.PointsNormal.getWidth()/2;
		
		//6.设置密码,其实就是把point的index初始化,那么我们连接的点在内部表示就是一堆数字,也就是设置的密码
		int index = 1;
		for(Point[] points : this.points)
		{
			for(Point point :points)
			{
				point.index = index;
				index++;
			}
		}
		
		this.isInit = true;
	}

1. 上面这段代码其实就是首先画点的,这些点其实就是一个图片,然后将图片的点绘制出来。

//3.加载图片资源
		this.PointsNormal = BitmapFactory.decodeResource(getResources(), R.drawable.point_normal);
		this.PointsPressed = BitmapFactory.decodeResource(getResources(), R.drawable.point_pressed);
		this.PointsError = BitmapFactory.decodeResource(getResources(), R.drawable.point_error);

这是加载图片资源,这里加载了三张图片资源,是因为首先第一张是正常没有操作图形锁时显示的,第二张是开始连接点时点改变,第三张是绘制的密码错误时的点的样子。

      线有两张图片也是一样的。

2.

//第二行
		this.points[1][0] = new Point(this.offsetsX+this.width/4,this.offsetsY+this.width/2);
		this.points[1][1] = new Point(this.offsetsX+this.width/2,this.offsetsY+this.width/2);
		this.points[1][2] = new Point(this.offsetsX+this.width*3/4,this.offsetsY+this.width/2);

这是得到九个点,这里是第二行的点的初始化,里面的参数是点的位置。至于这些位置的得到offsetsX = (this.width-this.height)/2;就是这些代码,其实这个是偏移量,就是点偏移X轴或者Y轴的位置,那个this.width才是主要的位置参数。

 

3.画点

/**
	 * 用于绘制图形在画布上的方法
	 * @param canvas
	 */
	private void Points2Canvas(Canvas canvas) {

		this.paint = new Paint();
		//开始绘制点在画布上
		for(int i=0;i<this.points.length;i++)
		{
			for(int j=0;j<this.points[i].length;j++)
			{
				Point point = this.points[i][j];
				if(point.state==Point.STATE_PRESSED)
				{
					canvas.drawBitmap(this.PointsPressed, point.x-this.bitmapR, point.y-this.bitmapR, paint);
				}

				else if(point.state==Point.STATE_NORMAL)
				{
					canvas.drawBitmap(this.PointsNormal,point.x-this.bitmapR, point.y-this.bitmapR, paint);
				}
				else
				{
					canvas.drawBitmap(this.PointsError, point.x-this.bitmapR, point.y-this.bitmapR, paint);
				}
			}
		}
	}

这就是画点的方法。

 

4. 那么就是这个onDraw()方法调用画的方法开始画这些东西。

/**
	 * 重写这个方法,是用与绘制点的
	 */
	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		if(!isInit)//没有初始化点时
		{
			initPoints();
		}
		//画点
		this.Points2Canvas(canvas);
		//画线
		if(this.pointList.size()>0)
		{
			
			Point a = this.pointList.get(0);
			//画图形锁的线
			for(int i=0;i<this.pointList.size();i++)
			{
				Point b = this.pointList.get(i);
				this.line2Canvas(canvas, a, b);
				//a点变为b点是为了下一个连接的点可以成为b点,然后开始可以连线
				a = b;
			}
			//画鼠标的线
			if(this.movingNoPoint)
			{
				this.line2Canvas(canvas, a, new Point(this.movingX,this.movingY));
			}
		}
	}

5. 事件设置,这里设置了一个onTouch事件,就是为了用户设置图形密码时的各种操作。里面的各种注释很详细,就不过多的阐述。

/**
	 * 重写touch事件来设置触屏时点和线的情况
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		this.movingNoPoint = false;
		this.movingX = event.getX();
		this.movingY = event.getY();
		this.isFinish = false;
		Point point = null;
		switch(event.getAction())
		{
		case MotionEvent.ACTION_DOWN://触屏时
			if(this.onPatternListener!=null)
			{
				this.onPatternListener.onPatternStart(true);
			}
			this.reset();//清空List中保存的点
			point = this.checkPoint();
			if(point!=null)
			{
				this.isSelect = true;
			}
			break;
		case MotionEvent.ACTION_MOVE://触屏移动时
			if(this.isSelect)
			{
				point = this.checkPoint();
				if(point==null)
				{
					this.movingNoPoint = true;
				}
			}
			break;
		case MotionEvent.ACTION_UP://松开时
			this.isFinish = true;
			this.isSelect = false;
			break;
		}
		//点还在连线当中,判断是否连接的点重复了
		if(this.isSelect&&!this.isFinish&&point!=null)
		{
			//是一个重复点
			if(this.crossPointCheck(point))
			{
				this.movingNoPoint = true;
			}
			else //是一个新点
			{
				point.state = Point.STATE_PRESSED;
				this.pointList.add(point);
			}
		}
		//点已经连线完毕
		if(isFinish)
		{
			//绘制图形锁不成立
			if(this.pointList.size()==1)
			{
				this.reset();//清空保存的点
			}
			//绘制的点太少,不能成为密码锁
			else if(this.pointList.size()<this.POINTSIZE&&this.pointList.size()>1)
			{
				this.pointError();
				if(this.onPatternListener!=null)
				{
					this.onPatternListener.onPatternChange(null);
				}
			}
			else //绘制成功
			{
				if(this.onPatternListener!=null)
				{
					String passwordStr = "";
					for(int i=0;i<this.pointList.size();i++)
					{
						passwordStr = passwordStr+this.pointList.get(i).index;
					}
					if(!TextUtils.isEmpty(passwordStr))
					{
						this.onPatternListener.onPatternChange(passwordStr);;
					}					
				}
			}
		}
		//调用onDraw(),刷新View
		postInvalidate();
		return true;
	}

6.

/***
		 * 图案的监听器,这个其实就是要Activity继承这个接口,然后就可以返回数据到Activity中
		 */
		public static interface OnPatternChangeListener
		{
			/**
			 * 图案改变的方法
			 * @param passwordStr 是图案的密码,这个是图案改变的方法
			 */
			void onPatternChange(String passwordStr);
			/**
			 * 图案开始绘制
			 * @param isStart 表示是否重新开始绘制图案了
			 */
			void onPatternStart(boolean isStart);
		}
		
	}
public class MainActivity extends Activity implements OnPatternChangeListener
@Override
	public void onPatternStart(boolean isStart) {
		// TODO Auto-generated method stub
		if(isStart)
		{
			this.title.setText("绘制图形锁");
		}
	}

可以看到这三个代码,第一个是LockPatternView类中的自定义的监听器接口,

      第二个是表明这个MainActivity继承这个接口

      第三个是MainActivity为这个接口复写的方法

其实这是一种很常见的为Activity传递数据的方式。

 

 

布局上的细节:

      首先看入下代码,对比两段代码会发现,第二段代码中在画时减去了一个点图片的半径,这里入果是第一段代码画出来的效果就是如下图所示,这里画笔开始画时是将点的图片从点的位置开始画的,就是“点”左边的其实是“点”的中点位置,所以我们减去“点”图片的半径是为了往右的偏移量变小。

canvas.drawBitmap(this.PointsPressed, point.x, point.y, paint);

 

canvas.drawBitmap(this.PointsPressed, point.x-this.bitmapR, point.y-this.bitmapR, paint);

 

下图二是第二段代码的图片。


 

 

结果:

这是绘制图形密码成功的时候

 

if(TextUtils.isEmpty(passwordStr))

      {

         this.title.setText("图案绘制失败");

         this.lockPatternView.reset();

      }

      这是我在MainActivity中设置的,如果图形密码绘制错误那么就会清空,所以就是这个样子。


PS:以上笔记是学习慕课网图形锁视频的

项目完整代码我已经上传了,可以自己在我的资源里搜索。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值