Android自定义UI手势密码简单版

先看看效果图:

ImageLockActivity

package com.example.imagelock; 

import com.example.view.NinePointLineView; 

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View; 

public class ImageLockActivity extends Activity { 

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    View v = new NinePointLineView(this);
    setContentView(v);
  }
}

NinePointLineView

package com.example.view; 

import com.example.imagelock.R; 

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast; 

public class NinePointLineView extends View { 

  /**
   * 定义3个Paint,还有一个坐标圆点图片
   */
  Paint linePaint = new Paint();
  Paint whiteLinePaint = new Paint();
  Paint textPaint = new Paint();
  Bitmap defaultBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.lock); 

  PointInfo[] points = new PointInfo[9];
  int width, height;
  //坐标点的半径长度
  int defaultBitmapRadius = defaultBitmap.getWidth() / 2; 

  //绘制密码时候出现的原点的直径,半径
  Bitmap selectedBitmap = BitmapFactory.decodeResource(getResources(),
      R.drawable.indicator_lock_area);
  int selectedBitmapDiameter = selectedBitmap.getWidth();
  int selectedBitmapRadius = selectedBitmapDiameter / 2; 

  StringBuffer lockString = new StringBuffer(); 

  Context context;
  /** 构造器*********************************************/
  public NinePointLineView(Context context) {
    super(context);
    this.context = context;
    this.setBackgroundColor(Color.WHITE);
    initPaint();
  } 

  public NinePointLineView(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.context = context;
    this.setBackgroundColor(Color.WHITE);
    initPaint();
  }
  private void initPaint() {
    //线--包裹9个原点
    linePaint.setColor(Color.RED);
    linePaint.setStrokeWidth(defaultBitmap.getWidth());
    linePaint.setAntiAlias(true);
    linePaint.setStrokeCap(Cap.ROUND);
    //线内--比原点直径少5
    whiteLinePaint.setColor(Color.GREEN);
    whiteLinePaint.setStrokeWidth(defaultBitmap.getWidth() - 5);
    whiteLinePaint.setAntiAlias(true);
    whiteLinePaint.setStrokeCap(Cap.ROUND);
    //字体设置
    textPaint.setTextSize(30);
    textPaint.setAntiAlias(true);
    textPaint.setTypeface(Typeface.MONOSPACE);
  } 

  /**********************************************************
   * 测量
   */
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    width = getWidth();
    height = getHeight();
    if (width != 0 && height != 0) {
      initPoints(points);
    }
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  } 

  /**
   * 初始化原点
   */
  private void initPoints(PointInfo[] points) { 

    int len = points.length; 

    //2个原点的间距
    int seletedSpacing = (width - selectedBitmapDiameter * 3) / 4; 

    //第1个原点的坐标
    int seletedX = seletedSpacing;
    int seletedY = height - width + seletedSpacing; 

    //第1个原点内部的小圆的坐标
    int defaultX = seletedX + selectedBitmapRadius - defaultBitmapRadius;
    int defaultY = seletedY + selectedBitmapRadius - defaultBitmapRadius; 

    for (int i = 0; i < len; i++) {
      //第4、7个原点
      if (i == 3 || i == 6) {
        seletedX = seletedSpacing;
        //第一个原点y坐标+直径+2点间距离
        seletedY += selectedBitmapDiameter + seletedSpacing; 

        defaultX = seletedX + selectedBitmapRadius
            - defaultBitmapRadius;
        //第一个原点y坐标+直径+2点间距离
        defaultY += selectedBitmapDiameter + seletedSpacing; 

      }
      points[i] = new PointInfo(i, defaultX, defaultY, seletedX, seletedY); 

      //原点坐标xy为直径+2点间距离
      seletedX += selectedBitmapDiameter + seletedSpacing;
      defaultX += selectedBitmapDiameter + seletedSpacing; 

    }
  }
  /*****************************************************************/
  @Override
  protected void onLayout(boolean changed, int left, int top, int right,
      int bottom) {
    super.onLayout(changed, left, top, right, bottom);
  } 

  private int startX = 0, startY = 0;
  PointInfo startPoint = null;
  @Override
  protected void onDraw(Canvas canvas) { 

    drawNinePoint(canvas); 

    super.onDraw(canvas);
  }
  /**
   *
   * @param canvas
   */
  private void drawNinePoint(Canvas canvas) { 

    if (startPoint != null) {
      drawEachLine(canvas, startPoint);
    } 

    for(PointInfo pointInfo : points) {
      if (pointInfo!=null) { 

        if (pointInfo.isSelected()) {
          canvas.drawBitmap(selectedBitmap, pointInfo.getSeletedX(),pointInfo.getSeletedY(), null);
        }
        canvas.drawBitmap(defaultBitmap, pointInfo.getDefaultX(),pointInfo.getDefaultY(), null);
      }
    } 

  }
  private void drawEachLine(Canvas canvas, PointInfo point) {
    if (point.hasNextId()) {
      int n = point.getNextId();
      drawLine(canvas, point.getCenterX(), point.getCenterY(),
          points[n].getCenterX(), points[n].getCenterY());
      drawEachLine(canvas, points[n]);
    }
  } 

  private void drawLine(Canvas canvas, float startX, float startY,
      float stopX, float stopY) {
    canvas.drawLine(startX, startY, stopX, stopY, linePaint);
    canvas.drawLine(startX, startY, stopX, stopY, whiteLinePaint);
  }
