Pan平移手势
终于效果图:


Swipe轻扫手势

LongPress长按手势

Pinch和Rotation手势

捏合(缩放)和旋转

终于效果图:

涂鸦

终于效果图:

事件分3大类:触摸、加速计、远程遥控


仅仅有响应者的子类,才干够接收和处理事件


父类响应者中定义的事件处理接口例如以下:


触摸事件处理的四个方法例如以下:(仅仅要实现,系统会自己主动调用)


一个UITouch对象,代表着一根手指,手指移动,UITouch对象实时更新


一个UITouch对象,相应一根手指,记录着触摸时的全部信息


重要~常常使用UITouch的方法,取得触摸时的信息(如位置、所点对象)


事件对象UIEvent,经常使用的属性是:事件类型


触摸的四个方法(即过程)具体解释:注意同一时候和一前一后触摸的情况

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHJlX2VtaW5lbnQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

必须先找到事件的最合适的响应者(从父到子地找)


以下是寻找最合适的事件响应者详细样例:


特殊情况:要尤其注意


找到了事件的最佳处理者之后,就是响应者链条了
默认是会调用其[super touchesXXX],这个super就是上一个响应者
即:官方文档中的next responder

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHJlX2VtaW5lbnQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

以下是官方文档中关于上一个响应者的图片,即Next Responder


总结起来就是:view有控制器,则传给控制器;否则,传给父view


再次总结:响应者链条传递机制(上一个响应者就是NEXT RESPONDER)


传统监听事件的做法:(不再推荐使用)

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHJlX2VtaW5lbnQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

六种手势识别器,后面会详细举例:
假设要同一时候监听两种以上的手势:
为每个手势设置delegate,而且实现以下的方法

- (BOOL)gestureRecognizer:(UIGestureRecognizer
*)shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)



手势识别器的标准做法:三步曲(创建、设置、绑定)


重点关注三种手势识别的状态:開始\结束\取消


官方文档中关于手势识别的状态变化图

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHJlX2VtaW5lbnQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

手势识别器的代理方法<UIGestureRecognizerDelegate>
当中:shouldReceiveTouch能够指定手势在特定条件下有效

shouldRecognizeSimultaneouslyWithGestureRecognizer

返回YES代表能够同一时候识别不同手势,如同一时候旋转和缩放





Pan平移手势
终于效果图:


//
// PanController.m
// 38_手势
//
// Created by beyond on 14-9-16.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// #import "PanController.h" @interface PanController ()
// nana头像所在的View
@property (weak, nonatomic) IBOutlet UIView *nanaView;
- (IBAction)dismiss; @end @implementation PanController - (void)viewDidLoad
{
[super viewDidLoad];
// 创建pan手势,并绑定监听方法
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panView:)];
[self.nanaView addGestureRecognizer:pan];
} - (void)panView:(UIPanGestureRecognizer *)pan
{ switch (pan.state) {
case UIGestureRecognizerStateBegan: // 開始触发手势 break; case UIGestureRecognizerStateEnded: // 手势结束 break; default:
break;
} // 1.在view上面挪动的距离
CGPoint translation = [pan translationInView:pan.view];
CGPoint center = pan.view.center;
center.x += translation.x;
center.y += translation.y;
pan.view.center = center; // 2.清空移动的距离
[pan setTranslation:CGPointZero inView:pan.view];
} #pragma mark - 连线
- (IBAction)dismiss
{
[self dismissViewControllerAnimated:YES completion:nil];
}
@end

