文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android开发中中怎么实现投放九宫格手势密码功能

2023-05-31 09:14

关注

这篇文章将为大家详细讲解有关Android开发中中怎么实现投放九宫格手势密码功能,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

要实现九宫格密码要解决的问题有:

给九宫格密码界面布局九个点,即确定每个节点的位置。每个点到上下左右的距离都是相同的。即九个点刚好围成一个正方形。所以这样的布局界面无法用现有的五大布局来完成必须自定义这个控件。

每个节点只能被选择一次,所以必须记录每个点的选中状态。

手势开始滑动时,每个节点如何知道手势运动的轨迹经过自己。

连线,连线如果步考虑效果,直接用canvas的drawline方法来画连线时当然是很简单的。但是如果用图线(即联系用用一个Bitmap)来画,如何画。解决了这四个问题我们就可以做九宫格密码了。

记录被选择节点的顺序。

带着这是那个问题我们开始实现我们要实现的效果。因为网上好多事例所以我就直接拿别人的事例来消化吧。为了更好的解读这个问题我先把代码贴出来后面在讲解这样我觉得我会刚好说一些,大家也更容易理解一些 

package org.demo.custon_view;  import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView;   public class SquaredPassWord extends View {  ImageView i;  private int length;// 九宫格密码是正方形所以只要知道边长就可以  private Point[] points = new Point[9];// 九宫格节点  private Bitmap defualtPointMap = BitmapFactory.decodeResource(getResources(), R.drawable.locus_round_original);// 正常情况下点的位图  private int poitleght = defualtPointMap.getWidth();// 节点的边长;这里值考虑正方形状态  private Bitmap selectPointMap = BitmapFactory.decodeResource(getResources(), R.drawable.locus_round_click);// 选中情况下点的位图  private Point startPoint;// 起点  private Point tempPoint;// 临时存储上一个节点  private StringBuffer passWBuffer = new StringBuffer();// 保存轨迹顺序的密码  private Bitmap lineBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.locus_line);  private int lineBitmapheight = lineBitmap.getHeight();  private double lineBitmapWidth = lineBitmap.getWidth();  // 以下四个变量是为了绘制最后一个跟手指之间的连线  private int startX;// 移动起点X  private int startY;// 移动起点Y  private int moveX;// 正在移动的X  private int moveY;// 正在移动的Y   public SquaredPassWord(Context context) {   super(context);   }   public SquaredPassWord(Context context, AttributeSet attrs) {   super(context, attrs);   }   public SquaredPassWord(Context context, AttributeSet attrs, int defStyle) {   super(context, attrs, defStyle);   }   @Override  public boolean onTouchEvent(MotionEvent event) {   boolean flag = true;   switch (event.getAction()) {   case MotionEvent.ACTION_DOWN:    passWBuffer.delete(0, passWBuffer.length());    int x = (int) event.getX();    int y = (int) event.getY();    for (Point point : points) {     if (point.isInMyArea(x, y)) {      point.setSelected(true);      tempPoint = startPoint = point;      startX = startPoint.getCenterX();      startY = startPoint.getCenterY();      passWBuffer.append(startPoint.getId());     }    }    invalidate();    break;   case MotionEvent.ACTION_MOVE:    moveX = (int) event.getX();    moveY = (int) event.getY();    for (Point point : points) {     if (point.isInMyArea(moveX, moveY) && !point.isSelected()) {      tempPoint.setNextID(point.getId());      point.setSelected(true);      tempPoint = point;      startX = tempPoint.getCenterX();      startY = tempPoint.getCenterY();      passWBuffer.append(tempPoint.getId());     }    }    invalidate();    break;   case MotionEvent.ACTION_UP:    reSetData();    startX = startY = moveX = moveY = 0;    invalidate();    flag = false;    break;    default:    break;   }   return flag;  }     private void reSetData() {   for (Point point : points) {    point.setSelected(false);    point.setNextID(point.getId());   }  }   @Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {   // TODO Auto-generated method stub   int width = getWidth() - getPaddingLeft() - getPaddingRight();   int height = getHeight() - getPaddingTop() - getPaddingBottom();   length = (width < height ? width : height);// 获取边长   if(!(length>0)){       }   System.out.println(length);   initPionts(points);   super.onMeasure(widthMeasureSpec, heightMeasureSpec);  }   @Override  protected void onDraw(Canvas canvas) {   // TODO Auto-generated method stub   if (moveX != 0 && moveY != 0 && startX != 0 && startY != 0) {    // 绘制当前活动的线段    drawLine(startX, startY, moveX, moveY, canvas);   }   drawLinePoint(canvas);   super.onDraw(canvas);  }     @SuppressWarnings("null")  private void initPionts(Point[] points) {   int spacing = (length - poitleght * 3) / 2;    if (points == null && points.length != 9) {// 只做九宫格的处理    return;   } else {    for (int i = 0; i < 9; i++) {     int row = i / 3;// 行数     int column = i % 3;// 列数;求整取余      int x = (poitleght + spacing) * column + getPaddingLeft();// x坐标     int y = (poitleght + spacing) * row + getPaddingTop();// y坐标     Point point = new Point((i + 1), x, y, poitleght);     points[i] = point;    }   }  }     private void drawLinePoint(Canvas canvas) {   if (startPoint != null) {    drawP2POrbit(startPoint, canvas);   }   Paint paint = null;// new Paint();   // 绘制每个点的图片   for (Point point : points) {    if (point.isSelected()) {// 绘制大圈     canvas.drawBitmap(selectPointMap, point.getX(), point.getY(), paint);    } else {     canvas.drawBitmap(defualtPointMap, point.getX(), point.getY(), paint);    }   }  }     private void drawP2POrbit(Point point, Canvas canvas) {   if (point.getId() != point.nextID) {    // canvas.concat(matrix);    Point endPoint = null;    // 获取目标节点    for (Point point3 : points) {     if (point3.getId() == point.getNextID()) {      endPoint = point3;      break;     }    }    if (endPoint != null) {     // 画线     drawLine(point.getCenterX(), point.getCenterY(), endPoint.getCenterX(), endPoint.getCenterY(), canvas);     // 递归     drawP2POrbit(endPoint, canvas);    }   }  }     private void drawLine(int startX, int startY, int stopX, int stopY, Canvas canvas) {   Paint paint = new Paint();   // 获得斜边长度   double hypotenuse = Math.hypot((stopX - startX), (stopY - startY));   // double side = stopX - startX;// 邻边   // double piAngle = Math.acos(side / hypotenuse);// pi角度   // float rotate = (float) (180 / Math.PI * piAngle);// 转换的角度   float rotate = getDegrees(startX, startY, stopX, stopY);   Matrix matrix = new Matrix();   // matrix.postRotate(rotate);//不能用这个matritx 来选择角度只能用 让canvas懒选择     // 用matrix的话会引起图片所表示的线条不在中心点上     canvas.rotate(rotate, startX, startY);   matrix.preTranslate(0, 0);   matrix.setScale((float) (hypotenuse / lineBitmapWidth), 1.0f);   matrix.postTranslate(startX, startY - lineBitmapheight / 2.f);   canvas.drawBitmap(lineBitmap, matrix, paint);   canvas.rotate(-rotate, startX, startY);//恢复   canvas.save();  //  Paint paint1 = new Paint(); //  paint1.setColor(Color.BLACK); //  paint1.setStrokeWidth(8);// 粗细 //  paint1.setFlags(Paint.ANTI_ALIAS_FLAG); //  canvas.drawLine(startX, startY, stopX, stopY, paint1);   }     private float getDegrees(int startX, int startY, int stopX, int stopY) {   // 获得斜边长度   double hypotenuse = Math.hypot((stopX - startX), (stopY - startY));   double side = stopX - startX;// 邻边   double piAngle = Math.acos(side / hypotenuse);// pi角度   float rotate = (float) (180 / Math.PI * piAngle);// 转换的角度(0--180);   if (stopY - startY < 0) {// 如果Y愁小于0说明角度在第三或者第四像限    rotate = 360 - rotate;   }   return rotate;  }     public String getOrbitString() {   return (passWBuffer == null ? null : passWBuffer.toString());  }     class Point {    private int id;// 点的id   private int nextID;// 连向下一个借点的id   private int x;// 点的左上角x坐标   private int y;// 点的左上角的y坐标   private boolean isSelected;// 该节点是否被选中   private int width;// 点的长度 这里只考虑正方形    public Point() {    super();    // TODO Auto-generated constructor stub   }    public int getId() {    return id;   }    public void setId(int id) {    this.id = id;   }    public int getNextID() {    return nextID;   }    public void setNextID(int nextID) {    this.nextID = nextID;   }    public int getX() {    return x;   }    public void setX(int x) {    this.x = x;   }    public int getY() {    return y;   }    public void setY(int y) {    this.y = y;   }    public boolean isSelected() {    return isSelected;   }    public void setSelected(boolean isSelected) {    this.isSelected = isSelected;   }    public int getWidth() {    return width;   }    public void setWidth(int width) {    this.width = width;   }    public Point(int id, int x, int y, int width) {    super();    this.id = id;    this.x = x;    this.y = y;    this.nextID = id;    this.isSelected = false;    this.width = width;   }    public int getCenterX() {    return x + (width / 2);   }    private int getCenterY() {    return y + (width / 2);   }       public boolean isInMyArea(int x, int y) {     // return (this.x < x && x < (this.x + width)) && (this.y < y && y <    // (this.y + width));    return ((this.getCenterX() - lineBitmapWidth / 2) < x && x < (this.getCenterX() + lineBitmapWidth / 2))      && ((this.getCenterY() - lineBitmapWidth / 2) < y && y < (this.getCenterY() + lineBitmapWidth / 2));   }  } }

1、布局九个节点。将九个节点布局起来首先要知道控件宽和高,这样我们才能如何布局,在onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法中用getWidth()和getHeight(); 方法我们就可以得到高度和宽度,因为自定义布局还有一个padding属性,所以我们还要计算这个步骤。所以计算真正布局这九个节点的正方形的边长(我们这里是做正方形的九宫格)为:
int width = getWidth() - getPaddingLeft() - getPaddingRight();
int height = getHeight() - getPaddingTop() - getPaddingBottom();
length = (width < height ? width : height);// 获取边长如果这个边长大于0我就开始确定九个节点分别的坐标位置。边长=三个节点的变长+两个间隙长度。

那么现在我们可以确定每个节点的位置了第一个节点为(0,0),第二节点为(0+pointwidth+spacing,0), ……。但是我们现在要做的首先是是怎样结论每个节点的位置,即定义一个节点的类。根据前面列出的几个问题可得出该节点要记录节点的id,起止坐标,被选中状态,节点的中心点坐标以及节点所连接的下一个节点的左边。根据这些性质我们写出了Point 的内部类如上面代码286行开始的定义。定义完了节点的类我们就开始为他们初始化如144还看是的initPionts方法。

2、画点以及画连线drawLinePoint方法所示用一个循环就可以把所有点画出来。绘制连线,现在有个情况要分析一下,1)点与点之间的连线即节点已经确定了加一个节点的id。2)节点与手势之间的连线,即节点还没有确定下一个节点前节点到手指的连线。先抛开画线这个方法不说画线就是画起点到终点的连线,这样我们可以先定义一个空发方法,传递canvas,以及表示两点坐标的参数传递给drawLine这个方法(220行开始),后面再去处理画线。根据先易后难的原则我们可以很容易的绘制点与点之间的连线如187行drawP2POrbit方法。麻烦就在点到手指的连线。干根据常识我们知道这个点肯定是最后被选中的那个点。而且这个点不是一成不变的所以我们得定义一个临时变量tempPoint来保存这个节点(不能用startPoit记录startPoint用保存最起点的位置)。而连线的终点就是手指的坐标点。这样就可以缺点两个节点下来了。见代码57行开始的onTouchEvent方法,该方法里头同时还记录的节点呗选中的顺序。这样我们就可以在ondraw方法画出了点和连线如128行开始。

3、画连线,drawLine(220行)这里我没什么要特别说的唯一要提起的就是反三角函数问题以及角度转化问题,反三角函数我不说了大家都会只是太长时间没用了忘了现在再去看一眼就行。而这个角度转化这块要特别注意一下我们要转化的是canvas的角度而不是bitmap的角度以为转化bitmap的角度的画很不容易确定bitmap的起点坐标因为bitmap以左上角作为起点坐标,随着角度的变化起点坐标也跟着变很难去计算。所以转换canvas的角度比较简单,最后在画晚线后别忘了再把角度转回来。并保存。

4、返回密码串getOrbitString(276行)是返回密码串的方法,在调用者(activity)的ontouch的Action_UP中调用就可以了。

关于Android开发中中怎么实现投放九宫格手势密码功能就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