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. Python中读取,显示,保存图片的方法

    一 opencv import cv2 as cv # load img = cv.imread(imagepath) # shape=(height, width, channel) h,w,c = ...

  2. SCUT - 337 - 岩殿居蟹 - 线段树 - 树状数组

    https://scut.online/p/337 这个东西是个阶梯状的.那么可以考虑存两棵树,一棵树是阶梯的,另一棵树的平的,随便一减就是需要的阶梯. 优化之后貌似速度比树状数组还惊人. #incl ...

  3. 浅谈JavaScript--this指向

    js中this的值取决于调用的模式 方法调用模式 var student={ name:"adoctors", showThis:function(){ console.log(t ...

  4. SSM整合文档

    SSM整合文档 v2 一. 文件说明 文件名 描述 spring-servlet.xml 配置SpringMvc框架相关 applicationContext.xml 配置Spring容器 sprin ...

  5. Java 实现大转盘抽奖

    需要用到 JAVA中的Random()函数 注意:大转盘抽奖各奖项中奖概率之和为 1.奖品列表中的概率为累加概率,需要按照添加进列表的顺序进行累加,添加顺序不做要求. 实际中使用需要考虑奖品数量限制等 ...

  6. SMTP服务器配置

    Windows Server 2012/2012 R2:安装和配置 SMTP 服务器 安装 SMTP 服务器 以下是安装 SMTP 服务器功能的步骤: 1. 打开“服务器管理器”:单击键盘上的 Win ...

  7. 7、python数据类型之集合set

    数据类型之集合setset 不允许重复的无序集合,不能通过下标取值,因为无序1.创建   创建空集合   s ={} 默认类型为字典,所以不是空集合,空集合如下   s = set()   s = { ...

  8. Java安装JDBC驱动教程(SQL Server系列)

    端口一般开放都没问题,默认设置就行,第一步下载JDBC,我自己在使用微软新的JDBC6.0的包的时候出错,后来就退回到JDBC4.0引用,完美使用. SQLJDBC4.0下载地址:点击下载 下载之后, ...

  9. .NET Core微服务 权限系统+工作流(二)工作流系统

    一.前言 接上一篇 .NET Core微服务 权限系统+工作流(一)权限系统 ,再来一发 工作流,我在接触这块开发的时候一直好奇它的实现方式,翻看各种工作流引擎代码,探究其实现方式,个人总结出来一个核 ...

  10. mybatis + log4j2 问题 java.lang.NoClassDefFoundError: org/apache/logging/log4j/spi/AbstractLoggerWrapper

    root cause java.lang.NoClassDefFoundError: org/apache/logging/log4j/spi/AbstractLoggerWrapper 网上资料比较 ...