NJLockView.h /.m

@class NJLockView;

@protocol NJLockViewDelegate <NSObject>

- (void)lockViewDidClick:(NJLockView *)lockView andPwd:(NSString *)pwd;

@end

@interface NJLockView : UIView

@property (nonatomic, weak)IBOutlet id<NJLockViewDelegate> delegate;
@end
@interface NJLockView ()

@property (nonatomic, strong) NSMutableArray *buttons;
/**
* 定义属性,记录用户当前手指的位置(非按钮范围内)
*/
@property (nonatomic, assign) CGPoint currentPoint;
@end @implementation NJLockView - (NSMutableArray *)buttons
{
if (_buttons == nil) {
_buttons = [NSMutableArray array];
}
return _buttons;
} // 当视图是通过代码创建出来的就会调用initWithFrame
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
// NSLog(@"initWithFrame");
[self setup];
}
return self;
} // 当视图从xib或storyboard中创建出来就会调用
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
// 创建9个按钮
// NSLog(@"initWithCoder");
[self setup]; }
return self;
} /**
* 创建9个按钮添加到自定view中
*/
- (void)setup
{
for (int i = ; i < ; i++) {
// 1.创建按钮
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
// 2.设置按钮的背景图片
[btn setBackgroundImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal]; [btn setBackgroundImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected]; // 3.添加按钮到View
[self addSubview:btn]; // btn.backgroundColor = [UIColor redColor]; // 4.禁止按钮的点击事件(因为我们需要监听触摸事件)
btn.userInteractionEnabled = NO; // 5.设置按钮的tag作为唯一标识
btn.tag = i;
}
} - (void)layoutSubviews
{
[super layoutSubviews];
// 设置按钮的frame
for (int i = ; i < self.subviews.count; i++) {
// 1.取出对应位置的按钮
UIButton *btn = self.subviews[i]; // 2.设置frame
CGFloat btnW = ;
CGFloat btnH = ;
// 2.1计算间距
CGFloat margin = (self.frame.size.width - ( * btnW)) / ;
int col = i % ; // 列号
int row = i / ; // 行号
// 间距 + 列号 * (按钮宽度+ 间距)
CGFloat btnX = margin + col * (btnW + margin);
CGFloat btnY = margin + row * (btnW + margin); btn.frame = CGRectMake(btnX, btnY, btnW, btnH);
} } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// 1.获取按下的点
CGPoint startPoint = [self getCurrentTouchPoint:touches]; // 2.判断触摸的位置是否在按钮的范围内
UIButton *btn = [self getCurrentBtnWithPoint:startPoint]; // 存储按钮
if (btn)
{
// 设置选中状态
btn.selected = YES;
// 将按钮保存到数组中
[self.buttons addObject:btn];
} btn.selected = YES; // [self setNeedsDisplay]; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// 1.获取按下的点
CGPoint movePoint = [self getCurrentTouchPoint:touches];
// 2.获取触摸的按钮
UIButton *btn = [self getCurrentBtnWithPoint:movePoint]; // 存储按钮
if (btn && btn.selected != YES)
{
// 设置选中状态
btn.selected = YES;
// 将按钮保存到数组中
[self.buttons addObject:btn];
}
// 记录当前手指移动的位置
self.currentPoint = movePoint; // 通知view绘制线段
[self setNeedsDisplay]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{ // 取出用户输入的密码
NSMutableString *result = [NSMutableString string];
for (UIButton *btn in self.buttons) {
[result appendFormat:@"%d", btn.tag ];
}
// NSLog(@"result = %@", result);
// 通知代理,告诉代理用户输入的密码
if ([self.delegate respondsToSelector:@selector(lockViewDidClick:andPwd:)]) {
[self.delegate lockViewDidClick:self andPwd:result];
} [self.buttons makeObjectsPerformSelector:@selector(setSelected:) withObject:@(NO)]; // 清空数组
[self.buttons removeAllObjects];
[self setNeedsDisplay]; // 清空currentPoint
self.currentPoint = CGPointZero;
} - (void)drawRect:(CGRect)rect
{ CGContextRef ctx = UIGraphicsGetCurrentContext(); // 清空上下文
CGContextClearRect(ctx, rect); // 从数组中取出所有的按钮, 连接所有按钮的中点
for (int i = ; i < self.buttons.count; i++) {
// 取出按钮
UIButton *btn = self.buttons[i];
if ( == i) {
CGContextMoveToPoint(ctx, btn.center.x, btn.center.y);
}else
{
CGContextAddLineToPoint(ctx, btn.center.x, btn.center.y);
}
} // 判断如果当前点是00就不会只
// if (!CGPointEqualToPoint(self.currentPoint, CGPointZero)) {
//
// // 当所有的按钮的中点都连接号之后再连接手指当前的位置
// CGContextAddLineToPoint(ctx, self.currentPoint.x, self.currentPoint.y);
// } // 判断数组中是否有按钮, 如果有按钮就有起点, 有起点就不会报错
if (self.buttons.count != ) { CGContextAddLineToPoint(ctx, self.currentPoint.x, self.currentPoint.y);
} // [[UIColor greenColor] set]; [[UIColor colorWithRed:/255.0 green:/255.0 blue:/255.0 alpha:0.5] set];
CGContextSetLineWidth(ctx, );
CGContextSetLineJoin(ctx, kCGLineJoinRound);
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextStrokePath(ctx);
} /**
* 根据系统传入的UITouch集合获取当前触摸的点
* @return 当初触摸的点
*/
- (CGPoint)getCurrentTouchPoint:(NSSet *)touches
{
// 1.获取按下的点
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:touch.view];
return point;
} /**
* 根据触摸点获取触摸到的按钮
* @return 触摸的按钮
*/
- (UIButton *)getCurrentBtnWithPoint:(CGPoint)point
{
// 2.判断触摸的位置是否在按钮的范围内
for (UIButton *btn in self.subviews) {
//
if (CGRectContainsPoint(btn.frame, point)) {
return btn;
}
}
return nil;
}
@end

