事件处理详解

一:事件处理

事件处理常见属性:

事件类型

  • @property(nonatomic,readonly) UIEventType     type;
  • @property(nonatomic,readonly) UIEventSubtype  subtype;

事件产生的时间

  • @property(nonatomic,readonly) NSTimeInterval  timestamp;

事件传递

- hitTest:withEvent:

SWIFT

func hitTest(_ point: CGPoint,
   withEvent event: UIEvent?) -> UIView?

OBJECTIVE-C

- (UIView *)hitTest:(CGPoint)point
          withEvent:(UIEvent *)event

- pointInside:withEvent:

SWIFT

 func pointInside(_ point: CGPoint,
        withEvent event: UIEvent?) -> a href="" Bool /a

OBJECTIVE-C

- (BOOL)pointInside:(CGPoint)point
withEvent:(UIEvent *)event

事件传递方法的简单实用:

事件传递的时候调用

  • 什么时候调用:当事件传递给控件的时候,就会调用控件的这个方法,去寻找最合适的view
  • 作用:寻找最合适的view

// point:当前的触摸点,point这个点的坐标系就是方法调用者

 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

 {

     // 调用系统的做法去寻找最合适的view,返回最合适的view

     UIView *fitView = [super hitTest:point withEvent:event];

 //    NSLog(@"fitView--%@",fitView);

     return fitView;

 }

// 作用:判断当前这个点在不在方法调用者(控件)上

 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

 {

     return YES;

 }

事件传递底层的实现:

如果父控件不能接收触摸事件,那么子控件就不可能接收到触摸事件(掌握)

  1. 如何找到最合适的控件来处理事件?
  2. 自己是否能接收触摸事件?
  3. 触摸点是否在自己身上?
  4. 从后往前遍历子控件数组,重复前面的两个步骤
  5. 如果没有符合条件的子控件,那么就自己最适合处理

// 点击黄色视图 -》 事件 -》 UIApplication -> UIWindow

// 因为所有的视图类都是继承BaseView

 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

 {

         NSLog(@"%@--hitTest",[self class]);

     //    return [super hitTest:point withEvent:event];

     // 1.判断当前控件能否接收事件

     if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil;

     // 2. 判断点在不在当前控件

     if ([self pointInside:point withEvent:event] == NO) return nil;

     // 3.从后往前遍历自己的子控件

     NSInteger count = self.subviews.count;

     ; i >= ; i--) {

         UIView *childView = self.subviews[i];

         // 把当前控件上的坐标系转换成子控件上的坐标系

         CGPoint childP = [self convertPoint:point toView:childView];

         UIView *fitView = [childView hitTest:childP withEvent:event];

         if (fitView) { // 寻找到最合适的view

             return fitView;

         }

     }

     // 循环结束,表示没有比自己更合适的view

     return self;

 }

关于事件传递的底层原理和方法的实现:

事件响应:(响应者链)

响应者链条:是由多个响应者对象连接起来的链条

作用:能很清楚的看见每个响应者之间的联系,并且可以让一个事件多个对象处理。

响应者对象:能处理事件的对象

事件传递的完整过程

  • 1> 先将事件对象由上往下传递(由父控件传递给子控件),找到最合适的控件来处理这个事件。
  • 2> 调用最合适控件的touches….方法
  • 3> 如果调用了[super touches….];就会将事件顺着响应者链条往上传递,传递给上一个响应者
  • 4> 接着就会调用上一个响应者的touches….方法

重点:如何判断上一个响应者

  • 1> 如果当前这个view是控制器的view,那么控制器就是上一个响应者
  • 2> 如果当前这个view不是控制器的view,那么父控件就是上一个响应者

二:触摸事件

各个方法的解释

UITouch相关属性:

触摸产生时所处的窗口

  • @property(nonatomic,readonly,retain) UIWindow    *window;

触摸产生时所处的视图

  • @property(nonatomic,readonly,retain) UIView      *view;

短时间内点按屏幕的次数,可以根据tapCount判断单击、双击或更多的点击

  • @property(nonatomic,readonly) NSUInteger          tapCount;

记录了触摸事件产生或变化时的时间,单位是秒

  • @property(nonatomic,readonly) NSTimeInterval      timestamp;

当前触摸事件所处的状态

  • @property(nonatomic,readonly) UITouchPhase        phase;

方法:

  • - (CGPoint)locationInView:(UIView *)view;
  1. 返回值表示触摸在view上的位置
  2. 这里返回的位置是针对view的坐标系的(以view的左上角为原点(0, 0))
  3. 调用时传入的view参数为nil的话,返回的是触摸点在UIWindow的位置
  • - (CGPoint)previousLocationInView:(UIView *)view;

该方法记录了前一个触摸点的位置

