思路:
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).
创建密码,修改密码思路类似.