iOS开发——实用技术OC篇&事件处理详解

事件处理详解

一:事件处理

事件处理常见属性:

事件类型

  • @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

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

OBJECTIVE-C

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

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

事件传递的时候调用

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

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

 1 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
 2
 3 {
 4
 5     // 调用系统的做法去寻找最合适的view,返回最合适的view
 6
 7     UIView *fitView = [super hitTest:point withEvent:event];
 8
 9
10
11 //    NSLog(@"fitView--%@",fitView);
12
13
14
15
16
17     return fitView;
18
19 }

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

1 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
2
3 {
4
5     return YES;
6
7 }

事件传递底层的实现:

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

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

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

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

 1 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
 2
 3 {
 4
 5         NSLog(@"%@--hitTest",[self class]);
 6
 7     //    return [super hitTest:point withEvent:event];
 8
 9
10
11
12
13     // 1.判断当前控件能否接收事件
14
15     if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil;
16
17
18
19     // 2. 判断点在不在当前控件
20
21     if ([self pointInside:point withEvent:event] == NO) return nil;
22
23
24
25     // 3.从后往前遍历自己的子控件
26
27     NSInteger count = self.subviews.count;
28
29
30
31     for (NSInteger i = count - 1; i >= 0; i--) {
32
33         UIView *childView = self.subviews[i];
34
35
36
37         // 把当前控件上的坐标系转换成子控件上的坐标系
38
39         CGPoint childP = [self convertPoint:point toView:childView];
40
41
42
43         UIView *fitView = [childView hitTest:childP withEvent:event];
44
45
46
47
48
49         if (fitView) { // 寻找到最合适的view
50
51             return fitView;
52
53         }
54
55
56
57
58
59     }
60
61
62
63     // 循环结束,表示没有比自己更合适的view
64
65     return self;
66
67
68
69 }

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

事件响应:(响应者链)

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

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

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

事件传递的完整过程

  • 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版

 1 -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
 2
 3 {
 4
 5     UITouch *touch = [touches anyObject];
 6
 7
 8
 9     CGPoint curP = [touch locationInView:self];
10
11
12
13     CGPoint preP = [touch previousLocationInView:self];
14
15
16
17     CGFloat offsetX = preP.x - curP.x;
18
19     CGFloat offsetY = preP.y - curP.y;
20
21     self.transform = CGAffineTransformTranslate(self.transform, -offsetX, -offsetY);
22
23 }    }

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

 1
 2
 3
 4
 5
 6
 7     override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
 8
 9
10
11         var touch:UITouch = touches(AnyObject)
12
13
14
15         var preP:CGPoint = touch.locationInView(self)
16
17         var curP:CGPoint = touch.previousLocationInView(self)
18
19
20
21         var ofX = curP.x - preP.x
22
23         var ofY = curP.y - preP.y
24
25
26
27         self.transform = CGAffineTransformTranslate(self.transform, ofX, ofY)
28
29     }
30
31  

触摸事件简单介绍:

// 当手指开始触摸view

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

1 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
2
3 {
4
5     NSLog(@"%ld", touches.count);
6
7     NSLog(@"%s",__func__);
8
9 }

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

1 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
2
3 {
4
5     NSLog(@"%s",__func__);
6
7 }

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

1 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
2
3      NSLog(@"%s",__func__);
4
5 }

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

1 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
2
3 {
4
5
6
7 }

三:gestureReginazation

各个方法的解释

UIView拖动

OC&Swift版

 1
 2
 3
 4
 5 @interface ViewController ()
 6
 7
 8
 9 @property (weak, nonatomic) IBOutlet iCocosView *dragView;
10
11
12
13 @end
14
15
16
17 @implementation ViewController
18
19
20
21 - (void)viewDidLoad {
22
23     [super viewDidLoad];
24
25
26
27 //    self.view.transform = CGAffineTransformTranslate(self.view.transform, 100, 100);
28
29
30
31     /**
32
33      为对应的View创建并且添加手势和手势监听方法
34
35      */
36
37     UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(Drag:)];
38
39     [self.dragView addGestureRecognizer:pan];
40
41
42
43 }

