刚才我使用银行APP时,看见了这个效果,趁着下班时间,就写了。
先看下效果图:
我先说下我的思路:
1: 先计算每个点 XY坐标点,然后存储在integerList中,然后画九个点,此时我把它叫为:画板的原始状态!
2:复写onTouchEvent事件, 然后每次监听ACTION_DOWN,ACTION_MOVE,ACTION_UP状态;
对了,integerList里点的存储的顺序是:从左上角开始为第一个,然后,第二个……..第九个;
具体的看下图:
具体的看下代码:
package com.app.test.testlineproject;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
/**
* Created by ${liumegnqiang} on 2017/6/28.
*/
public class LockLineView extends View {
private float height;// view的高度
private float wight;
private float radius ;//圆的半径
private float companyWidth;//因为是三个点,所以将width分为三分 也就是 companyWidth = width / 3;
private float companyHeight;
private List integerList = new ArrayList<>();//九个点的坐标
private List indexList = new ArrayList<>();//连接的点(不重复)
private float moveX;//每次移动的X坐标
private float moveY;//每次移动的Y坐标
private OnLessPaintListener onLessPaintListener;
private boolean isUP = false;//判断是否是UP状态,是的话,就去除多余的连接 , 只连接点与点
private int widthLine = 4;//线的宽度
//R.color.line 可以自定义color
private int selectColor = ContextCompat.getColor(getContext(),R.color.line);//圆选中的颜色
private int unSelectColor = Color.GRAY;//圆未选中的颜色
private int lineColor = ContextCompat.getColor(getContext(),R.color.line);//线的颜色
public LockLineView(Context context) {
super(context);
}
public LockLineView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LockLineView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
height = getMeasuredHeight();
wight = getMeasuredWidth();
/**
* 这三个数值的计算比例,可根据自己的需求, 更改!!!
*/
companyWidth = wight / 3;
companyHeight = height / 3;
radius = wight / 16;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
/**
* 画九宫格
*/
paint.setColor(unSelectColor);//原点的颜色
for(int i = 0;i < 3;i++){
for(int j = 0;j < 3 ;j++ ){
RectF rectF = new RectF();
rectF.left = j * companyWidth + companyWidth / 2 - radius;
rectF.right = j * companyWidth + companyWidth / 2 + radius;
rectF.top = i * companyHeight + companyHeight / 2 - radius;
rectF.bottom = i * companyHeight + companyHeight / 2 + radius;
integerList.add(new PaintBean(j * companyWidth + companyWidth / 2, i * companyHeight + companyHeight / 2));
canvas.drawOval(rectF, paint);
}
}
/**
* 画连接的线
*/
if(indexList.size() == 0){
return;
}
paint.setColor(lineColor);//线的颜色
paint.setStrokeWidth(widthLine);//线的宽度
for(int i = 1;i < indexList.size();i++){
canvas.drawLine(integerList.get(indexList.get(i - 1)).getPaintX(), integerList.get(indexList.get(i - 1)).getPaintY(),
integerList.get(indexList.get(i)).getPaintX(),integerList.get(indexList.get(i)).getPaintY(), paint);
}
if(!isUP){
canvas.drawLine(integerList.get(indexList.get(indexList.size() - 1)).getPaintX(), integerList.get(indexList.get(indexList.size() - 1)).getPaintY(),
moveX, moveY, paint);
}
/**
* 画选中的点
*/
paint.setColor(selectColor);//选中圆的颜色
for(int i = 0;i < indexList.size();i++){
PaintBean paintBean = integerList.get(indexList.get(i));
RectF rectF = new RectF();
rectF.left = paintBean.getPaintX() - radius;
rectF.right = paintBean.getPaintX() + radius;
rectF.top = paintBean.getPaintY() - radius;
rectF.bottom = paintBean.getPaintY() + radius;
canvas.drawOval(rectF, paint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:{
Message message = new Message();
message.what = 3;
handler.sendMessage(message);
break;
}
case MotionEvent.ACTION_MOVE:{
moveX = event.getX();
moveY = event.getY();
for(int i = 0;i < integerList.size();i++){
PaintBean paintBean = integerList.get(i);
float distance = (float)Math.sqrt((paintBean.getPaintX()-moveX) * (paintBean.getPaintX()-moveX)
+ (paintBean.getPaintY() - moveY) * (paintBean.getPaintY() - moveY));
/**
* 有一个问题:
* 就是当你测试时,可以中间隔一个原点,
* 也就是该原点没有被选中,这时你可以修改该下面的判断,进行修改;
* 当然 你感觉没问题的话 就不用改了。。。
*/
if(distance < radius){
if(!indexList.contains(i)){
indexList.add(i);
}
}
}
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
break;
}
case MotionEvent.ACTION_UP:{
Message message = new Message();
message.what = 2;
handler.sendMessage(message);
break;
}
}
return true;
}
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1:{
isUP = false;
integerList.clear();
invalidate();
break;
}
case 2:{
isUP = true;
if(indexList.size() < 4){
/**
* TODO 连点数少于四个时,业务逻辑处理
*/
Toast.makeText(getContext(),"连点数不能少于4个", Toast.LENGTH_SHORT).show();
if(onLessPaintListener != null){
onLessPaintListener.onLessPaintListener();//少于四个时,回调给view层
}
integerList.clear();
indexList.clear();
}else{
/**
* TODO 连点数大于四个时,业务逻辑处理
*/
}
invalidate();
break;
}
case 3:{
isUP = false;
integerList.clear();
indexList.clear();
invalidate();
break;
}
}
}
};
/**
* 在view层设置参数之后(比如:setWidthLine(4)),可调用此方法,刷新LockLineView;
*/
public void setPaint(){
postInvalidate();
}
/**
* 少于四个点数时,回调
*/
interface OnLessPaintListener{
void onLessPaintListener();
}
public OnLessPaintListener getOnLessPaintListener() {
return onLessPaintListener;
}
public void setOnLessPaintListener(OnLessPaintListener onLessPaintListener) {
this.onLessPaintListener = onLessPaintListener;
}
public float getRadius() {
return radius;
}
public void setRadius(float radius) {
this.radius = radius;
}
public int getWidthLine() {
return widthLine;
}
public void setWidthLine(int widthLine) {
this.widthLine = widthLine;
}
public int getLineColor() {
return lineColor;
}
public void setLineColor(int lineColor) {
this.lineColor = lineColor;
}
public int getUnSelectColor() {
return unSelectColor;
}
public void setUnSelectColor(int unSelectColor) {
this.unSelectColor = unSelectColor;
}
public int getSelectColor() {
return selectColor;
}
public void setSelectColor(int selectColor) {
this.selectColor = selectColor;
}
}
有的小伙伴可能会问:为什么不用postInvalidate()呢?
其实我刚开始用的就是这个方法,但是我发现滑动的move和刷新view不同步,所以就用了invalidate(),自己控制刷新view。
至于颜色的,可以通过相应的get方法进行设置。对了 这个view的宽高,需要自己去调试!
最后附上源码:
http://download.csdn.net/detail/lmq121210/9884371