Tap手势
//
// TapController.m
// 38_手势
//
// Created by beyond on 14-9-16.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// #import "TapController.h" // 手势代理
@interface TapController ()<UIGestureRecognizerDelegate> @property (weak, nonatomic) IBOutlet UIImageView *nanaImgView; - (IBAction)dismiss; @end @implementation TapController - (void)viewDidLoad
{
[super viewDidLoad];
_nanaImgView.userInteractionEnabled = YES;
_nanaImgView.multipleTouchEnabled = YES;
//[self testTap];
[self testTap2];
} - (void)testTap
{
// 1.创建Tap手势识别器对象
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
// 两根手势,连续敲击2次,手势才干识别成功
tap.numberOfTapsRequired = 2;
tap.numberOfTouchesRequired = 2; // 2.加入监听方法(识别到了相应的手势,就会调用监听方法)
[tap addTarget:self action:@selector(taping)]; // 3.为nanaImgView 加入Tap手势识别器对象
[self.nanaImgView addGestureRecognizer:tap];
} - (void)testTap2
{
// 1.创建Tap手势识别器对象,同一时候绑定监听方法(识别到了相应的手势,就会调用监听方法)
UIGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(taping)];
// 2.设置手势的代理,目的是:决定手势仅仅有在特定场合才会被识别(触发监听的方法)
tap.delegate = self;
// 3.为nanaImgView 加入Tap手势识别器对象
[self.nanaImgView addGestureRecognizer:tap];
}
#define kRandomColor [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1.0]
// 监听的方法
- (void)taping
{
// 每次tap,随机变换背景颜色
self.view.backgroundColor = kRandomColor;
NSLog(@"-----taping");
}
#pragma mark - gestureRecognizer的代理方法
// 当点击view的时候,会先询问这种方法,是否接收本次tap点击(即是否为有效tap)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
CGPoint pos = [touch locationInView:touch.view];
// 点击图片的左半边有效,右半边无效
if (pos.x <= self.nanaImgView.frame.size.width * 0.5) {
return YES;
}
return NO;
} #pragma mark - 连线方法
- (IBAction)dismiss
{
[self dismissViewControllerAnimated:YES completion:nil];
}
@end

Swipe轻扫手势

LongPress长按手势

长按手势的主要属性參数

//
// SwipeLongPressController.m
// 38_手势
//
// Created by beyond on 14-9-17.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// #import "SwipeLongPressController.h" @interface SwipeLongPressController ()
@property (weak, nonatomic) IBOutlet UIImageView *nanaImgView;
- (IBAction)dismiss; @end @implementation SwipeLongPressController - (void)viewDidLoad
{
[super viewDidLoad];
// 1.同意交互
_nanaImgView.userInteractionEnabled = YES; // 2.自己定义方法,加入swipe手势
[self addSwipe]; // 3.自己定义方法,加入longPress手势
[self addLongPress];
} // 2.自己定义方法,加入swipe手势
- (void)addSwipe
{
// 1.创建Swipe手势识别器对象,同一时候绑定监听方法(识别到了相应的手势,就会调用监听方法)
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swiping)];
// 设置属性:轻扫的方向
swipe.direction = UISwipeGestureRecognizerDirectionUp;
// 2.为nanaImgView 加入Swipe手势识别器对象
[self.nanaImgView addGestureRecognizer:swipe];
}
// 3.自己定义方法,加入longPress手势
- (void)addLongPress
{
// 1.创建LongPress手势识别器对象,同一时候绑定监听方法(识别到了相应的手势,就会调用监听方法)
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] init];
[longPress addTarget:self action:@selector(longPressing)]; // 设置属性:至少长按2秒,默认0.5秒
longPress.minimumPressDuration = 2;
// 按下之后,不松手,在能触发手势之前,可同意移动的范围,50px范围内长按有效,默认是10px
longPress.allowableMovement = 50; // 2.为nanaImgView 加入Swipe手势识别器对象
[self.nanaImgView addGestureRecognizer:longPress];
}
#define kRandomColor [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1.0]
// 手势的监听的方法
- (void)swiping
{
self.view.backgroundColor = kRandomColor;
NSLog(@"-----swiping");
}
// 手势的监听的方法
- (void)longPressing
{
self.view.backgroundColor = kRandomColor;
NSLog(@"-------长按了nanaImgView");
} - (IBAction)dismiss
{
[self dismissViewControllerAnimated:YES completion:nil ];
}
@end

Pinch和Rotation手势

捏合(缩放)和旋转

终于效果图:

//
// PinchRotationController.m
// 38_手势
//
// Created by beyond on 14-9-17.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// #import "PinchRotationController.h" // 手势识别器的代理方法,目的是:
@interface PinchRotationController ()<UIGestureRecognizerDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *nanaImgView;
- (IBAction)dismiss; @end @implementation PinchRotationController - (void)viewDidLoad
{
[super viewDidLoad];
// 同一时候加入Pinch捏合手势(缩放) 和旋转手势
[self addPinchAndRotate];
} #pragma mark - 缩放 + 旋转
- (void)addPinchAndRotate
{
// 1.加入 Pinch捏合手势(缩放)
[self addPinch];
// 2.加入 旋转手势
[self addRotate];
} // 1.加入 Pinch捏合手势(缩放) ,缩放手势(捏合手势)
- (void)addPinch
{
// 1.创建Pinch手势识别器对象,同一时候绑定监听方法(识别到了相应的手势,就会调用监听方法)
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinching:)];
// 2.设置代理???
pinch.delegate = self;
// 3.为nanaImgView 加入Pinch手势识别器对象
[self.nanaImgView addGestureRecognizer:pinch];
} // 2.加入 旋转手势
- (void)addRotate
{
// 1.创建Rotation手势识别器对象,同一时候绑定监听方法(识别到了相应的手势,就会调用监听方法)
UIRotationGestureRecognizer *rotate = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotating:)];
// 2.设置代理???
rotate.delegate = self;
// 3.为nanaImgView 加入Rotation手势识别器对象
[self.nanaImgView addGestureRecognizer:rotate];
}
#pragma mark - 重要~~~~手势的监听方法
// Pinch捏合(缩放)
- (void)pinching:(UIPinchGestureRecognizer *)pinch
{
// X Y 按比例进行缩放
pinch.view.transform = CGAffineTransformScale(pinch.view.transform, pinch.scale, pinch.scale);
// 每次又一次归零~~~
pinch.scale = 1; // 这个真的非常重要!!!!!
}
// 旋转手势
- (void)rotating:(UIRotationGestureRecognizer *)rotate
{
// 按手势识别器 的旋转角度进行旋转
rotate.view.transform = CGAffineTransformRotate(rotate.view.transform, rotate.rotation);
// 每次要又一次归零~~~~
rotate.rotation = 0; // 这个非常重要!!!!!
} #pragma mark - 手势识别器的代理方法
/**
* 是否同意多个手势识别器同一时候有效
* Simultaneously : 同一时候地
*/
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
} #pragma mark - 连线方法
- (IBAction)dismiss
{
[self dismissViewControllerAnimated:YES completion:nil ];
}
@end



涂鸦

终于效果图:

控制器

//
// PaintController.m
// 38_手势_涂鸦
//
// Created by beyond on 14-9-17.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 涂鸦控制器 #import "PaintController.h"
// 画布
#import "Canvas.h" @interface PaintController ()
// 画板
@property (weak, nonatomic) IBOutlet Canvas *canvasView; // 清除画板
- (IBAction)clear;
// 撤销
- (IBAction)undo;
// 保存至相冊
- (IBAction)save; @end @implementation PaintController // 清除画板
- (IBAction)clear
{
[self.canvasView clear];
}
// 撤销
- (IBAction)undo
{
[self.canvasView undo];
}
// 保存至相冊
- (IBAction)save
{
// 1.截图
UIImage *image = [UIImage captureWithView:self.canvasView]; // 2.保存到图片,建议使用系统推荐的回调方法
UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
} // 保存图片操作之后就会调用本方法
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
if (error) { // 保存失败
[MBProgressHUD showError:@"保存失败"];
} else { // 保存成功
[MBProgressHUD showSuccess:@"保存成功"];
}
} @end

自己定义View:画布

