思路:

1.画9个按钮,通过按钮的选中状态控制按钮.

2.连线通过贝塞尔曲线绘制.

3.校验密码通过给按钮绑定tag值判断.

主要代码:

OC版本:

 //
// NineLockView.m
// lockView
//
// Created by Shaoting Zhou on 2018/1/24.
// Copyright © 2018年 Shaoting Zhou. All rights reserved.
// #import "NineLockView.h" CGFloat const btnCount = ; //九宫格个数
CGFloat const btnW = ; //单个按钮宽
CGFloat const btnH = ; //单个按钮高
CGFloat const viewY = ; //视图Y
int const columnCount = ; //列数
#define kScreenWidth [UIScreen mainScreen].bounds.size.width @interface NineLockView ()
@property (nonatomic, strong) NSMutableArray * selectBtnsAry; //选中按钮的数组
@property (nonatomic, assign) CGPoint currentPoint; //当前的点 坐标 用于判断最后一个点
@end @implementation NineLockView -(NSMutableArray *)selectBtnsAry{
if(!_selectBtnsAry){
_selectBtnsAry = [NSMutableArray array];
}
return _selectBtnsAry;
} //通过代码布局时会调用这个方法
-(instancetype)initWithFrame:(CGRect)frame{
if(self = [super initWithFrame:frame]){
self.backgroundColor = [UIColor clearColor];
[self addButton];
}
return self;
} //通过sb xib布局时会调用这个方法
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
if(self = [super initWithCoder:aDecoder]){
[self addButton];
}
return self;
} #pragma Mark - 布局按钮
- (void)addButton{
CGFloat height = ;;
for (int i = ; i < btnCount; i++) {
UIButton * btn = [UIButton buttonWithType:(UIButtonTypeCustom)];
btn.tag = i;
btn.userInteractionEnabled = NO; //不可交互
//设置默认的图片
[btn setBackgroundImage:[UIImage imageNamed:@"gesture_normal"] forState:(UIControlStateNormal)];
//设置选中的图片
[btn setBackgroundImage:[UIImage imageNamed:@"gesture_selected"] forState:(UIControlStateSelected)];
int row = i / columnCount; //第几行
int column = i % columnCount; //第几列
CGFloat margin = (self.frame.size.width - columnCount * btnW) / (columnCount + ); //边距
CGFloat btnX = margin + column * (btnW + margin); //x轴
CGFloat btnY = row * (btnW + margin); //y轴
// btn.backgroundColor =[UIColor redColor];
btn.frame = CGRectMake(btnX, btnY, btnW, btnH);
height = btnH + btnY; //视图高等于 最后一个点的高+y
[self addSubview:btn];
}
self.frame = CGRectMake(, viewY, kScreenWidth, height); //视图frame
} - (CGPoint)pointWithTouch:(NSSet *)touches{
UITouch * touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
return point;
}
- (UIButton *)buttonWithPoint:(CGPoint)point{
for (UIButton * btn in self.subviews) {
if(CGRectContainsPoint(btn.frame, point)){
return btn;
}
}
return nil;
} #pragma Mark - 开始移动
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//1.拿到触摸的点
CGPoint point = [self pointWithTouch:touches];
//2.根据触摸的点拿到相应的按钮
UIButton * btn = [self buttonWithPoint:point];
//3.设置状态
if(btn && btn.selected == NO){
btn.selected = YES;
[self.selectBtnsAry addObject:btn];
} } #pragma Mark - 移动中
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//1.拿到触摸的点
CGPoint point = [self pointWithTouch:touches];
//2.根据触摸的点拿到相应的按钮
UIButton * btn = [self buttonWithPoint:point];
//3.设置状态
if(btn && btn.selected == NO){
btn.selected = YES;
[self.selectBtnsAry addObject:btn];
}else{
self.currentPoint = point;
}
[self setNeedsDisplay];
} #pragma Mark - 结束移动
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
if([self.delegete respondsToSelector:@selector(lockView:didFinishPath:)]){
NSMutableString * path = [NSMutableString string];
for (UIButton * btn in self.selectBtnsAry) {
[path appendFormat:@"%ld",(long)btn.tag];
}
[self.delegete lockView:self didFinishPath:path];
}
//清空状态
for(int i = ; i < self.selectBtnsAry.count; i++ ){
UIButton * button = self.selectBtnsAry[i];
button.selected = NO;
}
[self.selectBtnsAry removeAllObjects];
[self setNeedsDisplay];
} #pragma Mark - 取消移动
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self touchesEnded:touches withEvent:event];
} #pragma Mark - 绘图
- (void)drawRect:(CGRect)rect{
if(self.selectBtnsAry.count == ){
return;
}
UIBezierPath * path = [UIBezierPath bezierPath];
path.lineWidth = ;
path.lineJoinStyle = kCGLineJoinRound;
[[UIColor colorWithRed:/255.0 green:/255.0 blue:/255.0 alpha:0.5] set];
//遍历按钮
for(int i = ; i < self.selectBtnsAry.count; i++ ){
UIButton * button = self.selectBtnsAry[i];
NSLog(@"%d",i);
if(i == ){
//设置起点
[path moveToPoint:button.center];
}else{
//连线
[path addLineToPoint:button.center];
} }
[path addLineToPoint:self.currentPoint]; //最后一点 连接自己
[path stroke]; } @end

