項目可能的需要,自己嘗試寫了一個九宮格解鎖,在此記錄,以作筆記。
先上效果圖
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwczX0xiRGZkRGZ0Xy9GbvNGL2EzXlpXazxSP9EkT6VEVNVTRU1EM4wmYwhGWhxGZzwEMW1mY1RzRapnTtxkb5ckYplTeMZTTINGMShUYfRHelRHLwEzX39GZhh2css2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xyayFWbyVGdhd3LcV2Zh1Wa9M3clN2byBXLzN3btg3Pn5GcukzM3AzMwETMxEjMxgTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
關于項目的分析,見下圖
width 九宮格控件的寬度,height 九宮格的控件的高度,offsetX是x軸的偏移量,offsetY是y軸的偏移量(實際編寫的時候一般根據寬高的數值取小的居中顯示,是以 offsetX與offsetY 根據寬高有一個數值會為 0 ),将控件中間區域分為 4X4 的數組區域,step為方格的大小,數組坐标與數組【1,2,3,4,5,6,7,8,9】的對應關系對應如圖(根據需要可以把 1-9 改為字母或者特殊字元的對應關系),計算公時為 坐标 ( i , j ) 對應的數字 number = i +( j - 1)*3.
手勢在移動的時候感覺觸摸的坐标判斷是否連接配接到對應的點。
九宮格控件 NineLockView
public class NineLockView extends View {
private Paint paint;
private boolean isInit=true;//是否初始化
private boolean isDrawEnd=false;//是否畫最後的點與觸摸點之間的線
private int offsetX;//x軸偏移量
private int offsetY;//y軸偏移量
private int step;//節點間的距離
private int radius=40;//節點圓圈的半徑大小
private int lastPointX;//最後一個節點的 x 坐标
private int lastPointY;//最後一個節點的 y 坐标
private float linearEndX;//觸摸點的最終位置坐标
private float linearEndY;
private List<Point> code=new ArrayList<Point>();//選中點的集合
private NineLockListener lockListener;
public NineLockView(Context context,@Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init(){
paint=new Paint();
paint.setColor(Color.parseColor("#458264"));
paint.setAntiAlias(true);
paint.setStrokeWidth(1);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
}
public void setLockListener(NineLockListener lockListener) {
this.lockListener = lockListener;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(isInit){
isInit=false;
int w=getWidth();
int h=getHeight();
if(w>h){
offsetX=(w-h)/2;
w=h;
}else {
offsetY=(h-w)/2;
h=w;
}
step=w/4;
code.clear();
lastPointY=0;
lastPointX=0;
}
for(int i=1;i<4;i++){
for(int j=1;j<4;j++){
canvas.drawCircle(
offsetX+step*i,
offsetY+step*j,
radius,
paint
);
}
}
paint.setStrokeWidth(8);//設定連線的寬度
if(code.size()>=1){
for(int i=1;i<code.size();i++){
canvas.drawLine(code.get(i-1).x*step+offsetX,
code.get(i-1).y*step+offsetY,
code.get(i).x*step+offsetX,
code.get(i).y*step+offsetY,
paint);
}
lastPointX=code.get(code.size()-1).x*step+offsetX;
lastPointY=code.get(code.size()-1).y*step+offsetY;
}
if(isDrawEnd && lastPointX!=0 && lastPointY!=0 && linearEndX > 9 && linearEndY>9){
canvas.drawLine(lastPointX,lastPointY,linearEndX,linearEndY,paint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
isInit=true;
isDrawEnd=true;
invalidate();
standLinear(event.getX(),event.getY());
break;
case MotionEvent.ACTION_MOVE:
standLinear(event.getX(),event.getY());
break;
case MotionEvent.ACTION_UP:
isDrawEnd=false;
setResultCode();
invalidate();
break;
}
return super.onTouchEvent(event);
}
/**
* 根據手的滑動判斷是否選中某個節點
* 當觸摸點與節點值之間的距離小于 radius 時預設選中
* @param x
* @param y
*/
private void standLinear(float x,float y){
boolean isStand=false;
for(int i=1;i<4;i++){
for(int j=1;j<4;j++){
float tx=offsetX+step*i-x;
float ty=offsetY+step*j-y;
if(Math.sqrt(tx*tx+ty*ty)<=radius){
isStand=true;
if(code.size()==0){
linearEndX=i;
linearEndY=j;
code.add(new Point(i,j));
}else {
Point last=code.get(code.size() - 1);
//如果目前點與記錄的最後一個點重複,則不再重複添加
if (last.x == i && last.y == j) {
linearEndX = x;
linearEndY = y;
} else {
//添加記錄點,如果在豎直或水準方向上中間間隔一個點則間隔的點也要加上
//未考慮對角線間隔的情況
if(i==last.x && j==last.y+2){
code.add(new Point(i,j-1));
}else if(i==last.x && j==last.y-2){
code.add(new Point(i,j+1));
}else if(j==last.y && i==last.x+2){
code.add(new Point(i-1,j));
}else if(j==last.y && i==last.x-2){
code.add(new Point(i+1,j));
}
code.add(new Point(i,j));
}
}
break;
}
}
if(isStand){
break;
}
}
if(!isStand){
linearEndX=x;
linearEndY=y;
}
invalidate();
}
private void setResultCode(){
if(lockListener!=null){
if(code.size()==0){
lockListener.onError();
}else {
int[] result = new int[code.size()];
for (int i = 0; i < code.size(); i++) {
result[i] = (code.get(i).y - 1 )* 3 + code.get(i).x;
}
lockListener.onLockResult(result);
}
}
}
}
以上代碼是九宮格以及連線的自定義控件的代碼
源碼 碼雲中國 git 下載下傳:九宮格代碼下載下傳