/**

*  实现手势监听方法

*/

 1 -(void)Drag:(UIPanGestureRecognizer *)pan
 2
 3 {
 4
 5     //获取盘的位置
 6
 7     CGPoint p = [pan translationInView:pan.view];
 8
 9
10
11     /**
12
13      *  使用三步法实现赋值
14
15      */
16
17     //根据pan的位置获取pan的中心点
18
19     CGPoint center = pan.view.center;
20
21     center.x += p.x;
22
23     center.y += p.y;
24
25     pan.view.center = center;
26
27
28
29     //根据pan的移动设置对应View的移动
30
31     [pan setTranslation:CGPointZero inView:pan.view];
32
33 }

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

 1  @IBOutlet weak var dragViews: iCocos!
 2
 3
 4
 5     override func viewDidLoad() {
 6
 7         super.viewDidLoad()
 8
 9
10
11         var pan:UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: "Drag:")
12
13         self.dragViews.addGestureRecognizer(pan)
14
15     }
16
17
18
19     func Drag(pan:UIPanGestureRecognizer)
20
21     {
22
23         var P:CGPoint = pan.translationInView(pan.view!)
24
25         var center:CGPoint = pan.view!.center
26
27         center.x += P.x
28
29         center.y += P.y
30
31         pan.view?.center = center
32
33
34
35         pan.setTranslation(CGPointZero, inView: pan.view)
36
37     

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

手势方法简单实用:UIGestureRecognizerDelegate

#pragma mark - 手势代理方法

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

1 //- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
2
3 //{
4
5 //    return NO;
6
7 //}

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

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

1 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
2
3 {
4
5     return YES;
6
7 }

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

 1 //- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
 2
 3 //    // 获取当前的触摸点
 4
 5 //    CGPoint curP = [touch locationInView:self.imageView];
 6
 7 //
 8
 9 //    if (curP.x < self.imageView.bounds.size.width * 0.5) {
10
11 //        return NO;
12
13 //    }else{
14
15 //        return YES;
16
17 //    }
18
19 //}
20
21  

#pragma mark - 点按手势

 1 - (void)setUpTap
 2
 3 {
 4
 5     // 创建点按手势
 6
 7     UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];
 8
 9
10
11     tap.delegate = self;
12
13
14
15     [_imageView addGestureRecognizer:tap];
16
17 }
18
19
20
21 - (void)tap:(UITapGestureRecognizer *)tap
22
23 {
24
25     NSLog(@"%s",__func__);
26
27 }
28
29  

#pragma mark - 长按手势

 1 // 默认会触发两次
 2
 3 - (void)setUpLongPress
 4
 5 {
 6
 7     UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
 8
 9
10
11     [self.imageView addGestureRecognizer:longPress];
12
13 }
14
15
16
17
18
19 - (void)longPress:(UILongPressGestureRecognizer *)longPress
20
21 {
22
23
24
25     if (longPress.state == UIGestureRecognizerStateBegan) {
26
27
28
29         NSLog(@"%s",__func__);
30
31     }
32
33 }

#pragma mark - 清扫

 1 - (void)setUpSwipe
 2
 3 {
 4
 5     // 默认轻扫的方向是往右
 6
 7     UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe)];
 8
 9
10
11     swipe.direction = UISwipeGestureRecognizerDirectionUp;
12
13
14
15     [self.imageView addGestureRecognizer:swipe];
16
17
18
19     // 如果以后想要一个控件支持多个方向的轻扫,必须创建多个轻扫手势,一个轻扫手势只支持一个方向
20
21     // 默认轻扫的方向是往右
22
23     UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe)];
24
25
26
27     swipeDown.direction = UISwipeGestureRecognizerDirectionDown;
28
29
30
31     [self.imageView addGestureRecognizer:swipeDown];
32
33
34
35
36
37 }
38
39
40
41 - (void)swipe
42
43 {
44
45     NSLog(@"%s",__func__);
46
47 }

#pragma mark - 旋转手势

 1 - (void)setUpRotation
 2
 3 {
 4
 5     UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotation:)];
 6
 7     rotation.delegate = self;
 8
 9     [self.imageView addGestureRecognizer:rotation];
10
11 }
12
13
14
15 // 默认传递的旋转的角度都是相对于最开始的位置
16
17 - (void)rotation:(UIRotationGestureRecognizer *)rotation
18
19 {
20
21
22
23     self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, rotation.rotation);
24
25
26
27     // 复位
28
29     rotation.rotation = 0;
30
31
32
33     // 获取手势旋转的角度
34
35     NSLog(@"%f",rotation.rotation);
36
37 }

#pragma mark - 捏合

 1 - (void)setUpPinch
 2
 3 {
 4
 5     UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)];
 6
 7     pinch.delegate = self;
 8
 9     [self.imageView addGestureRecognizer:pinch];
10
11 }
12
13
14
15 - (void)pinch:(UIPinchGestureRecognizer *)pinch
16
17 {
18
19     self.imageView.transform = CGAffineTransformScale(self.imageView.transform, pinch.scale, pinch.scale);
20
21
22
23     // 复位
24
25
26
27     pinch.scale = 1;
28
29 }

