学写了好些个自定义view了,想试试这个能不能自己写一个,发现基本成功了
package com.stone.ninegridlock.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.LinkedHashSet;
/**
* 九宫格锁
* 关于画外圆,可以先直接算出圆心点和半径,以绘制。本例先算的是圆的外矩形
* 连线时如果感觉突兀,可记录内圆心点,以内圆心作碰撞检测
* 可以完善的地方:保存点的顺序,onmeasure中,判断是否匹配,用于解锁方案
*
* author : stone
* email : aa86799@163.com
* time : 15/12/25 22 55
*/
public class NineGridLockView extends View {
private int mCount = 3; //n行n列
private ArrayList<RectF> mListRectFs; //圆的外矩形
private ArrayList<Point> mListCircle; //外圆心点
private LinkedHashSet<Integer> mSetPoints; //记录需要连线的外圆心点在mListCircle中的索引值。LinkedHashSet线性不可重复集合,FIFO
private Paint mPaint;
private float mRadius; //外圆半径
private float mMinRadius = 20; //内圆半径
private float mStrokeWidth = 10; //绘制时的画笔宽度
private Point mMovePoint; //记录一个手势移动时的 实时点
public NineGridLockView(Context context) {
this(context, null);
}
public NineGridLockView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public NineGridLockView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(mStrokeWidth);
mListRectFs = new ArrayList<RectF>();
mListCircle = new ArrayList<Point>();
mSetPoints = new LinkedHashSet<Integer>();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
float w = Math.min(getMeasuredWidth(), getMeasuredHeight());
mRadius = getMeasuredWidth() * 1.00f / (mCount * 3 + 1);
float rectWH = mRadius * 2;
RectF rectF;
for (int i = 0; i < mCount; i++) {
for (int j = 0; j < mCount; j++) {
rectF = new RectF(mRadius + 3 * j * mRadius, mRadius + 3 * i * mRadius,
mRadius + 3 * j * mRadius + rectWH, mRadius + 3 * i * mRadius + rectWH);
mListRectFs.add(rectF);
//item外框
// canvas.drawRect(rectF, mPaint);
// canvas.drawArc(rectF, 0, 360, true, mPaint);
mListCircle.add(new Point((int) (rectF.left + mRadius), (int) (rectF.top + mRadius)));
}
}
}
@Override
protected void onDraw(Canvas canvas) {
for (int i = 0; i < mListCircle.size(); i++) {
Point p = mListCircle.get(i);
mPaint.setColor(Color.GRAY);
//外圆
canvas.drawCircle(p.x, p.y, mRadius, mPaint);
//小圆点
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(p.x, p.y, mMinRadius, mPaint);
//重置绘边样式
mPaint.setStyle(Paint.Style.STROKE);
}
//重新绘制 需要连线的外圆 变色
mPaint.setColor(Color.RED);
for (int index : mSetPoints) {
Point p = mListCircle.get(index);
canvas.drawCircle(p.x, p.y, mRadius, mPaint);
}
//绘制连线
mPaint.setColor(Color.BLACK);
Point p1 = null, p2 = null;
for (int index : mSetPoints) {
if (p1 == null) {
p1 = mListCircle.get(index);
continue;
}
p2 = mListCircle.get(index);
canvas.drawLine(p1.x, p1.y, p2.x, p2.y, mPaint);
p1 = p2;
}
//绘制实时连线
if (mMovePoint != null && p1 != null) {
canvas.drawLine(p1.x, p1.y, mMovePoint.x, mMovePoint.y, mPaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
int index = touchIndex(x, y);
if (index != -1) {
mSetPoints.add(index);
}
mMovePoint = new Point((int) event.getX(), (int) event.getY());
invalidate();
break;
case MotionEvent.ACTION_UP:
mMovePoint = null;
invalidate();
break;
}
return true;
}
/**
* 判断触摸点在哪个item上
* @param x
* @param y
* @return
*/
private int touchIndex(float x, float y) {
for (int i = 0; i < mListCircle.size(); i++) {
Point p = mListCircle.get(i);
if (isCollision(x, y, p.x, p.y, mRadius)) {
return i;
}
}
return -1;
}
/**
* 点和圆形碰撞检测
*
* @param x1 点
* @param y1 点
* @param x2 圆
* @param y2 圆
* @param radius 半径
* @return
*/
private boolean isCollision(float x1, float y1, float x2, float y2, float radius) {
if (Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)) <= radius) {
// 如果点和圆心距离小于或等于半径则认为发生碰撞
return true;
}
return false;
}
}
我的自定义View项目地址: https://github.com/aa86799/MyCustomView (欢迎start&fork)
本文地址:https://github.com/aa86799/MyCustomView/tree/master/ninegridlock