事件处理详解

一:事件处理

事件处理常见属性:

事件类型

  • @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. 对web日志文件实现按照人员、行为分类

    日志格式: method,time,name in,2015-05-06 17:37:46,Jenny1out,2015-05-06 17:37:46,Judith1in,2015-05-06 17: ...

  2. Intent传递数据

    方式比较多,先看看代码,一会儿再总结. activity_main.xml <RelativeLayout xmlns:android="http://schemas.android. ...

  3. Go语言相关图书推荐

    Go语言编程 作      者 许式伟 等 著 出 版 社 人民邮电出版社 出版时间 2012-08-01 版      次 1 页      数 245 印刷时间 2012-08-01 开      ...

  4. [WebService]之Schema

    schema入门 1:schema出现的目的是通过一个更加合理的方式来编写xml文件的限制(以XML语法的方式) 2:schema可以使用命名空间来支持多个名称相同的元素 3:schema可以很好的的 ...

  5. [原创]Devexpress XtraReports 系列 3 创建主从报表

    昨天写了系列的第二篇Devexpress XtraReports 系列 2 创建表格报表 . 今天我们来继续系列 3 创建主从报表 首先我们来看看最后实现的效果.Demo最后附上. 开始吧. 第一步, ...

  6. How to setup Wicket Examples in Eclipse

    Wicket examples is a good place to learn Apache Wicket by examples, and a must reference site for ne ...

  7. hibernate search例子

    [TOC] 1. 概念介绍 1.1. Hibernate Search Hibernate Search是Hibernate的子项目,把数据库全文检索能力引入到项目中,并通过"透明" ...

  8. HTML5简介及HTML5的发展前景

    WEB技术发展越来越迅速,HTML5的到来更是把WEB技术推向了巅峰,目前HTML5技术已经日趋成熟,不仅在PC段,HTML5更是在移动终端上也有广泛的应用,HTML5的未来十分光明,值得我们去学习. ...

  9. Add mappings to an Elasticsearch index in realtime

    Changing mapping on existing index is not an easy task. You may find the reason and possible solutio ...

  10. hdoj 5358 First One

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5358 一开始一直以为是一道数学题,在找有什么规律化简Log2(S(i,j)),结束了以后才造  ⌊lo ...