#pragma mark - 拖拽

 1 - (void)setUpPan
 2
 3 {
 4
 5     UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
 6
 7
 8
 9
10
11     [self.imageView addGestureRecognizer:pan];
12
13 }
14
15
16
17 - (void)pan:(UIPanGestureRecognizer *)pan
18
19 {
20
21     // 获取手势的触摸点
22
23     CGPoint curP = [pan locationInView:self.imageView];
24
25
26
27     // 移动视图
28
29     // 获取手势的移动,也是相对于最开始的位置
30
31     CGPoint transP = [pan translationInView:self.imageView];
32
33
34
35     self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, transP.x, transP.y);
36
37
38
39     // 复位
40
41     [pan setTranslation:CGPointZero inView:self.imageView];
42
43
44
45     NSLog(@"%@",NSStringFromCGPoint(curP));
46
47 }
48
49  

手势状态:

 1 statetypedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
 2
 3     // 没有触摸事件发生,所有手势识别的默认状态
 4
 5     UIGestureRecognizerStatePossible,
 6
 7     // 一个手势已经开始但尚未改变或者完成时
 8
 9     UIGestureRecognizerStateBegan,
10
11     // 手势状态改变
12
13     UIGestureRecognizerStateChanged,
14
15     // 手势完成
16
17     UIGestureRecognizerStateEnded,
18
19     // 手势取消,恢复至Possible状态
20
21     UIGestureRecognizerStateCancelled,
22
23     // 手势失败,恢复至Possible状态
24
25     UIGestureRecognizerStateFailed,
26
27     // 识别到手势识别
28
29     UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded
30
31 };
32
33  

四:加速计:(运动)

1 - (void)orientationChanged:(NSNotification *)notification {
2
3
4
5      // Respond to changes in device orientation
6
7
8
9 }
 1 - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
 2
 3
 4
 5     if (motion == UIEventSubtypeMotionShake)
 6
 7
 8
 9     {
10
11
12
13         // User was shaking the device. Post a notification named "shake."
14
15
16
17         [[NSNotificationCenter defaultCenter] postNotificationName:@"shake" object:self];
18
19
20
21      }
22
23
24
25 }

五:远程控制