UIView不接收触摸事件的三种情况

不接收用户交互

  • userInteractionEnabled = NO

隐藏

  • hidden = YES

透明

  • alpha = 0.0 ~ 0.01

提示:UIImageView的userInteractionEnabled默认就是NO,因此UIImageView以及它的子控件默认是不能接收触摸事件的

实现UIView的拖动:

OC&Swift版

 -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

 {

     UITouch *touch = [touches anyObject];

     CGPoint curP = [touch locationInView:self];

     CGPoint preP = [touch previousLocationInView:self];

     CGFloat offsetX = preP.x - curP.x;

     CGFloat offsetY = preP.y - curP.y;

     self.transform = CGAffineTransformTranslate(self.transform, -offsetX, -offsetY);

 }    }

--------------------swift-----------------------


     override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {

         var touch:UITouch = touches(AnyObject)

         var preP:CGPoint = touch.locationInView(self)

         var curP:CGPoint = touch.previousLocationInView(self)

         var ofX = curP.x - preP.x

         var ofY = curP.y - preP.y

         self.transform = CGAffineTransformTranslate(self.transform, ofX, ofY)

     }

触摸事件简单介绍:

// 当手指开始触摸view

// NSArray,字典,NSSet(无序)

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

 {

     NSLog(@"%ld", touches.count);

     NSLog(@"%s",__func__);

 }

// 当手指在view上移动的时候

 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

 {

     NSLog(@"%s",__func__);

 }

// 当手指离开这个view的时候

 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{

      NSLog(@"%s",__func__);

 }

// 当触摸事件被打断的时候调用(电话打入)

 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

 {

 }

三:gestureReginazation

各个方法的解释

UIView拖动

OC&Swift版


 @interface ViewController ()

 @property (weak, nonatomic) IBOutlet iCocosView *dragView;

 @end

 @implementation ViewController

 - (void)viewDidLoad {

     [super viewDidLoad];

 //    self.view.transform = CGAffineTransformTranslate(self.view.transform, 100, 100);

     /**

      为对应的View创建并且添加手势和手势监听方法

      */

     UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(Drag:)];

     [self.dragView addGestureRecognizer:pan];

 }

/**

*  实现手势监听方法

*/

 -(void)Drag:(UIPanGestureRecognizer *)pan

 {

     //获取盘的位置

     CGPoint p = [pan translationInView:pan.view];

     /**

      *  使用三步法实现赋值

      */

     //根据pan的位置获取pan的中心点

     CGPoint center = pan.view.center;

     center.x += p.x;

     center.y += p.y;

     pan.view.center = center;

     //根据pan的移动设置对应View的移动

     [pan setTranslation:CGPointZero inView:pan.view];

 }

------------------swift-----------------------

  @IBOutlet weak var dragViews: iCocos!

     override func viewDidLoad() {

         super.viewDidLoad()

         var pan:UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: "Drag:")

         self.dragViews.addGestureRecognizer(pan)

     }

     func Drag(pan:UIPanGestureRecognizer)

     {

         var P:CGPoint = pan.translationInView(pan.view!)

         var center:CGPoint = pan.view!.center

         center.x += P.x

         center.y += P.y

         pan.view?.center = center

         pan.setTranslation(CGPointZero, inView: pan.view)

------------------------------------------

手势方法简单实用:UIGestureRecognizerDelegate

#pragma mark - 手势代理方法

// 是否允许开始触发手势

 //- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer

 //{

 //    return NO;

 //}

// 是否允许同时支持多个手势,默认是不支持多个手势

// 返回yes表示支持多个手势

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

 {

     return YES;

 }

// 是否允许接收手指的触摸点

 //- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{

 //    // 获取当前的触摸点

 //    CGPoint curP = [touch locationInView:self.imageView];

 //    

 //    if (curP.x < self.imageView.bounds.size.width * 0.5) {

 //        return NO;

 //    }else{

 //        return YES;

 //    }

 //}

#pragma mark - 点按手势

 - (void)setUpTap

 {

     // 创建点按手势

     UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];

     tap.delegate = self;

     [_imageView addGestureRecognizer:tap];

 }

 - (void)tap:(UITapGestureRecognizer *)tap

 {

     NSLog(@"%s",__func__);

 }

#pragma mark - 长按手势

 // 默认会触发两次

 - (void)setUpLongPress

 {

     UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];

     [self.imageView addGestureRecognizer:longPress];

 }

 - (void)longPress:(UILongPressGestureRecognizer *)longPress

 {

     if (longPress.state == UIGestureRecognizerStateBegan) {

         NSLog(@"%s",__func__);

     }

 }

