0829-0612
0612
截屏
1、获取图片上下文
2、view的layer 渲染到 上下文中
3、上下文中拿到图片
4、图片写到保存相册里 (图片不需要转二进制了转成二进制数据) UIImageWriteToSavedPhotosAlbum(newImage,self,@selector(image:didFinishSavingWithError:contextInfo:),nil); //nil这里是传入给回掉方法的值 id类型(void *)
5、实现图片保存完成的回调方法
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;
6.1、如果用户取消了访问相册的允许后 第二次就点击就默认不会允许访问相册了
所以需要手动提醒用户到 setting->privacy->Photos->开到我们的应用 开启switch按钮
// NJViewController.m #import "NJViewController.h" #import "MBProgressHUD+NJ.h" @interface NJViewController () - (IBAction)captureView:(UIButton *)sender; @property (weak, nonatomic) IBOutlet UIView *customView; @end @implementation NJViewController - (IBAction)captureView:(UIButton *)sender { // 延迟1 ~2 秒之后再截屏 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 1.创建一个bitmap的上下文 UIGraphicsBeginImageContext(self.view.frame.size); // 2.将屏幕绘制到上下文中 [self.view.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); // 3.保存图片到相册 UIImageWriteToSavedPhotosAlbum(newImage, self, @selector(image:didFinishSavingWithError:contextInfo:), nil); }); } - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { if (error) { // NSLog(@"保存失败"); [MBProgressHUD showError:@"保存失败, 请检测应用是否拥有访问相册的权限"]; }else { [MBProgressHUD showSuccess:@"保存成功"]; } } @end
----------------
画图板触摸事件
画板
每个方法里都先取出手指
1、begin方法里创建UIBezierPath path小路径 设置[path setLineJoinStyle:kCGLineCapRound]; 获取当前手指的locationInView path移动到手指的位置 将path添加到 arr1里
2、move方法里用arr1的最后一个path 并且立即展示 [self setNeedsDisplay]
3、end方法里 重复move方法
4、-drawRect方法里每次展示的时候都 取出所有UIBezierPath小路径 绘制一遍 [[UIColor redColor] set]; [path stroke]
// // NJView.m // 02-画画板 #import "NJView.h" @interface NJView () @property (nonatomic, strong) NSMutableArray *paths; @end @implementation NJView - (NSMutableArray *)paths { if (_paths == nil) { _paths = [NSMutableArray array]; } return _paths; } // 开始触摸 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // 1.获取手指对应UITouch对象 UITouch *touch = [touches anyObject]; // 2.通过UITouch对象获取手指触摸的位置 CGPoint startPoint = [touch locationInView:touch.view]; // 3.当用户手指按下的时候创建一条路径 UIBezierPath *path = [UIBezierPath bezierPath]; // 3.1设置路径的相关属性 [path setLineJoinStyle:kCGLineJoinRound]; [path setLineCapStyle:kCGLineCapRound]; [path setLineWidth:10]; // 4.设置当前路径的起点 [path moveToPoint:startPoint]; // 5.将路径添加到数组中 [self.paths addObject:path]; } // 移动 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { // 1.获取手指对应UITouch对象 UITouch *touch = [touches anyObject]; // 2.通过UITouch对象获取手指触摸的位置 CGPoint movePoint = [touch locationInView:touch.view]; // 3.取出当前的path UIBezierPath *currentPaht = [self.paths lastObject]; // 4.设置当前路径的终点 [currentPaht addLineToPoint:movePoint]; // 6.调用drawRect方法重回视图 [self setNeedsDisplay]; } // 离开view(停止触摸) - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [self touchesMoved:touches withEvent:event]; /* // 1.获取手指对应UITouch对象 UITouch *touch = [touches anyObject]; // 2.通过UITouch对象获取手指触摸的位置 CGPoint endPoint = [touch locationInView:touch.view]; // 3.取出当前的path UIBezierPath *currentPaht = [self.paths lastObject]; // 4.设置当前路径的终点 [currentPaht addLineToPoint:endPoint]; // 6.调用drawRect方法重回视图 [self setNeedsDisplay]; */ } // 画线 - (void)drawRect:(CGRect)rect { [[UIColor redColor] set]; // 边路数组绘制所有的线段 for (UIBezierPath *path in self.paths) { [path stroke]; } } - (void)test { /* // 1.创建一条路径 CGMutablePathRef path = CGPathCreateMutable(); CGPathMoveToPoint(path, NULL, 20, 20); CGPathAddLineToPoint(path, NULL, 100, 100); CGMutablePathRef path2 = CGPathCreateMutable(); CGPathMoveToPoint(path2, NULL, 120, 120); CGPathAddLineToPoint(path2, NULL, 200, 200); CGContextRef ctx = UIGraphicsGetCurrentContext(); // 2.将路径添加到上下文中 CGContextAddPath(ctx, path); CGContextAddPath(ctx, path2); // 3.渲染 CGContextStrokePath(ctx); */ /* // UIBezierPath == CGMutablePathRef // 1.创建一条路径 UIBezierPath *path = [UIBezierPath bezierPath]; // 2.给路径设置起点和重点 [path moveToPoint:CGPointMake(20, 20)]; [path addLineToPoint:CGPointMake(100, 100)]; [path setLineCapStyle:kCGLineCapRound]; [path setLineWidth:10]; [path setLineJoinStyle:kCGLineJoinRound]; // 3.渲染路径 [path stroke]; // 1.创建一条路径 UIBezierPath *path2 = [UIBezierPath bezierPath]; // 2.给路径设置起点和重点 [path2 moveToPoint:CGPointMake(120, 120)]; [path2 addLineToPoint:CGPointMake(200, 200)]; [path2 stroke]; */ } - (void)clearView { [self.paths removeAllObjects]; [self setNeedsDisplay]; } - (void)backView { [self.paths removeLastObject]; [self setNeedsDisplay]; } @end
[[UIColor redColor] set]; //设置stroke的颜色
UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:startPoint]; [path setLineJoinStyle:kCGLineCapRound];
[self.pathLists addObject:path];
[self setNeedsDisplay];
- (void)drawRect:(CGRect)rect{ [path stroke];
}
[arrayM removeAllObjects];
[arrayM removeLastObject];
touch.veiw触摸的view
----------------
手势解锁 touch
1、自定义stroyboard中的view v1(背景色设置为clear) 里面拖一个自定义view v2
2、v2 重写 - (id)initWithFrame:(CGRect)frame - (id)initWithCoder:(NSCoder *)aDecoder 里面调用方法 [self setup]
3、v2 setup方法里面绘制九宫格 9个空白的按钮 并设置userInteractionEnabled = NO;
4、v2 layoutSubviews里面设置每个按钮的frame
5、v2 touches began move end
// // NJLockView.m // 04-手势解锁 // // Created by apple on 14-6-12. // Copyright (c) 2014年 heima. All rights reserved. // #import "NJLockView.h" @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 = 0; i < 9; 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 = 0; i < self.subviews.count; i++) { // 1.取出对应位置的按钮 UIButton *btn = self.subviews[i]; // 2.设置frame CGFloat btnW = 74; CGFloat btnH = 74; // 2.1计算间距 CGFloat margin = (self.frame.size.width - (3 * btnW)) / 4; int col = i % 3; // 列号 int row = i / 3; // 行号 // 间距 + 列号 * (按钮宽度+ 间距) 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 = 0; i < self.buttons.count; i++) { // 取出按钮 UIButton *btn = self.buttons[i]; if (0 == 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 != 0) { CGContextAddLineToPoint(ctx, self.currentPoint.x, self.currentPoint.y); } // [[UIColor greenColor] set]; [[UIColor colorWithRed:18/255.0 green:102/255.0 blue:72/255.0 alpha:0.5] set]; CGContextSetLineWidth(ctx, 10); 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
---------------------------
事件传递
面试的时候看看即可 这里了解一下 开发中几乎用不到
先进先出
触摸事件-》系统->UIApplication的事件队列中->UIApplication将事件通常传递给keywindow->
keywindow找到最合适的view来处理
(
从父控件传递到子空间 直到找到最合适的子控件
如果父控件(UIView类型)不能接收触摸事件 那么子控件就不能接收触摸事件(掌握)
UIView不能接收触摸事件的几种情况:1、 userInteractionEnabled = NO; 2、 hidden = YES; 3、alpha <=0.01;
UIImageView默认userInteractionEnabled = NO;
)
响应者链条
如果最适合的响应者没有实现touch方法 那么就顺着响应者链条向上一个响应者传递
响应者链条
api文档
----------------
所以产生了UIGestureRecognizer
UIImageView添加一个点击手势识别器
1、view添加点击手势识别器
2、手势识别器添加监听方法 abc
如果手势识别器添加delegate
delegate实现方法
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
返回NO
那么 tap就不会执行 abc
// // NJViewController.m // 08-敲击手势识别器 #import "NJViewController.h" @interface NJViewController ()<UIGestureRecognizerDelegate> @property (weak, nonatomic) IBOutlet UIImageView *iconView; @end @implementation NJViewController - (void)viewDidLoad { [super viewDidLoad]; // 0 .打开UIImageView的用户交互 self.iconView.userInteractionEnabled = YES; // 1.创建手势识别器 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init]; // 1.1设置手势识别器的属性 // // 设置用户必须点击几次才能出发点击事件 // tap.numberOfTapsRequired = 2; // // 设置用户必须两根手指同时点击才会促发事件 // tap.numberOfTouchesRequired = 2; tap.delegate = self; //如果设置了这个 并且写了代理方法a 点击手势识别器监听到了就让a执行这个方法 // 2.view添加手势识别器 [self.iconView addGestureRecognizer:tap]; // 3.监听手势识别器 [tap addTarget:self action:@selector(tapView)]; // [self.iconView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapView)]]; } -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { return NO; } - (void)tapView { NSLog(@"图片被点击了"); } @end