当前位置: 移动技术网 > 移动技术>移动开发>Android > 使用Android自定义控件实现滑动解锁九宫格

使用Android自定义控件实现滑动解锁九宫格

2019年07月24日  | 移动技术网移动技术  | 我要评论

本文概述:

 滑动解锁九宫格的分析:

1、需要自定义控件;
2、需要重写事件ontouchevent();
3、需要给九个点设置序号和坐标,这里用map类就行;
4、需要判断是否到滑到过九点之一,并存储滑到过的点的序号,而且需要一个方法可以返回它们,这里用list类就行;

滑动解锁当前还是比较流行的,今天写了个简单的滑动解锁九宫格的例程,分享出来让初学者看看。

我的是这样的:

demo

首先,自定义一个view

/**
 * 九宫格
 */
public class ninegridview extends view {
  private int width;//该控件的宽
  private int height;//该控件的高
  private paint mpaintbigcircle;//用于画外圆
  private paint mpaintsmallcircle;//用于画内圆
  private paint mpaintline;//用于画线
  private paint mpainttext;//用于画文本
  private path path;//手势划线时需要用到它
  private map<integer, float[]> pointcontainer;//存储九个点的坐标
  private list<integer> pointerslipped;//存储得到的九宫格密码
  public list<integer> getpointerslipped() {
    return pointerslipped;
  }
  public void setpointerslipped(list<integer> pointerslipped) {
    this.pointerslipped = pointerslipped;
  }
  public ninegridview(context context) {
    super(context);
  }
  public ninegridview(context context, attributeset attrs) {
    super(context, attrs);
    mpaintbigcircle = new paint();
    mpaintbigcircle.setcolor(color.blue);
    mpaintbigcircle.setstyle(paint.style.stroke);//不充满
    mpaintbigcircle.setantialias(true);//抗锯齿打开
    mpaintsmallcircle = new paint();
    mpaintsmallcircle.setcolor(color.green);
    mpaintsmallcircle.setstyle(paint.style.fill);//充满,即画的几何体为实心
    mpaintsmallcircle.setantialias(true);
    mpaintline = new paint();
    mpaintline.setcolor(color.green);
    mpaintline.setstyle(paint.style.stroke);
    mpaintline.setstrokewidth(20);
    mpaintline.setantialias(true);
    mpainttext = new paint();
    mpainttext.setcolor(color.white);
    mpainttext.settextalign(paint.align.center);//向中央对齐
    mpainttext.settextsize(50);
    mpainttext.setantialias(true);
    path = new path();
    pointcontainer = new hashmap<>();
    pointerslipped = new arraylist<>();
  }
  @override
  protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
    super.onmeasure(widthmeasurespec, heightmeasurespec);
    width = getdefaultsize(getsuggestedminimumwidth(), widthmeasurespec);
    height = getdefaultsize(getsuggestedminimumheight(), heightmeasurespec);
  }
  private float pivotx;//触屏得到的x坐标
  private float pivoty;//触屏得到的y坐标
  private float selectedx;//当前选中的圆点的x坐标
  private float selectedy;//当前选中的圆点的y坐标
  private float selectedxold;//从前选中的圆点的x坐标
  private float selectedyold;//从前选中的圆点的y坐标
  private boolean ishasmoved = false;//用于判断path是否调用过moveto()方法
  @override
  public boolean ontouchevent(motionevent event) {
    switch (event.getaction()) {
      case motionevent.action_down:
        pivotx = event.getx();
        pivoty = event.gety();
        //每次触屏时需要清空一下pointerslipped,即重置密码
        pointerslipped.clear();
        log.d("pointtouched", pivotx + "," + pivoty);
        getselectedpointindex(pivotx, pivoty);
        invalidate();//重绘
        break;
      case motionevent.action_move:
        pivotx = event.getx();
        pivoty = event.gety();
        getselectedpointindex(pivotx, pivoty);
        invalidate();
        break;
      case motionevent.action_up:
        /**
         * 当手指离开屏幕时,重置path
         */
        path.reset();
        ishasmoved = false;
        string indexsequence = "";
        //打印出上一次手势密码的值
        for(int index:pointerslipped){
          indexsequence += "/"+index;
        }
        log.d("index",indexsequence);
        break;
    }
    invalidate();
    return true;
  }
  /**
   * 得到并存储经过的圆点的序号
   * @param pivotx
   * @param pivoty
   */
  private void getselectedpointindex(float pivotx, float pivoty) {
    int index = 0;
    if (pivotx > patternmargin && pivotx < patternmargin + bigcircleradius * 2) {
      if (pivoty > height / 2 && pivoty < height / 2 + bigcircleradius * 2) {
        selectedx = pointcontainer.get(1)[0];
        selectedy = pointcontainer.get(1)[1];
        index = 1;
        log.d("selectedpoint", selectedx + "," + selectedy);
      } else if (pivoty > height / 2 + added && pivoty < height / 2 + added + bigcircleradius * 2) {
        selectedx = pointcontainer.get(4)[0];
        selectedy = pointcontainer.get(4)[1];
        index = 4;
      } else if (pivoty > height / 2 + added * 2 && pivoty < height / 2 + added * 2 + bigcircleradius * 2) {
        selectedx = pointcontainer.get(7)[0];
        selectedy = pointcontainer.get(7)[1];
        index = 7;
      }
    } else if (pivotx > patternmargin + added && pivotx < patternmargin + added + bigcircleradius * 2) {
      if (pivoty > height / 2 && pivoty < height / 2 + bigcircleradius * 2) {
        selectedx = pointcontainer.get(2)[0];
        selectedy = pointcontainer.get(2)[1];
        index = 2;
      } else if (pivoty > height / 2 + added && pivoty < height / 2 + added + bigcircleradius * 2) {
        selectedx = pointcontainer.get(5)[0];
        selectedy = pointcontainer.get(5)[1];
        index = 5;
      } else if (pivoty > height / 2 + added * 2 && pivoty <height / 2 + added * 2 + bigcircleradius * 2) {
        selectedx = pointcontainer.get(8)[0];
        selectedy = pointcontainer.get(8)[1];
        index = 8;
      }
    } else if (pivotx > patternmargin + added * 2 && pivotx < patternmargin + added * 2 + bigcircleradius * 2) {
      if (pivoty > height / 2 && pivoty < height / 2 + bigcircleradius * 2) {
        selectedx = pointcontainer.get(3)[0];
        selectedy = pointcontainer.get(3)[1];
        index = 3;
      } else if (pivoty > height / 2 + added && pivoty < height / 2 + added + bigcircleradius * 2) {
        selectedx = pointcontainer.get(6)[0];
        selectedy = pointcontainer.get(6)[1];
        index = 6;
      } else if (pivoty > height / 2 + added * 2 && pivoty < height / 2 + added * 2 + bigcircleradius * 2) {
        selectedx = pointcontainer.get(9)[0];
        selectedy = pointcontainer.get(9)[1];
        index = 9;
      }
    }
    if (selectedx!=selectedxold||selectedy!=selectedyold){
      //当这次的坐标与上次的坐标不同时存储这次点序号
      pointerslipped.add(index);
      selectedxold = selectedx;
      selectedyold = selectedy;
      if (!ishasmoved){
        //当第一次触碰到九个点之一时,path调用moveto;
        path.moveto(selectedx,selectedy);
        ishasmoved = true;
      }else{
        //path移动至当前圆点坐标
        path.lineto(selectedx,selectedy);
      }
    }
  }
  private string text = "请绘制解锁图案";
  private float x;//绘制的圆形的x坐标
  private float y;//绘制圆形的纵坐标
  private float added;//水平竖直方向每个圆点中心间距
  private float patternmargin = 100;//九宫格距离边界距离
  private float bigcircleradius = 90;//外圆半径
  private float smallcircleradius = 25;//内圆半径
  private int index;//圆点的序号
  @override
  protected void ondraw(canvas canvas) {
    super.ondraw(canvas);
    added = (width - patternmargin * 2) / 3;
    x = patternmargin + added / 2;
    y = added / 2 + height / 2;
    index = 1;
    canvas.drawcolor(color.black);
    canvas.drawtext(text, width / 2, height / 4, mpainttext);
    /**
     * 绘制九个圆点图案
     */
    for (int column = 0; column < 3; column++) {
      for (int row = 0; row < 3; row++) {
        canvas.drawcircle(x, y, bigcircleradius, mpaintbigcircle);
        canvas.drawcircle(x, y, smallcircleradius, mpaintsmallcircle);
        pointcontainer.put(index, new float[]{x, y});
        index++;
        x += added;
      }
      y += added;
      x = patternmargin + added / 2;
    }
    x = patternmargin + added / 2;
    y = added / 2 + height / 2;
    canvas.drawpath(path, mpaintline);
  }
}