#pragma mark - 清扫

 - (void)setUpSwipe

 {

     // 默认轻扫的方向是往右

     UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe)];

     swipe.direction = UISwipeGestureRecognizerDirectionUp;

     [self.imageView addGestureRecognizer:swipe];

     // 如果以后想要一个控件支持多个方向的轻扫,必须创建多个轻扫手势,一个轻扫手势只支持一个方向

     // 默认轻扫的方向是往右

     UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe)];

     swipeDown.direction = UISwipeGestureRecognizerDirectionDown;

     [self.imageView addGestureRecognizer:swipeDown];

 }

 - (void)swipe

 {

     NSLog(@"%s",__func__);

 }

#pragma mark - 旋转手势

 - (void)setUpRotation

 {

     UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotation:)];

     rotation.delegate = self;

     [self.imageView addGestureRecognizer:rotation];

 }

 // 默认传递的旋转的角度都是相对于最开始的位置

 - (void)rotation:(UIRotationGestureRecognizer *)rotation

 {

     self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, rotation.rotation);

     // 复位

     rotation.rotation = ;

     // 获取手势旋转的角度

     NSLog(@"%f",rotation.rotation);

 }

#pragma mark - 捏合

 - (void)setUpPinch

 {

     UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)];

     pinch.delegate = self;

     [self.imageView addGestureRecognizer:pinch];

 }

 - (void)pinch:(UIPinchGestureRecognizer *)pinch

 {

     self.imageView.transform = CGAffineTransformScale(self.imageView.transform, pinch.scale, pinch.scale);

     // 复位

     pinch.scale = ;

 }

#pragma mark - 拖拽

 - (void)setUpPan

 {

     UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];

     [self.imageView addGestureRecognizer:pan];

 }

 - (void)pan:(UIPanGestureRecognizer *)pan

 {

     // 获取手势的触摸点

     CGPoint curP = [pan locationInView:self.imageView];

     // 移动视图

     // 获取手势的移动,也是相对于最开始的位置

     CGPoint transP = [pan translationInView:self.imageView];

     self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, transP.x, transP.y);

     // 复位

     [pan setTranslation:CGPointZero inView:self.imageView];

     NSLog(@"%@",NSStringFromCGPoint(curP));

 }

手势状态:

 statetypedef NS_ENUM(NSInteger, UIGestureRecognizerState) {

     // 没有触摸事件发生,所有手势识别的默认状态

     UIGestureRecognizerStatePossible,

     // 一个手势已经开始但尚未改变或者完成时

     UIGestureRecognizerStateBegan,

     // 手势状态改变

     UIGestureRecognizerStateChanged,

     // 手势完成

     UIGestureRecognizerStateEnded,

     // 手势取消,恢复至Possible状态

     UIGestureRecognizerStateCancelled, 

     // 手势失败,恢复至Possible状态

     UIGestureRecognizerStateFailed,

     // 识别到手势识别

     UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded

 };

四:加速计:(运动)

 - (void)orientationChanged:(NSNotification *)notification {

      // Respond to changes in device orientation

 }
 - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {

     if (motion == UIEventSubtypeMotionShake)

     {

         // User was shaking the device. Post a notification named "shake."

         [[NSNotificationCenter defaultCenter] postNotificationName:@"shake" object:self];

      }

 }

五:远程控制

