思路:

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. SQL Server 2005 企业版没有 Microsoft SQL Server Management

    我从网上下载的:SQL Server 2005 集成sp2的 企业版安装后没发现 Management Studio管理工具,起初以为是自己安装时没装上,昨天试了全部安装后还是没找到,很是郁闷,在网上 ...

  2. maven到Gradle,一些对比和分享

    Gradle作为一款基于Groovy语言的构建工具,已经吸引众多的ant,maven使用者转投gradle的怀抱,和Gradle相比,ant显得冗余复杂,maven显得有些死板落后,而gradle基于 ...

  3. 语音识别ASR - HTK(HResults)计算字错率WER、句错率SER

    HResults计算字错率(WER).句错率(SER) 前言 好久没发文,看到仍有这么多关注的小伙伴,觉得不发篇文对不住.确实好久没有输出经验总结相关的文档,抽了个时间,整理了下笔记,发一篇关于ASR ...

  4. Daily record-December

    December 11. All circles have the same shape. 所有圆的形状都是相同的.2. She first drew a circle on the board. 她 ...

  5. python3 发送gzip文件请求

    #condig=utf-8import requestsimport json,gzip def toGzipFormat(postData): data=bytes(json.dumps(postD ...

  6. vue学习02

    圆中圆: father: padding:6px width:56px height:56px border-radius:50% box-sizing:border-box son: width:1 ...

  7. [NOIP2013D2]

    T1 Problem 洛谷 Solution 这是线性扫描题吧. 就从1 ~ n 循环,若比起面高,则 ans += h[i] - h[i - 1]. Code #include<cmath&g ...

  8. Forth-83 多任务解析

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  9. 修改AD中PCB各层的透明度

    1.采用的Altium designer 版本为AD16: 2.进入PCB编辑页面,快捷键Ctrl+D,进入视图配置: 3.选择“透明度”,设置选中的层.对象所需的透明度:(横向可以连续选择多个对象, ...

  10. asp调用短信接口实现用户注册

    前几天做一个asp语言开发的网站需要实现用户注册短信验证功能,就研究了一下如何实现,简单给大家分享下调用过程. 首先需要找到一个第三方短信接口,当时用的是动力思维乐信的短信接口. 首先需要先注册个动力 ...