/**
 * ********************************************************************
 */
  boolean isUp = false;
  int moveX, moveY;
  @Override
  public boolean onTouchEvent(MotionEvent event) { 

    boolean flag = true;
    //isUp默认是false--绘制是否完毕,此时为true
    if (isUp) {
      finishDraw(); 

      Toast.makeText(context, "绘制完毕,手指离开,在点击", 0).show();
      flag = false; 

    } else {
      handlingEvent(event);
      flag = true;
      Toast.makeText(context, "手指一旦绘制", 0).show(); 

    }
    //是否处理事件
    return flag;
  }
  private void finishDraw() {
    for (PointInfo temp : points) {
      temp.setSelected(false);
      temp.setNextId(temp.getId());
    }
    lockString.delete(0, lockString.length());
    isUp = false;
    invalidate();
  } 

  private void handlingEvent(MotionEvent event) {
    switch (event.getAction()) {
    case MotionEvent.ACTION_MOVE:
      moveX = (int) event.getX();
      moveY = (int) event.getY();
      for (PointInfo temp : points) {
        if (temp.isInMyPlace(moveX, moveY) && temp.isSelected()==false) {
          temp.setSelected(true);
          startX = temp.getCenterX();
          startY = temp.getCenterY();
          int len = lockString.length();
          if (len != 0) {
            int preId = lockString.charAt(len - 1) - 48;
            points[preId].setNextId(temp.getId());
          }
          lockString.append(temp.getId());
          break;
        }
      }
      invalidate();
      break; 

    case MotionEvent.ACTION_DOWN:
      //获取按下的xy坐标
      int downX = (int) event.getX();
      int downY = (int) event.getY();
      for (PointInfo temp : points) {
        //如果符合距离范围内
        if (temp.isInMyPlace(downX, downY)) {
          //将其设置为选中状态
          temp.setSelected(true);
          //将选中的圆点设置为起始位置圆点
          startPoint = temp;
          //将其圆心作为起始点
          startX = temp.getCenterX();
          startY = temp.getCenterY();
          lockString.append(temp.getId());
          break;
        }
      }
      invalidate();
      break; 

    case MotionEvent.ACTION_UP:
      startX = startY = moveX = moveY = 0;
      //绘制完毕
      isUp = true;
      invalidate();
      break;
    default:
      break;
    }
  } 

  /**
   * 原点bean
   */
  private class PointInfo {
    private boolean selected; 

    private int id; 

    private int nextId; 

    private int defaultX; 

    private int defaultY; 

    private int seletedX; 

    private int seletedY; 

    public PointInfo(int id, int defaultX, int defaultY, int seletedX,
        int seletedY) {
      this.id = id;
      this.nextId = id;
      this.defaultX = defaultX;
      this.defaultY = defaultY;
      this.seletedX = seletedX;
      this.seletedY = seletedY;
    } 

    public boolean isSelected() {
      return selected;
    } 

    public void setSelected(boolean selected) {
      this.selected = selected;
    } 

    public int getId() {
      return id;
    } 

    public int getDefaultX() {
      return defaultX;
    } 

    public int getDefaultY() {
      return defaultY;
    } 

    public int getSeletedX() {
      return seletedX;
    } 

    public int getSeletedY() {
      return seletedY;
    } 

    public int getCenterX() {
      return seletedX + selectedBitmapRadius;
    } 

    public int getCenterY() {
      return seletedY + selectedBitmapRadius;
    } 

    public boolean hasNextId() {
      return nextId != id;
    } 

    public int getNextId() {
      return nextId;
    } 

    public void setNextId(int nextId) {
      this.nextId = nextId;
    } 

    /**
     * 如果某个xy值在某个原点的左右上下范围内,就说明ok
     */
    public boolean isInMyPlace(int x, int y) {
      boolean inX = x > seletedX
          && x < (seletedX + selectedBitmapDiameter);
      boolean inY = y > seletedY
          && y < (seletedY + selectedBitmapDiameter); 

      return (inX && inY);
    } 

  } 

} 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android 简易手势密码开源库详解

    简介 本文介绍一个Android手势密码开源库的使用及实现的详细过程,该开源库主要实现以下几个功能: 支持手势密码的绘制,并支持密码保存功能,解锁时自动比对密码给出结果 封装了绘制密码的方法,比对两次密码是否一致,可以快捷地进行手势密码的设置 可以设置密码输入错误后的重试次数上限 可以自定义不同状态下手势密码图案的颜色 可以自定义手势密码的触摸点数量(n*n) 最近需要用到手势密码解锁功能,找了一些demo感觉用起来都有点麻烦,于是参考一些文章自己造了下轮子,封装了相关的一些方法,使用起来比较便

  • Android自定义UI手势密码改进版源码下载

    在之前文章的铺垫下,再为大家分享一篇:Android手势密码,附源码下载,不要错过. 源码下载:http://xiazai.jb51.net/201610/yuanma/androidLock(jb51.net).rar 先看第一张图片的布局文件 activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://sc

  • Android仿支付宝手势密码解锁功能

    Starting 创建手势密码可以查看 CreateGestureActivity.java 文件. 登陆验证手势密码可以看 GestureLoginActivity.java 文件. Features 使用了 JakeWharton/butterknife butterknife 使用了 ACache 来存储手势密码 /** * 保存手势密码 */ private void saveChosenPattern(List<LockPatternView.Cell> cells) { byte[

  • Android自定义UI手势密码终结版

    之前写过3篇手势密码的demo,不过没有集成到真实的企业项目中,这几天正好领到一个手势密码项目,昨天刚好弄完,今天抽空整理下,目前还没有完善,有一些地方需要更改,不过基本的流程都可以跑通了. 源码下载地址:http://xiazai.jb51.net/201610/yuanma/AndroidGestureLock(jb51.net).rar 先看主界面的入口把.里面有2个button(一个是设置手势密码.一个是校验手势密码) activity_main.xml <RelativeLayout

  • Android手势密码view学习笔记(一)

    刚接触Android的时候看到别人写的手势密码view,然后当时就在想,我什么时候才能写出如此高端的东西?? 没关系,不要怕哈,说出这样话的人不是你技术不咋地而是你不愿意花时间去研究它,其实也没有那么难哦(世上无难事,只怕有心人!),下面我们就一步一步实现一个手势密码view. 想必都看过手势密码view,但我们还是看看我们今天要实现的效果吧: 上面是一个手势view的提示view,下面是一个手势view. 用法: <com.leo.library.view.GestureContentView

  • Android手势密码实现实例代码

    一.效果实现 二.实现思路: 1. 正上方的提示区域,用一个类(LockIndicator.java)来实现,自定义view来绘制9个提示图标: 2. 手势密码绘制区域,用一个类(GestureContentView.java)来实现,它继承自ViewGroup里面, 添加9个ImageView来表示图标, 在onLayout()方法中设置它们的位置: 3. 手势路径绘制, 用一个类(GestureDrawline.java)来实现,复写onTouchEvent()方法,在这个方法里面监听Tou

  • Android手势密码的实现

    一.大致界面介绍: 图1 图2 图3 图4 图1:手势密码绘制界面 [主要是绘制上方的9个提示图标和9个宫格密码图标] 图2:设置手势密码 [监听手势的输入,TouchEvent的事件处理,获取输入的手势密码,同时显示在上方的提示区域] 图3:再绘制一次,两次密码不一致提示界面 [这里在实现的时候,错误提示文字加了"左右晃动的动画",错误路径颜色标记为红色] 图4:校验手势密码,输入的密码错误,给予红色路径+错误文字提示 二.实现思路: 1. 正上方的提示区域,用一个类(LockInd

  • Android手势密码view学习笔记(二)

    我们还是接着我们上一篇博客中的内容往下讲哈,上一节 Android手势密码view笔记(一)我们已经实现了我们的IndicatorView指示器view了: 下面我们来实现下我们的手势密码view: 实现思路: 1.我们照样需要拿到用户需要显示的一些属性(行.列.选中的图片.未选中的图片.错误显示的图片.连接线的宽度跟颜色......). 2.我们需要根据手势的变换然后需要判断当前手指位置是不是在某个点中,在的话就把该点设置为选中状态,然后每移动到两个点(也就是一个线段)就记录该两个点. 3.最

  • Android自定义控件实现手势密码

    Android手势解锁密码效果图 首先呢想写这个手势密码的想法呢,完全是凭空而来的,然后笔者就花了一天时间弄出来了.本以为这个东西很简单,实际上手的时候发现,还有很多逻辑需要处理,稍不注意就容易乱套.写个UI效果图大约只花了3个小时,但是处理逻辑就处理了2个小时!废话不多说,下面开始讲解.      楼主呢,自己比较自定义控件,什么东西都掌握在自己的手里感觉那是相当不错(对于赶工期的小伙瓣儿们还是别手贱了,非常容易掉坑),一有了这个目标,我就开始构思实现方式.      1.整个自定义控件是继承

  • Android自定义UI手势密码改进版

    接着第一个Android UI手势密码设计的基础上继续改进,效果图如下 activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layo

随机推荐