此九宫格手势自定义控件虽然比较简陋,但是也基本实现了如下功能:
1.默认显示九个小内圆,实心圆。 另外提供了,设置其半径,初始化颜色,以及选中之后的颜色
2.如果选中了小内圆,对应的也显示外圆环。 另外提供了,选中时候的颜色,以及失败的时候的颜色的设置
3.连线的绘制,在触摸滑动的过程中选中的点为联络站进行绘制路径。另外提供了 触摸时候连线的颜色以及失败的时候的颜色设置
4.手指离开触摸屏的时候,记录了对应的密码数字。并提供回调接口,可传递给外界进行校验判断。
注意:逻辑不复杂,但是需要注意的是,测量的时候对于AT_MOST如何处理。另外对自定义View设置padding的情况下如何处理,使其生效。
下面直接贴代码:
1.自定义View
package com.example.win10.smallprojecttest; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Point; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.logging.Handler; /** * Created by WIN10 on 2019/2/11. */ public class MyLockView extends View { public Context context; private int screenWidth; private int screenHeight; int width;//去掉内边距之后的宽度,可用来画画的宽度 int height;//此去掉内边距之后的高度,可用来画画的高度 //内圆的画笔,color1默认,color11 被选中时候的颜色 private int radio1 = 50; private int color1 = Color.GRAY; private int color11 = Color.BLUE; private Paint paint1; //外圆的画笔参数 private int radio2 = 80; private int color2 = Color.BLUE; private int color22 = Color.RED; private Paint paint2; //连线画笔的参数 private int color3 = Color.BLUE; private int color33 = Color.RED; private Paint paint3; int left0 = 0;//大圆环的最左边的坐标 在无pading时为0 int top0 = 0;//大圆环的最上边的坐标 在无padding时为0 //下面是九个点 Point point1 = new Point(); Point point2 = new Point(); Point point3 = new Point(); Point point4 = new Point(); Point point5 = new Point(); Point point6 = new Point(); Point point7 = new Point(); Point point8 = new Point(); Point point9 = new Point(); ArrayList<Point> pointList = new ArrayList<>(); public void setSmallCircle(int radio,int defaultColor,int selectColor){ radio1=radio; color1=defaultColor; color11=selectColor; } public void setLargeCircle(int radio,int defaultColor,int errorColor){ radio2=radio; color2=defaultColor; color22=errorColor; } public void setLine(int defaultColor,int errorColor){ color3=defaultColor; color33=errorColor; } public MyLockView(Context context) { this(context, null); } public MyLockView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public MyLockView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.context = context; init(); } public void init() { screenWidth = ScreenUtil.getScreenWidth(context); screenHeight = ScreenUtil.getScreenHeight(context); paint1 = new Paint(); paint1.setAntiAlias(true); paint1.setColor(color1); paint1.setStyle(Paint.Style.FILL); paint2 = new Paint(); paint2.setAntiAlias(true); paint2.setColor(color2); paint2.setStyle(Paint.Style.STROKE); paint2.setStrokeWidth(6); paint3 = new Paint(); paint3.setAntiAlias(true); paint3.setColor(color3); paint3.setStyle(Paint.Style.STROKE); paint3.setStrokeWidth(6); } //根据可用View的尺寸去设置9点 public void setAllPoint(int width, int height) { int delX = (width - radio2 * 2) / 2; int delY = (height - radio2 * 2) / 2; point1.set(left0 + radio2, top0 + radio2); point2.set(point1.x + delX, point1.y); point3.set(point2.x + delX, point1.y); point4.set(point1.x, point1.y + delY); point5.set(point4.x + delX, point4.y); point6.set(point5.x + delX, point4.y); point7.set(point4.x, point4.y + delY); point8.set(point7.x + delX, point7.y); point9.set(point8.x + delX, point7.y); pointList.add(point1); pointList.add(point2); pointList.add(point3); pointList.add(point4); pointList.add(point5); pointList.add(point6); pointList.add(point7); pointList.add(point8); pointList.add(point9); } //测量,在AT_MOST下进行处理 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widths = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heights = MeasureSpec.getSize(heightMeasureSpec); if (widthMode == MeasureSpec.AT_MOST) { widths = (int) (screenWidth * 0.8); } if (heightMode == MeasureSpec.AT_MOST) { heights = (int) (screenHeight * 0.6); } setMeasuredDimension(widths, heights); } //重新设置布局,处理Padding情况 @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int paddingLeft = getPaddingLeft(); int paddingTop = getPaddingTop(); int paddingRight = getPaddingRight(); int paddingBottom = getPaddingBottom(); super.onLayout(changed, left + paddingLeft, top + paddingTop, right - paddingRight, bottom - paddingBottom); width = right - left - paddingLeft - paddingRight; height = bottom - top - paddingTop - paddingBottom; left0 = paddingLeft; top0 = paddingTop; setAllPoint(width, height); postInvalidate(); } //画画 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Point point = null; //没有选中的内圆,还是灰色的 for (int i = 0; i < pointList.size(); i++) { paint1.setColor(color1); point = pointList.get(i); canvas.drawCircle(point.x, point.y, radio1, paint1); } if (arrayListSelect.size() > 0) { paint1.setColor(color11); Path path = new Path(); path.moveTo(pointList.get(arrayListSelect.get(0)).x, pointList.get(arrayListSelect.get(0)).y); for (int j = 0; j < arrayListSelect.size(); j++) { Integer index = arrayListSelect.get(j); point = pointList.get(index); canvas.drawCircle(point.x, point.y, radio1, paint1); canvas.drawCircle(point.x, point.y, radio2, paint2); if (arrayListSelect.size() > 1 && j > 0) { path.lineTo(point.x, point.y); } } if (isTouching&&ScreenUtil.dist(xMove,yMove,point.x,point.y)>radio2) { path.lineTo(xMove, yMove); } canvas.drawPath(path, paint3); } } int xMove; int yMove; boolean isTouching = false; ArrayList<Integer> arrayListSelect = new ArrayList<>();//存储触摸到的点,不重复添加 @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: isTouching = true; arrayListSelect.clear(); int x = (int) event.getX(); int y = (int) event.getY(); getOuterCircle(x, y); break; case MotionEvent.ACTION_MOVE: xMove = (int) event.getX(); yMove = (int) event.getY(); getOuterCircle(xMove, yMove); postInvalidate(); break; case MotionEvent.ACTION_UP: if (guesterListener != null) { guesterListener.getGuesterNum(arrayListSelect); } isTouching = false; new android.os.Handler().postDelayed(new Runnable() { @Override public void run() { arrayListSelect.clear(); init(); postInvalidate(); } }, 1500); break; } return true; } private int getOuterCircle(int x, int y) { Point point; for (int i = 0; i < pointList.size(); i++) { point = pointList.get(i); if (x > point.x - radio1 && x < point.x + radio1 && y > point.y - radio1 && y < point.y + radio1) { if (!arrayListSelect.contains(i)) { arrayListSelect.add(i); } } } return -1; } GuesterListener guesterListener; public void setOnGuesterLisetener(GuesterListener lisetener) { guesterListener = lisetener; } public interface GuesterListener { void getGuesterNum(ArrayList<Integer> arrayList); } public void passWordError(ArrayList arrayList){ arrayListSelect=arrayList; paint3.setColor(color33); paint2.setColor(color22); postInvalidate(); } }
2.工具类:
package com.example.win10.smallprojecttest; import android.content.Context; import android.util.DisplayMetrics; import android.view.Display; import android.view.WindowManager; import static java.lang.Math.pow; /** * Created by WIN10 on 2019/2/11. */ public class ScreenUtil { public static int height; public static int width; private static ScreenUtil instance; private Context context; private ScreenUtil(Context context) { this.context = context; WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics(); manager.getDefaultDisplay().getMetrics(dm); width = dm.widthPixels; height = dm.heightPixels; } public static ScreenUtil getInstance(Context context) { if (instance == null) { instance = new ScreenUtil(context); } return instance; } /** * 得到手机屏幕的宽度, pix单位 */ /** * 获得通知栏的高度 * * @return */ public static int getStatusHeight(Context context) { int resid = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resid > 0) { return context.getResources().getDimensionPixelSize(resid); } return -1; } /** * 得到手机屏幕的宽度, pix单位 */ public int getScreenWidth() { return width; } //获取屏幕的宽度 public static int getScreenWidth(Context context) { WindowManager manager = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); Display display = manager.getDefaultDisplay(); return display.getWidth(); } //获取屏幕的高度 public static int getScreenHeight(Context context) { WindowManager manager = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); Display display = manager.getDefaultDisplay(); return display.getHeight(); } //px转dp public static int dp2px(Context context, float dp) { return (int) (dp * context.getResources().getDisplayMetrics().density + 0.5f); } //两个点之间的距离 public static int dist( int x1, int y1, int x2, int y2 ){ double x,y; x = Math.pow(x1-x2,2); y =Math. pow(y1-y2,2); return (int) Math.sqrt(x+y); } }
3.使用:
package com.example.win10.smallprojecttest; import android.graphics.Color; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.widget.Toast; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { MyLockView myLockView; String mima=""; int time=5; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myLockView= findViewById(R.id.test); myLockView.setSmallCircle(50, Color.GREEN,Color.BLUE); myLockView.setOnGuesterLisetener(new MyLockView.GuesterListener() { @Override public void getGuesterNum(ArrayList<Integer> arrayList) { mima = ""; if (time > 0) { time--; if (arrayList != null && arrayList.size() > 0) { for (int i = 0; i < arrayList.size(); i++) { Integer integer = arrayList.get(i); mima = mima + integer; } } if (!TextUtils.isEmpty(mima) && mima.equals("012345")) { Toast.makeText(MainActivity.this, "登陆成功", Toast.LENGTH_LONG).show(); time=5; } else { myLockView.passWordError(arrayList); Toast.makeText(MainActivity.this, "您还有" + time + "次机会", Toast.LENGTH_LONG).show(); } }else{ Toast.makeText(MainActivity.this, "您已经连续五次输入错误,账号已经冻结", Toast.LENGTH_LONG).show(); } } }); } }
资源文件就不贴了,随便试试就行。
扫描二维码关注公众号,回复:
6023490 查看本文章