//
// Canvas.h
// 38_手势_涂鸦
//
// Created by beyond on 14-9-17.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 画布 #import <UIKit/UIKit.h> @interface Canvas : UIView
// 清除画板
- (void)clear;
// 撤销上一笔画
- (void)undo;
@end
//
// Canvas.m
// 38_手势_涂鸦
//
// Created by beyond on 14-9-17.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 画布,核心代码 #import "Canvas.h" @interface Canvas()
// 存放贝塞尔路径对象数组,每一次touchBegin,相应一个新的路径
@property (nonatomic, strong) NSMutableArray *pathArr;
@end @implementation Canvas
#pragma mark - 懒载入
- (NSMutableArray *)pathArr
{
if (_pathArr == nil) {
_pathArr = [NSMutableArray array];
}
return _pathArr;
}
// 清除画板
- (void)clear
{
[self.pathArr removeAllObjects];
[self setNeedsDisplay];
}
// 撤销上一笔画
- (void)undo
{
[self.pathArr removeLastObject];
[self setNeedsDisplay];
}
#pragma mark - Touch方法
// 每一次touchBegin,相应一个新的路径对象
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// 1.获得当前的触摸点
UITouch *touch = [touches anyObject];
CGPoint startPos = [touch locationInView:touch.view]; // 2.创建一个新的路径
UIBezierPath *currenPath = [UIBezierPath bezierPath];
currenPath.lineCapStyle = kCGLineCapRound;
currenPath.lineJoinStyle = kCGLineJoinRound; // 设置起点
[currenPath moveToPoint:startPos]; // 3.加入路径到数组中
[self.pathArr addObject:currenPath]; [self setNeedsDisplay];
} // 取出最新的贝塞尔路径,加入新的点进去
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint pos = [touch locationInView:touch.view]; UIBezierPath *currentPath = [self.pathArr lastObject];
[currentPath addLineToPoint:pos]; [self setNeedsDisplay];
} // 抬笔时,与move一样
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesMoved:touches withEvent:event];
}
#pragma mark - 画线
- (void)drawRect:(CGRect)rect
{
[[UIColor redColor] set]; for (UIBezierPath *path in self.pathArr) {
path.lineWidth = 10;
[path stroke];
}
}
#pragma mark - 測试C画线代码
- (void)testPath
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
// CGContextMoveToPoint(ctx, 0, 0);
// CGContextAddLineToPoint(ctx, 100, 100);
// CGContextStrokePath(ctx); CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, 0, 0);
CGPathAddLineToPoint(path, NULL, 100, 100);
CGContextAddPath(ctx, path); CGMutablePathRef path2 = CGPathCreateMutable();
CGPathMoveToPoint(path2, NULL, 250, 250);
CGPathAddLineToPoint(path2, NULL, 110, 100);
CGContextAddPath(ctx, path2); CGContextStrokePath(ctx); CGPathRelease(path);
}
@end

截图分类

//
// UIImage+ScreenShot.m
// 38_手势
//
// Created by beyond on 14-9-17.
// Copyright (c) 2014年 com.beyond. All rights reserved.
// 分类,截图 #import "UIImage+ScreenShot.h" @implementation UIImage (ScreenShot) + (instancetype)captureWithView:(UIView *)view
{
// 1.开启上下文
UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, 0.0); // 2.将控制器view的layer渲染到上下文
[view.layer renderInContext:UIGraphicsGetCurrentContext()]; // 3.取出图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); // 4.结束上下文
UIGraphicsEndImageContext(); return newImage;
}
@end
































































版权声明:本文博客原创文章。博客,未经同意,不得转载。