调用

#import "NJViewController.h"
#import "NJLockView.h" @interface NJViewController ()<NJLockViewDelegate> @end @implementation NJViewController - (void)viewDidLoad
{
[super viewDidLoad]; } - (void)lockViewDidClick:(NJLockView *)lockView andPwd:(NSString *)pwd
{
NSLog(@"NJViewController %@", pwd);
} @end

IOS 九宫图解锁(封装)的更多相关文章

  1. Android入门第八篇之GridView(九宫图)

    本文来自http://blog.csdn.net/hellogv/ GridView跟ListView都是比较常用的多控件布局,而GridView更是实现九宫图的首选!本文就是介绍如何使用GridVi ...

  2. iOS开发拓展篇—封装音频文件播放工具类

    iOS开发拓展篇—封装音频文件播放工具类 一.简单说明 1.关于音乐播放的简单说明 (1)音乐播放用到一个叫做AVAudioPlayer的类 (2)AVAudioPlayer常用方法 加载音乐文件 - ...

  3. iOS启动图和开屏广告图,类似网易

    iOS启动图和开屏广告图,类似网易 启动图是在iOS开发过程中必不可少的一个部分,很多app在启动图之后会有一张自定义的开屏广告图,点击该广告图可以跳转到广告图对应的页面.今天呢,和大家分享一下如何添 ...

  4. cocos2d-x创建的九宫图变白块

    用UIImageView 创建的九宫图变白,直接用CCScale9Sprite创建的也是变白,找了半天原来是自己为了调整UI方便,开启了CCSprite边缘画线导致的,在ccConfig.h下 宏CC ...

  5. Android GridView(九宫图)

    GridView跟ListView都是比较常用的多控件布局,而GridView更是实现九宫图的首选! <?xml version="1.0" encoding="u ...

  6. Qt实现九宫图类控件

    <1>. 头文件(类声明) class CPreviewWidge : public QWidget { Q_OBJECT public: CPreviewWidge( ); ~CPrev ...

  7. iOS多图上传

    iOS多图上传涉及到多线程问题,个人比较喜欢使用GCD操作,下边是最近写的一个多图上传代码,附带相关注释 __block BOOL allSucc = YES; __block int m = 0; ...

  8. swift3.0  代码创建经典界面的九宫图--优化篇

    在上一篇只是简单实现了九宫图效果,本章需要形成APP界面九宫图效果 override func viewDidLoad() { super.viewDidLoad() createnine() } / ...

  9. 基于iOS 10、realm封装的下载器

    代码地址如下:http://www.demodashi.com/demo/11653.html 概要 在决定自己封装一个下载器前,我本以为没有那么复杂,可在实际开发过程中困难重重,再加上iOS10和X ...

随机推荐

  1. Ubuntu16.04启动xtion pro live报错

    william@william-System-Product-Name:~$ roslaunch openni2_launch openni2.launch ... logging to /home/ ...

  2. Head First Python 1-4章学习感悟

    一.学习知识总结 (1)迭代         range(起始值,结束值,步长):包含起始值,不包含结束值,步长为正数 (2)导入模块 from datetime import datetime (3 ...

  3. Perfect service(树形dp)

    Perfect service(树形dp) 有n台机器形成树状结构,要求在其中一些机器上安装服务器,使得每台不是服务器的计算机恰好和一台服务器计算机相邻.求服务器的最小数量.n<=10000. ...

  4. 在Linux系统下远程连接oracle的防火墙设置

    在Linux系统要远程连接Oracle的防火墙设置方法: 打开5801至5810 端口用于vnc iptables -I INPUT -p tcp --dport 5801:5810 -j ACCEP ...

  5. RRTI的概念以及Class对象作用

    深入理解Class对象 RRTI的概念以及Class对象作用 认识Class对象之前,先来了解一个概念,RTTI(Run-Time Type Identification)运行时类型识别,对于这个词一 ...

  6. 「BZOJ3600」没有人的算术 替罪羊树+线段树

    题目描述 过长--不想发图也不想发文字,所以就发链接吧-- 没有人的算术 题解 \(orz\)神题一枚 我们考虑如果插入的数不是数对,而是普通的数,这就是一道傻题了--直接线段树一顿乱上就可以了. 于 ...

  7. Technical support website

    Technical support:Please leave a message if you have any questions or suggestions. email: swvrwafet@ ...

  8. 你的php

    最开始学习做网页,用的是HTML,现在开始php了,那么要想用php,首先你得安装对不对,那么问题来了,你上哪安去啊(一看小编就是东北人),那么小编给各位提供了两个链接(不要告诉其他人哦)https: ...

  9. mysql CPU占用高

    https://blog.csdn.net/u011239989/article/details/72863333 QPS高,sql简单的场景下, 需要 1. 提高数据库的服务器性能CPU 内存等 2 ...

  10. 20-----定位 (Position)

    定位 定位有三种: 1.相对定位 2.绝对定位 3.固定定位 这三种定位,每一种都暗藏玄机,所以我们要一一单讲. 相对定位 相对定位:相对于自己原来的位置定位 现象和使用: 1.如果对当前元素仅仅设置 ...