OC版本

 //
// ViewController.m
// lockView
//
// Created by Shaoting Zhou on 2018/1/24.
// Copyright © 2018年 Shaoting Zhou. All rights reserved.
// #import "ViewController.h"
#import "NineLockView.h" #define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height @interface ViewController () <NineLockViewDelegate> @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor brownColor];
NineLockView * lockView = [[NineLockView alloc]initWithFrame:CGRectMake(, , kScreenWidth, kScreenHeight)];
lockView.delegete = self;
[self.view addSubview:lockView];
} -(void)lockView:(NineLockView *)lockView didFinishPath:(NSString *)path{
if(path.length <= ){
NSLog(@"请至少连4个点");
return;
}
if([path isEqualToString:@""]){
NSLog(@"OK");
}else{
NSLog(@"error");
}
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} @end

OC版本

swift版本:

 //
// ViewController.swift
// lockView-Swift
//
// Created by Shaoting Zhou on 2018/1/25.
// Copyright © 2018年 Shaoting Zhou. All rights reserved.
// import UIKit class ViewController: UIViewController,nineLockViewDelegate { let kScreenHeight = UIScreen.main.bounds.size.height
let kScreenWidth = UIScreen.main.bounds.size.width
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.brown
let nineLockView = NineLockView.init(frame: CGRect.init(x: 0, y: 0, width: kScreenWidth, height: kScreenHeight))
nineLockView.delegate = self
self.view.addSubview(nineLockView) // Do any additional setup after loading the view, typically from a nib.
}
//MARK: - 代理方法
func lockView(lockView: NineLockView, path: String) {
if(path.description.count < 4){
print("至少连4个");
return;
}
if(path == "01258"){
print("密码正确");
}else{
print("密码错误");
}
} override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
} }

Swift版本

 //
