一.引言
在上篇博客Android进阶之自定义View实战(一)仿iOS UISwitch控件实现中我们主要介绍了自定义View的最基本的实现方法。作为自定义View的入门篇,仅仅介绍了Canvas的基本使用方法,而对用户交互层面仅仅处理了单击事件接口,在实际的业务中,常常涉及到手势操作,本篇博客以九宫格手势解锁View为例,来说明自定义View如何根据需求处理用户的手势操作。虽然九宫格手势解锁自定义View网上资料有很多,实现原理大同小异,但这里我只是根据自己觉得最优的思路来实现它,目的是让更多的初学者能看清我的思想,更快的掌握它的套路。话不多说,先看效果图,本人纯种工科男,颜色大家看看就好~_~!(ps:as的录屏效果有一半屏幕是花的,所以上图片将就一下。。);
1.手指滑动状态
2.手指释放后,校验失败
3.手指释放后,校验成功
二.案例分析
根据上面的三张图,可以看出手势锁有下面几个要素:
1.九宫格阵列状态,每个格子有三种状态:空闲、击中、校验失败、校验成功,其中击中状态是在手指移动过程中产生,后面的校验状态是手指释放后产生。格子状态的改变都在View的触摸事件里处理。
2.九宫格的绘制元素,每个格子有半透明大圆、深色小圆、三角;在移动过程中的手指路径,包括两个:格子与格子之间的连线和路径的”尾巴”:动态探测线。
3.触摸事件所需要处理的逻辑主要有每个格子的状态处理和路径规划。
1>根据手指的位置,确定击中的节点,在down和move事件改变它的状态;
2>在move事件中,探测击中的节点,如果探测到则绘制连线,否则绘制探测线。
3>在up或者cancel事件中,取消探测线,并根据击中的节点校验密码,更新状态,计算三角的方向,重绘节点。
三.范例代码
1.通过第二节的分析,格子(Block)是这个View的基本构成单元,包含状态、位置、大小半径、三角等元素,触摸事件的处理都是真的Block的处理。Block代码:
package com.star.gesturelock;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
/**
* 一个阵列的基本组成单元
* Created by kakaixcm on 16/6/7.
*/
public class Block {
float mCenterPointX;//圆心x
float mCenterPointY;//圆心y
float mBigRadius;//大圆半径
float mLittleRadius;//小圆半径
BlockSate mState = BlockSate.IDLE;//默认空闲
int mId;//索引
//空闲状态颜色
int mIdleBigCircleColor = Color.parseColor("#110000ff");
int mIdleLittleCircleColor = Color.parseColor("#0000ff");
//选中状态颜色
int mHittedBigCircleColor = Color.parseColor("#1100ff00");
int mHittedLittleCircleColor = Color.parseColor("#00ff00");
//密码通过的颜色
int mSuccessBigCircleColor = Color.parseColor("#1100ff00");
int mSuccessdLittleCircleColor = Color.parseColor("#00ff00");
//密码错误时的颜色
int mErroBigCircleColor = Color.parseColor("#11ff0000");
int mErroLittleCircleColor = Color.parseColor("#ff0000");
//三角
Path mArrow = new Path();
//三角指向角度,水平向右为0度,顺时针方向为正
double mArrowAngle;
public void setArrowAngle(double angle){
mArrowAngle = angle;
}
public void drawArrow(Canvas canvas, Paint paint){
//没有松手,则不画三角
if(mState != BlockSate.SUCCESS && mState != BlockSate.ERRO){
return;
}
float arrowLen = (mBigRadius - mLittleRadius)*0.5f;
float arrowLeftX = mCenterPointX + mLittleRadius + (mBigRadius - mLittleRadius - arrowLen)/2;
float arrowRightX = arrowLeftX + arrowLen;
float topY = mCenterPointY - arrowLen;
float bottomY = mCenterPointY + arrowLen;
mArrow.moveTo(arrowRightX, mCenterPointY);
mArrow.lineTo(arrowLeftX, topY);
mArrow.lineTo(arrowLeftX, bottomY);
mArrow.close();
canvas.save();
canvas.rotate((float) mArrowAngle, mCenterPointX, mCenterPointY);
canv