注册:

 1 MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
 2
 3
 4
 5 [commandCenter.playCommand addTargetUsingBlock:^(MPRemoteCommandEvent *event) {
 6
 7
 8
 9     // Begin playing the current track.
10
11
12
13     [[MyPlayer sharedPlayer] play];
14
15
16
17 }

使用

 1 - (void)configureNowPlayingInfo:(MPMediaItem*)item{
 2
 3
 4
 5     MPNowPlayingInfoCenter* info = [MPNowPlayingInfoCenter defaultCenter];
 6
 7
 8
 9     NSMutableDictionary* newInfo = [NSMutableDictionary dictionary];
10
11
12
13     NSSet* itemProperties = [NSSet setWithObjects:MPMediaItemPropertyTitle,
14
15
16
17           MPMediaItemPropertyArtist,
18
19
20
21           MPMediaItemPropertyPlaybackDuration,
22
23
24
25           MPNowPlayingInfoPropertyElapsedPlaybackTime,
26
27
28
29           nil];
30
31
32
33
34
35
36
37     [item enumerateValuesForProperties:itemProperties
38
39
40
41           usingBlock:^(NSString *property, id value, BOOL *stop) {
42
43
44
45         [newInfo setObject:value forKey:property];
46
47
48
49     }];
50
51
52
53
54
55
56
57     info.nowPlayingInfo = newInfo;
58
59
60
61 }
时间: 2024-08-08 01:29:34

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

iOS开发——多线程OC篇&amp;多线程详解

多线程详解 前面介绍了多线程的各种方式及其使用,这里补一点关于多线程的概念及相关技巧与使用,相信前面不懂的地方看了这里之后你就对多线程基本上没有什么问题了! 1——首先ios开发多线程中必须了解的概念: 进程 正在进行中的程序被称为进程,负责程序运行的内存分配 每一个进程都有自己独立的虚拟内存空间 线程 线程是进程中一个独立的执行路径(控制单元) 一个进程中至少包含一条线程,即主线程 可以将耗时的执行路径(如:网络请求)放在其他线程中执行 创建线程的目的就是为了开启一条新的执行路径,运行指定的代

ios开发——实战OC篇&amp;FMDB详解

FMDB详解 前一篇文章中我们介绍的SQLite的使用,在iOS中原生的SQLite API在使用上相当不友好. 于是,就出现了一系列将SQLite API进行封装的库,例如FMDB.PlausibleDatabase.sqlitepersistentobjects等,FMDB (https://github.com/ccgus/fmdb) 是一款简洁.易用的封装库,这一篇文章简单介绍下FMDB的使用. 在FMDB下载文件后,工程中必须导入,并使用 libsqlite3.dylib 依赖包. F

iOS开发——屏幕适配篇&amp;Masonry详解

Masonry详解 前言 1 MagicNumber -> autoresizingMask -> autolayout 以上是纯手写代码所经历的关于页面布局的三个时期 在iphone1-iphone3gs时代 window的size固定为(320,480) 我们只需要简单计算一下相对位置就好了 在iphone4-iphone4s时代 苹果推出了retina屏 但是给了码农们非常大的福利:window的size不变 在iphone5-iphone5s时代 window的size变了(320,5

iOS开发——实用技术OC篇&amp;多线程整合

多线程整合 本文知识对iOS开发中多线程的一些知识整合,关于一些概念和技术问题并没有过多的介绍,如果你想了解更多请查看笔者之前写的iOS开发之多线程详解(比较完整):但是有部分涉及到之前文章中没有的技术点和常识,比如加锁的方式,面试相关的,还有一些关于GCD的高级用法,希望你能认真看完,或许可以收获到很多! http://www.cnblogs.com/iCocos/p/4553103.html http://www.cnblogs.com/iCocos/p/4553262.html ??先来看

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

单例模式的实实现(ACR&MRC) 在iOS开发中单例模式是一种非常常见的模式,虽然我们自己实现的比较少,但是,系统却提供了不少的到来模式给我们用,比如最常见的UIApplication,Notification等, 那么这篇文章就简单介绍一下,我们开发中如果想要实现单例模式要怎么去实现! 单例模式顾名思义就是只有一个实例,它确保一个类只有一个实例,并且自行实例化并向整个系统提供这个实例.它经常用来做应用程序级别的共享资源控制.这个模式使用频率非常高,通过一个单例类,可以实现在不同窗口之间传递数

iOS开发——实用技术OC篇&amp;UIWebView与JS的交互

UIWebView与JS的交互 事情的起因还是因为项目需求驱动.折腾了两天,由于之前没有UIWebView与JS交互的经历,并且觉得这次在功能上有一定的创造性,特此留下一点文字,方便日后回顾. 我要实现这样一个需求:按照本地的CSS文件展示一串网络获取的带HTML格式的只有body部分的文本,需要自己拼写完整的HTML.除此之外,还需要禁用获取的HTML文本中自带的 < img > 标签自动加载,并把下载图片的操作放在native端来处理,并通过JS将图片在Cache中的地址返回给UIWebv

iOS开发——实用技术OC篇&amp;?Invocation简单介绍

Invocation简单介绍 方法一:运行时方法:(这里在之前的文章定时器的几种方法中说过:www.cnblogs.com/iCocos/p/4694581.html) 1:创建一个签名: NSMethodSignature *singature = [NSMethodSignature signatureWithObjCTypes:"[email protected]:"]; 这里我想如果你仔细的话肯定注意到了:后面的“[email protected]:”,这里是运行时的语法在这里

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

简单抽屉效果的实现 就目前大部分App来说基本上都有关于抽屉效果的实现,比如QQ/微信等.所以,今天我们就来简单的实现一下.当然如果你想你的效果更好或者是封装成一个到哪里都能用的工具类,那就还需要下一些功夫了,我们这里知识简单的介绍怎么去实现,不过一般我们开发都是找别人做好的,也没必要烂肺时间,除非你真的是大牛或者闲的蛋疼. 其实关于抽屉效果就是界面有三个View,其实一个主View其他两个分别是左边和右边的View,我们分别为他们添加手势,实现左右滑动显示对应的View. 一:所以,首先我们需

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

8行代码教你搞定导航控制器全屏滑动返回效果 前言 此次文章,讲述的是导航控制器全屏滑动返回效果,而且代码量非常少,10行内搞定. 效果如图: 如果喜欢我的文章,可以关注我,也可以来小码哥,了解下我们的iOS培训课程.陆续还会有更新ing.... 一.自定义导航控制器 目的:以后需要使用全屏滑动返回功能,就使用自己定义的导航控制器. 二.分析导航控制器侧滑功能 效果:导航控制器默认自带了侧滑功能,当用户在界面的左边滑动的时候,就会有侧滑功能. 系统自带的侧滑效果: 分析: 1.导航控制器的view