// NineLockView.swift
// lockView-Swift
//
// Created by Shaoting Zhou on 2018/1/25.
// Copyright © 2018年 Shaoting Zhou. All rights reserved.
// import UIKit let btnCount = 9; //九宫格个数
let btnW:CGFloat = 74.0; //单个按钮宽
let btnH:CGFloat = 74.0; //单个按钮高
let viewY:CGFloat = 300.0; //视图Y
let columnCount = 3; //列数
let kScreenHeight = UIScreen.main.bounds.size.height
let kScreenWidth = UIScreen.main.bounds.size.width //创建协议
protocol nineLockViewDelegate:NSObjectProtocol
{
func lockView(lockView:NineLockView,path:String)
} class NineLockView: UIView {
weak var delegate:nineLockViewDelegate?
var selectBtnsAry = [UIButton] ()
var currentPoint:CGPoint! override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.clear
self .addButton();
} // MARK: 添加按钮
func addButton(){
var height:CGFloat = 0.0
for var i in 0 ..< btnCount{
let btn = UIButton.init(type: .custom)
btn.setImage(#imageLiteral(resourceName: "gesture_normal"), for: .normal) //默认图片
btn.setImage(#imageLiteral(resourceName: "gesture_selected"), for: .selected) //选中图片
btn.tag = i
btn.isUserInteractionEnabled = false //取消用户交互
let row = i / columnCount //行数
let column = i % columnCount //列数
let margin:CGFloat = (self.frame.size.width - CGFloat(columnCount) * btnW) / CGFloat( (columnCount + 1)); //边距
let btnX:CGFloat = margin + CGFloat(column) * (btnW + margin); //x轴
let btnY:CGFloat = CGFloat(row) * (btnW + margin); //y轴
btn.frame = CGRect.init(x: btnX, y: btnY, width: btnW, height: btnH)
height = btnY + btnH //视图的高 = 最后一个按钮的高 + y
self.addSubview(btn)
}
self.frame = CGRect.init(x: 0, y: viewY, width: kScreenWidth, height: height)
} func pointWithTouch(touches:Set<UITouch>) -> CGPoint{
let touch:UITouch = (touches as NSSet).anyObject() as! UITouch
let point = touch.location(in: self)
return point;
}
func buttonWithPoint(point:CGPoint) -> UIButton?{
for var view:UIView in self.subviews {
let btn:UIButton = view as! UIButton
if(btn.frame.contains(point)){
return btn
}
}
return nil
} // MARK: 开始移动
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//1.拿到触摸的点
let point:CGPoint = self.pointWithTouch(touches: touches)
//2.根据触摸的点拿到相应的按钮
guard let btn:UIButton = self.buttonWithPoint(point: point) else{
return;
}
//3.设置状态
if(btn.isSelected == false){
btn.isSelected = true
self.selectBtnsAry.append(btn)
} } // MARK: 移动中
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
//1.拿到触摸的点
let point:CGPoint = self.pointWithTouch(touches: touches)
//2.根据触摸的点拿到相应的按钮
guard let btn:UIButton = self.buttonWithPoint(point: point) else{
return;
}
//3.设置状态
if(btn.isSelected == false){
btn.isSelected = true
self.selectBtnsAry.append(btn)
}else{
self.currentPoint = point;
}
self.setNeedsDisplay() }
// MARK: 移动停止
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if delegate != nil{
var str = "";
for var i in 0 ..< self.selectBtnsAry.count{
let btn:UIButton = self.selectBtnsAry[i]
str = str + String(btn.tag)
}
self.delegate?.lockView(lockView: self, path: str)
} for var i in 0 ..< self.selectBtnsAry.count{
let btn:UIButton = self.selectBtnsAry[i]
btn.isSelected = false
}
self.selectBtnsAry.removeAll()
self.setNeedsDisplay()
} // MARK: 移动取消
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
self.touchesEnded(touches, with: event)
} // MARK: 绘图
override func draw(_ rect: CGRect) {
if(self.selectBtnsAry.count == 0){
return;
}
let path:UIBezierPath = UIBezierPath.init()
path.lineWidth = 8
path.lineJoinStyle = .round
UIColor.init(red: 32/255.0, green: 210/255.0, blue: 254/255.0, alpha: 0.5).set()
//遍历按钮
for var i in 0 ..< self.selectBtnsAry.count{
let btn:UIButton = self.selectBtnsAry[i]
if(i == 0){
//起点
path.move(to: btn.center)
}else{
//划线
path.addLine(to: btn.center)
}
}
path.addLine(to: self.currentPoint) //最后一点 连接自己
path.stroke()
} required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
} }

Swift版本

基本演示:

这里的只演示下基本九宫格校验密码(密码已经存在:01258).

创建密码,修改密码思路类似.

github: https://github.com/pheromone/iOS-nineLock