注册:

 MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];

 [commandCenter.playCommand addTargetUsingBlock:^(MPRemoteCommandEvent *event) {

     // Begin playing the current track.

     [[MyPlayer sharedPlayer] play];

 }

使用

 - (void)configureNowPlayingInfo:(MPMediaItem*)item{

     MPNowPlayingInfoCenter* info = [MPNowPlayingInfoCenter defaultCenter];

     NSMutableDictionary* newInfo = [NSMutableDictionary dictionary];

     NSSet* itemProperties = [NSSet setWithObjects:MPMediaItemPropertyTitle,

           MPMediaItemPropertyArtist,

           MPMediaItemPropertyPlaybackDuration,

           MPNowPlayingInfoPropertyElapsedPlaybackTime,

           nil];

     [item enumerateValuesForProperties:itemProperties

           usingBlock:^(NSString *property, id value, BOOL *stop) {

         [newInfo setObject:value forKey:property];

     }];

     info.nowPlayingInfo = newInfo;

 }

iOS开发——实用技术OC篇&事件处理详解的更多相关文章

  1. iOS开发——多线程OC篇&多线程详解

    多线程详解 前面介绍了多线程的各种方式及其使用,这里补一点关于多线程的概念及相关技巧与使用,相信前面不懂的地方看了这里之后你就对多线程基本上没有什么问题了! 1——首先ios开发多线程中必须了解的概念 ...

  2. ios开发——实战OC篇&FMDB详解

    FMDB详解 前一篇文章中我们介绍的SQLite的使用,在iOS中原生的SQLite API在使用上相当不友好. 于是,就出现了一系列将SQLite API进行封装的库,例如FMDB.Plausibl ...

  3. iOS开发——屏幕适配篇&Masonry详解

    Masonry详解 前言 MagicNumber -> autoresizingMask -> autolayout 以上是纯手写代码所经历的关于页面布局的三个时期 在iphone1-ip ...

  4. iOS开发——实用技术OC篇&单例模式的实实现(ACR&MRC)

    单例模式的实实现(ACR&MRC) 在iOS开发中单例模式是一种非常常见的模式,虽然我们自己实现的比较少,但是,系统却提供了不少的到来模式给我们用,比如最常见的UIApplication,No ...

  5. iOS开发——实用技术OC篇&简单抽屉效果的实现

    简单抽屉效果的实现 就目前大部分App来说基本上都有关于抽屉效果的实现,比如QQ/微信等.所以,今天我们就来简单的实现一下.当然如果你想你的效果更好或者是封装成一个到哪里都能用的工具类,那就还需要下一 ...

  6. ios开发——实用技术OC篇&地图与定位

    地图与定位 11.1 iOS定位服务 11.2 iOS地图 11.3 Web地图 1 iOS定位服务 iOS中有三个定位服务组件: Wifi定位,通过查询一个Wifi路由器的地理位置的信息.比较省电, ...

  7. iOS开发——实用技术OC篇&8行代码教你搞定导航控制器全屏滑动返回效果

    8行代码教你搞定导航控制器全屏滑动返回效果 前言 如果自定了导航控制器的自控制器的leftBarButtonItem,可能会引发边缘滑动pop效果的失灵,是由于 self.interactivePop ...

  8. ios开发——实用技术OC篇》倒计时实现的两种方法

    倒计时实现的两种方法 timeFireMethod函数,timeFireMethod进行倒计时的一些操作,完成时把timer给invalidate掉就ok了,代码如下: secondsCountDow ...

  9. iOS开发——实战OC篇&环境搭建之Xib(玩转UINavigationController与UITabBarController)

    iOS开发——实战OC篇&环境搭建之Xib(玩转UINavigationController与UITabBarController)   前面我们介绍了StoryBoard这个新技术,和纯技术 ...

随机推荐

  1. os和os.path模块

    Os和os.path模块函数 1.      Os模块 函数 描述 文件处理 Mkfifo()/mknod() 创建命名管道/创建文件系统节点 Remove()/unlink() 删除文件 Renam ...

  2. 【转】Linux Page Cache的工作原理

    1 .前言 自从诞生以来,Linux 就被不断完善和普及,目前它已经成为主流通用操作系统之一,使用得非常广泛,它与Windows.UNIX 一起占据了操作系统领域几乎所有的市场份额.特别是在高性能计算 ...

  3. storm流式大数据处理流行吗

    在如今这个信息高速增长的今天,信息实时计算处理能力已经是一项专业技能了,正是因为有了这些需求的存在才使得分布式,同时具备高容错的实时计算系统Storm才变得如此受欢迎,为什么这么说呢?下面看看新霸哥的 ...

  4. CentOS下安装gns3

    1.安装支持环境 sudo yum intall PyQt4 telnet 2.安装抓包用的wireshark sudo yum install wireshark wireshark-gnome 3 ...

  5. wifi reaver

    PIN码的格式很简单, 八位十进制数,最后一位(第8位)为校验位(可根据前7位算出),验证时先检测前4位,如果一致则反馈一个信息,所以只需1万次就可完全扫描一遍前4位,前4位确定下来的话,只需再试10 ...

  6. 30个有关Python的小技巧

    从我开始学习python的时候,我就开始自己总结一个python小技巧的集合.后来当我什么时候在Stack Overflow或者在某个开源软件里看到一段很酷代码的时候,我就很惊讶:原来还能这么做!,当 ...

  7. 桶排序-C-结构体排序

    struct TS { int index; ]; }; ] = {{,,,,,"s8"}}; ]; int i; int length = sizeof(a) / sizeof ...

  8. [POJ] #1002# 487-3279 : 桶排序/字典树(Trie树)/快速排序

    一. 题目 487-3279 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 274040   Accepted: 48891 ...

  9. Chef

    Chef是一个渐渐流行的部署大.小集群的自动化管理平台.Chef可以用来管理一个传统的静态集群,也可以和EC2或者其他的云计算提供商一起使用.Chef用cookbook作为最基本的配置单元,可以被泛化 ...

  10. linux极点五笔无法输入词组_ibus设置

    菜鸟学linux——用的是ubuntu 不知道是不是按个哪些快捷键,极点五笔突然无法输入词组.那个抓狂啊 没关系,设置一下就ok 第一步:右上角输入法,右键——>首选项——>常规——> ...