为什么要规避重复?

因为在触屏时,会调用很多次ontouchevent()方法,这样存储的手势密码肯定会不准确,我在以上代码中作出了处理,已经避免了重复,看打印信息:

这里写图片描述

显然,密码没有相邻数重复,当然还有一种情况就是手指在两个点之间来回等问题,这种状况也需要避免,这里没有作处理。当然,我做得还不够。。。

自定义view中用到的dp和px互相转换的工具类:

public class sizeconvert {
  /**
   * 将dp转换为sp
   */
  public static int dip2px(context context, float dipvalue){
    final float scale = context.getresources().getdisplaymetrics().density;
    return (int)(dipvalue * scale + 0.5f);
  }
  /**
   * sp转dp
   */
  public static int px2dip(context context, float pxvalue){
    final float scale = context.getresources().getdisplaymetrics().density;
    return (int)(pxvalue / scale + 0.5f);
  }
}

主活动:

public class ninegridactivity extends baseactivity{
  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.view_nine_grid);
  }
}

layout中的布局文件view_nine_grid:

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
  <com.test.shiweiwei.myproject.selfish_view.ninegridview
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
</linearlayout>

总结

我写的只是最基本的九宫格滑动解密项目,实际用的九宫格解密比这个要复杂,有许多特效和其他更严谨的处理,事件的处理也不是这样草草了事,如果想写得漂亮,还得多花工夫。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网