iOS 九宫格解锁的更多相关文章

  1. appium 九宫格解锁招商银行手机客户端app

    之前研究了一段时间的appium for native app 相应的总结如下:                                            appium测试环境搭建 :ht ...

  2. App自动化(2)--Python&Appium实现安卓手机九宫格解锁

    九宫格作为常见的手势密码,我们在使用的时候,是从起点开始,按住不放,然后滑动手指,直到最后一个点松开手指,如果与设置的手势密码匹配,则解锁成功. 现在大多数九宫格作为一个元素存在,很难定位到每一个点. ...

  3. iOS 指纹解锁 验证TouchID

    iOS指纹解锁 1.首先,引入依赖框架 LocalAuthentication.framework #import <LocalAuthentication/LocalAuthenticatio ...

  4. iOS 九宫格手势密码

    代码地址如下:http://www.demodashi.com/demo/11490.html 一.准备工作 需要准备什么环境 xcode,iOS8+ 本例子实现什么功能 主要实现手势密码设置,验证 ...

  5. Android之九宫格解锁的实现

        <ignore_js_op>                                                  下面是最重要的那个LocusPassWordView ...

  6. uiautomator2 实现App九宫格解锁

    App九宫格解锁 之前在testerhome社区看见codeskyblue大佬写过一种方法,但是这种办法存在一个弊端,那就是多个点的坐标是写死的,也就是说要是换了部手机,九宫格解锁就行不通了,于是就想 ...

  7. Python+Appium自动化测试(10)-TouchAction类与MultiAction类(控件元素的滑动、拖动,九宫格解锁,手势操作等)

    滑动屏幕方法swipe一般用于对页面进行上下左右滑动操作,但自动化过程中还会遇到其他情况,如对控件元素进行滑动.拖拽操作,九宫格解锁,手势操作,地图的放大与缩小等.这些需要针对控件元素的滑动操作,或者 ...

  8. iOS开发 - Swift - 自己写的一个九宫格解锁的Demo

    前段时间做项目,公司要用到一个九宫格的手势解锁的需求. 虽然在很多地方都可以找到写好的第三方源码, 但是我的性格是不喜欢Ctrl+V的,于是自己凭着理解敲了一个出来,功能很简单,只是单纯的返回结果.附 ...

  9. IOS仿Android九宫格解锁效果[转]

    原理很简单,监听view中touch的一系列事件,当判定手指位置在某个按钮附近的时候则判断此按钮选中,并画出线. 效果图如下: 你可以在NineGridUnlockView.m文件中方法 touche ...

随机推荐

  1. Promise的两种处理异步的方式

    单个异步处理: let usedMemoryPromise = fetchUsedMemeory(); usedMemoryPromise.then(data => {...}) functio ...

  2. php国家或者编码英文字母排序

    1.直接复制传入需要排序的字符,然后可以把返回的数据当key,传送给前台function getFirstCharter($str){ if(empty($str)){return '';} $fch ...

  3. HIT2019春软件构造->重写hashCode()方法

    不需要重写equals方法: 1.     一个类的每一个实例本质上都是唯一的. 2.     不关心一个类是否提供了“逻辑相等”的测试功能 3.     超类已经改写了equals方法,并且从超类继 ...

  4. 开发中常用的es6知识

    结合实际开发,开发中常用的es6的知识: 1.新增let和const命令: ES6 新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效: cons ...

  5. 不同浏览器中scrollHeight的比较

    每个浏览器的兼容性不同所以就有了如下判断方案 document.body是DOM中Document对象里的body节点, document.documentElement是文档对象根节点(html)的 ...

  6. python数据结构与算法之问题求解

    懂得计算机的童鞋应该都知道,一条计算机程序由数据结构跟算法两大部分组成.所以,其实不管你使用哪种计算机语言编写程序,最终这两部分才是一个程序设计的核心.所以,一个不懂得数据结构与算法的程序员不是一个好 ...

  7. VNPY - windows 安装踩坑记录

    twisted requires PyHamcrest>=, which is not ins grin requires argparse>=1.1, which is not inst ...

  8. js设置radio单选框值选中

    html页面: <div> <label><input type="radio" name="sex" value="m ...

  9. git提交步骤

    1,为了确定在本地分支下操作,可以用命令查看一下是否在本地分支 git branch 2,可以查看状态,是否添加了哪些内容 git status 3,如果确认无误,使用命令进行提交本地代码,并加上注释 ...

  10. 面试北京XX数通总结

    软件架构师何志丹 1             总括 1.1     面试时间 2019年1月21号. 1.2     公司概况 员工近20人,其中开发人员6人,全部objectarx(C++),全部老 ...