iOS_38_手势的更多相关文章

  1. H5单页面手势滑屏切换原理

    H5单页面手势滑屏切换是采用HTML5 触摸事件(Touch) 和 CSS3动画(Transform,Transition)来实现的,效果图如下所示,本文简单说一下其实现原理和主要思路. 1.实现原理 ...

  2. PhotoView实现图片随手势的放大缩小的效果

    项目需求:在listView的条目中如果有图片,点击条目,实现图片的放大,并且图片可以根据手势来控制图片放大缩小的比例.类似于微信朋友圈中查看好友发布的照片所实现的效果. 思路是这样的:当点击条目的时 ...

  3. iOS7 NavigationController 手势问题

    在iOS7中,如果使用了UINavigationController,那么系统自带的附加了一个从屏幕左边缘开始滑动可以实现pop的手势.但是,如果自定义了navigationItem的leftBarB ...

  4. [DeviceOne开发]-手势动画示例分享

    一.简介 这是iOS下的效果,android下完全一致.通过do_GestureView组件和do_Animation组件,deviceone能很容易实现复杂的跨平台纯原生动画效果,这个示例就是通过手 ...

  5. iOS手势解锁、指纹解锁--Swift代码

    一.手势密码 1. 1.1.用UIButton组成手势的节点. 1.2.当手指接触屏幕时,调用重写的 touchesBegan:withEvent方法(在touchesBegan里调用setNeeds ...

  6. ionic之$ionicGesture手势(大坑)

    鄙人来本公司前未用过ionic框架,但由于ionic是基于angularjs封装的,正好我用过angularjs,很荣幸的面试就过了,然后通过该网站http://www.ionic.wang(后面简称 ...

  7. mui 手势事件配置

    在开发中监听双击屏幕事件时不起作用,需要在mui.init方法的gestureConfig参数中设置需要监听的手势事件 手势事件配置: 根据使用频率,mui默认会监听部分手势事件,如点击.滑动事件:为 ...

  8. 超小Web手势库AlloyFinger原理

    目前AlloyFinger作为腾讯手机QQ web手势解决方案,在各大项目中都发挥着作用. 感兴趣的同学可以去Github看看:https://github.com/AlloyTeam/AlloyFi ...

  9. 超级小的web手势库AlloyFinger发布

    简介 针对多点触控设备编程的Web手势组件,快速帮助你的web程序增加手势支持,也不用再担心click 300ms的延迟了.拥有两个版本,无依赖的独立版和react版本.除了Dom对象,也可监听Can ...

随机推荐

  1. 2014ACM/ICPC亚洲区域赛牡丹江站现场赛-K ( ZOJ 3829 ) Known Notation

    Known Notation Time Limit: 2 Seconds      Memory Limit: 65536 KB Do you know reverse Polish notation ...

  2. 同步github工程gitcafe

    github固然好.仅仅是国内訪问有点慢. 为了提高博客訪问速度我决定把github上托管的博客同步到gitcafe上.最好能在DNS那里做CDN,可是貌似没有免费的服务.那直接指向gitcafe好了 ...

  3. JS兼容的方式来获取浏览器的宽度

    <script type="text/javascript"> //need to wait until onload so body is available win ...

  4. Cocos2d-x 2地图步行实现:SPFA算法

    本文乃Siliphen原创,转载请注明出处:http://blog.csdn.net/stevenkylelee 上一节<Cocos2d-x 地图行走的实现1:图论与Dijkstra算法> ...

  5. Flash-使用变形面板制作花朵

    在Flash中利用"变形"面板的"重置选取和变形"button(在变形面板右下角),能够自己主动将对象进行创造性变形地画图 步骤: (1)先导入一幅图像 (2) ...

  6. hdu5338 (二进制,双指针)

    这种双循环的优化问题碰到过很多了.层出不穷. 但无非就是要利用前面循环时,所产生的信息,从而减少计算. 可以注意到log其实是不超过40的, 那么以这方面入手,时间复杂度就可以降为nlogn log= ...

  7. python学习之print输出不换行

    print的即时打印会导致换行,要使得print的输出不换行,可以在字符串或者变量后面加个逗号(“,”),如下: s = "A bird in the hand..." for c ...

  8. java split小结(转)

    2016.03.27下午参加华为机试,简单扫了一眼几个题的标题,选择了一道字符串问题,其实该题非常非常的简单,可以说是简单的不能再简单了,而且有很多种解法,上机时我选择了直接借用java提供的一些函数 ...

  9. bestcoder44#1002

    这题采用分治的思想 首先,根据最后一位是否为1,将数分为两个集合,  集合与集合之间的lowbit为1, 然后将每个集合内的元素,倒数第二位是否为1,将数分为两个集合,集合与集合之间的lowbit为2 ...

  10. Ubuntu下安装vmware 9.0 + 注册码

    先附上一些注册码到时使用: NA0UF-DUH00-QZHM0-MU17K-CC824 4F469-F024Q-CZ8R9-DL1N0-13C6W HF261-0HL40-FZX21-F9AQ2-0C ...