iOS Programming Touch Events and UIResponder 

1 Touch Events 

As a subclass of UIResponder, a UIView can override four methods to handle the four distinct touch events:

作为UIResponder的一个子类,UIView可以重写四个方法来处理touch events。

(1)

a finger or fingers touches the screen 开始触摸
- (void)touchesBegan:(NSSet *)touches

withEvent:(UIEvent *)event;

(2)a finger or fingers moves across the screen (this message is sent repeatedly as a finger moves)滑动

- (void)touchesMoved:(NSSet *)touches

withEvent:(UIEvent *)event;

(3)a finger or fingers is removed from the screen 从屏幕上移除

- (void)touchesEnded:(NSSet *)touches

withEvent:(UIEvent *)event;

(4)a system event, like an incoming phone call, interrupts a touch before it ends 系统事件,比如一个电话进来,在它ends 之前打断了touch . 

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

 

When a finger touches the screen, an instance of UITouch is created.

当手指触摸屏幕时,一个UITouch 的实例就被创建了。 

The UIView that this finger touched  is sent the message touchesBegan:withEvent: and the UITouch is in the NSSet of touches.

手指触摸的UIView 就会被发送消息touchesBegan:withEvent。并且UITouch 是一系列的触摸集合。

 

As that finger moves around the screen, the touch object is updated to contain the current location of the finger on the screen.

当手指在屏幕上移动时,touch object就会被更新 来保鲜现在手指的位置。

Then, the same UIView that the touch began on is sent the message touchesMoved:withEvent:.

相同的UIView 就会被发送touchesMoved:withEvent。

The NSSet that is passed as an argument to this method contains the same UITouch that originally was created when the finger it represents touched the screen.

被传递参数的NSSet 包含 相同的UITouch。

 

When a finger is removed from the screen, the touch object is updated one last time to contain the current location of the finger, and the view that the touch began on is sent the message touchesEnded:withEvent:. After that method finishes executing, the UITouch object is destroyed.

当手指从屏幕上移走时,也会更新touch object 。会发送给UIView,touchesEnded:withEvent。在这个方法完成后,UITouch就会被销毁。

 

(1)One UITouch corresponds to one finger on the screen. This touch object lives as long as the finger is on the screen and always contains the current position of the finger on the screen.

(2)The view that the finger started on will receive every touch event message for that finger no matter what. If the finger moves outside of the UIView's frame that it began on, that view still receives the touchesMoved:withEvent: and touchesEnded:withEvent: messages. Thus, if a touch begins on a view, then that view owns the touch for the life of the touch.

所以如果一个touch 从一个view 开始,那么这个view 拥有这个touch 的这个生命周期。

(3) You do not have to – nor should you ever – keep a reference to a UITouch object. The application will give you access to a touch object when it changes state.

你不需要,也不应该有一个引用对UITouch。 当它的状态改变时,application将会给你它的获取。

Every time a touch does something, like begins, moves, or ends, a touch event is added to a queue of events that the UIApplication object manages.

一个事件被添加到被UIApplication管理的一个事件队列中。

In practice, the queue rarely fills up, and events are delivered immediately. The delivery of these touch events involves sending one of the UIResponder messages to the view that owns the touch.

touch event的传递包括发送一个UIResponder消息到拥有touch 的view。

 

What about multiple touches? If multiple fingers do the same thing at the exact same time to the same view, all of these touch events are delivered at once. Each touch object – one for each finger – is included in the NSSet passed as an argument in the UIResponder messages.

如何处理多点触摸?

如果是多个手指做相同的事情在相同的时间,所有的这些触摸事件就会一次被传递。每一个touch object ,每一个finger,包含在一个NSSet 中,作为UIResponder消息的一个参数。 

However, the window of opportunity for the "exact same time" is fairly short. So, instead of one responder message with all of the touches, there are usually multiple responder messages with one or more of the touches.

因为相同时间太少了,因此取而代之的事,多个responder 消息有一个或多个touches。

2Creating the TouchTracker Application

  let's get started with your application. In Xcode, create a new Empty Application iPhone project and

name it TouchTracker.

 

#import <Foundation/Foundation.h> @interface BNRLine : NSObject

@property (nonatomic) CGPoint begin; @property (nonatomic) CGPoint end;

@end

 

Next, create a new NSObject subclass called BNRDrawView. In BNRDrawView.h, change the superclass to UIView.

@interface BNRDrawView : UIView @end

@interface LKLine : NSObject

@property(nonatomic)CGPoint begin;

@property(nonatomic)CGPoint end;

@end

 

@interface LKDrawView : UIView

 

@end

 

-(void)loadView{

    self.view=[[LKDrawView alloc] initWithFrame:CGRectZero];

    
 

}

 LKDrawViewController *drawViewController=[[LKDrawViewController alloc] init];

self.window.rootViewController=drawViewController;

 

3. Drawing with BNRDrawView

 

#import "BNRDrawView.h" #import "BNRLine.h"

@interface BNRDrawView ()

@property (nonatomic, strong) BNRLine *currentLine; @property (nonatomic, strong) NSMutableArray *finishedLines;

@end

 

- (instancetype)initWithFrame:(CGRect)r

{
self = [super initWithFrame:r];

if (self) {
self.finishedLines = [[NSMutableArray alloc] init];

self.backgroundColor = [UIColor grayColor]; }

return self; }

 

- (void)strokeLine:(BNRLine *)line

{
UIBezierPath *bp = [UIBezierPath bezierPath]; bp.lineWidth = 10;
bp.lineCapStyle = kCGLineCapRound;

[bp moveToPoint:line.begin]; [bp addLineToPoint:line.end]; [bp stroke];

}

 

- (void)drawRect:(CGRect)rect

{
// Draw finished lines in black
[[UIColor blackColor] set];
for (BNRLine *line in self.finishedLines) {

[self strokeLine:line]; }

if (self.currentLine) {
// If there is a line currently being drawn, do it in red [[UIColor redColor] set];
[self strokeLine:self.currentLine];

} }

 

4 Turning Touches into Lines

A line is defined by two points. Your BNRLine stores these points as properties named begin and end.

 

When a touch begins, you will create a line and set both begin and end to the point where the touch began. When the touch moves, you will update end. When the touch ends, you will have your complete line.

当触摸开始时,就设置begin和end 属性,当移动时,就更新end 。当touch 结束,就完成了line。 

 

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

    UITouch *touch=[touches anyObject];

    CGPoint location=[touch locationInView:self];

    self.currentLine=[[LKLine alloc]init];

    self.currentLine.begin=location;

    self.currentLine.end=location;

    
 

    [self setNeedsDisplay];

}

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

    UITouch *touch=[touches anyObject];

    CGPoint location=[touch locationInView:self];

    self.currentLine.end=location;

    [self setNeedsDisplay];

    
 

}

 

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

    [self.finishedLines addObject:self.currentLine];

    self.currentLine=nil;

    [self setNeedsDisplay];

}

 

5  Handling multiple touches

By default, a view will only accept one touch at a time.

默认情况下,view 只能在同一时刻接受一个touch。

If one finger has already triggered touchesBegan:withEvent: but has not finished – and therefore has not triggered touchesEnded:withEvent: – subsequent touches are ignored.

如果一个手指已经触发了touchesBegan:withEvent,但是还没有结束,因此没有触发touchesEnded:withEvent:, 它的子序列touch 将会被忽略。

In this context, "ignore" means that the BNRDrawView will not be sent touchesBegan:withEvent: or any other UIResponder messages related to the extra touches.

ignore的意思是BNRDrawView将不会被送touchesBegan:withEvent或者任何其他的与多余的touches相关的UIResponder消息 

 

In BNRDrawView.m, enable BNRDrawView instances to accept multiple touches.

        self.multipleTouchEnabled=YES;

Now that BNRDrawView will accept multiple touches, each time a finger touches the screen, moves, or is removed from the screen, the view will receive the appropriate UIResponder message.

这个时候就可以接受对应的UIResponder消息了。

However, this now presents a problem: your UIResponder code assumes there will only be one touch active and one line being drawn at a time.

你的UIResponder code 假设只有一个touch active 并且在同一时间只能画一条线。

 

Notice, first, that each touch handling method you have already implemented sends the message anyObject to the NSSet of touches it receives.

In a single-touch view, there will only ever be one object in the set, so asking for any object will always give you the touch that triggered the event.

在single-touch view, 在一个set 中只有一个对象,所以要求任意对象将会触发事件。

 

In a multiple touch view, that set could contain more than one touch.

在multiple touch view,set 可能含有多个touch。 

 

While you could create a few more properties, like currentLine1 and currentLine2, you would have to go to considerable lengths to manage which instance variable corresponds to which touch.

 

Instead of the multiple property approach, you can use an NSMutableDictionary to hang on to each BNRLine in progress.

 你可以用字典来代表在程序中得line。 

The key to store the line in the dictionary will be derived from the UITouch object that the line corresponds to.

存储line 在字典中的关键字将会从 这个line 对应的UITouch 对象中获取。 

As more touch events occur, you can use the same algorithm to derive the key from the UITouch that triggered the event and use it to look up the appropriate BNRLine in the dictionary.

 

notice the use of valueWithNonretainedObject: to derive the key to store the BNRLine.

This method creates an NSValue instance that holds on to the address of the UITouch object that will be associated with this line.

这个方法创建了一个NSValue 实例,来保持这个UITouch对象的地址。

 Since a UITouch is created when a touch begins, updated throughout its lifetime, and destroyed when the touch ends, the address of that object will be constant through each touch event message.

因为一个UITouch 在touch开始创建,在生命周期更新,在touch end 销毁,因此这个对象的地址在整个touch event 是个常量。

 for (UITouch *touch in touches) {

        CGPoint location=[touch locationInView:self];

        LKLine *line=[[LKLine alloc]init];

        line.begin=location;

        line.end=location;

        NSValue *key=[NSValue valueWithNonretainedObject:touch];

        self.linesInProgress[key]=line;

        
 

    }

 

 

why not use the UITouch itself as the key? Why go through the hoop of creating an NSValue? Objects used as keys in an NSDictionary must conform to the NSCopying protocol, which allows them to be copied by sending the message copy. UITouch instances do not conform to this protocol because it does not make sense for them to be copied. Thus, the NSValue instances hold the address of the UITouch so that equal NSValue instances can be later created with the same UITouch.

 

 

The last thing left for the basics of TouchTracker is to handle what happens when a touch is cancelled.

最后一件事当触摸被取消如何处理

A touch can be cancelled when an application is interrupted by the operating system (for example, a phone call comes in) when a touch is currently on the screen.

When a touch is cancelled, any state it set up should be reverted.

如果一个touch 被取消,它的任何设置状态应该被取消。

-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
    NSLog(@"%@",NSStringFromSelector(_cmd));
    for (UITouch *touch in touches) {
        NSValue *key=[NSValue valueWithNonretainedObject:touch];
        [self.linesInProgress removeObjectForKey:key];
    }
    [self setNeedsDisplay];

}

 

 

 

 

 

iOS Programming Touch Events and UIResponder的更多相关文章

  1. ios Programming:The Big Nerd Ranch Guid(6th Edition) (Joe Conway & AARON HILLEGASS 著)

    Introduction (已看) Prerequisites What Has Changed in the Sixth Edition? Our Teaching Philosophy How t ...

  2. iOS Programming UIGestureRecognizer and UIMenuController

    iOS  Programming  UIGestureRecognizer and UIMenuController A UIGestureRecognizer intercepts touches ...

  3. iOS programming Delegation and Text Input

    iOS programming Delegation and Text Input  1.1 Text Fields    CGRect textFieldRect = CGRectMake(40, ...

  4. iOS学习——(转)UIResponder详解

    本文转载自:ios开发 之 UIResponder详解 我们知道UIResponder是所有视图View的基类,在iOS中UIResponder类是专门用来响应用户的操作处理各种事件的,包括触摸事件( ...

  5. iOS Programming Camera 2

    iOS Programming Camera  2  1.1 Creating BNRImageStore The image store will fetch and cache the image ...

  6. iOS Programming Views :Redrawing and UIScrollView

    iOS Programming Views :Redrawing and UIScrollView  1.1 event  You are going to see how views are red ...

  7. iOS Programming View and View Hierarchy 视图和视图等级

    iOS Programming  View and View Hierarchy 视图和视图等级 1.1(1)File → New → Project.. From the iOS section, ...

  8. 【开发】iOS入门 - Touch事件处理学习笔记

    网上介绍iOS事件机制的文章,有不少都讲得很好,搬运一次意义不大,这里我就列一些要点吧. 跟Android一样,iOS的Touch事件也是从外到内传递,然后从内到外响应,可以看成一个U型结构.然而,个 ...

  9. iOS programming UITableView and UITableViewController

    iOS programming  UITableView and UITableViewController A UITableView displays a single column of dat ...

随机推荐

  1. 使用JDBC 插入向数据库插入对象

    package com.ctl.util; import java.io.IOException; import java.lang.reflect.Field; import java.lang.r ...

  2. jdbc 连 oracle 12c

    jdbc 连 oracle 12c,除了连接串要书写正确(如果用PDB,可插拔数据库),必要的JDBC包也是不可或缺的. 比如我,机器本身装了个oracle 10g,然后上面有个java项目,使用jd ...

  3. mktemp temp race attack 临时文件隐患

    /tmp  安全隐患 -/tmp   在家目录  程序目录下 创建 临时文件

  4. 关于Vim的一个配置文件

    昨天晚上+今天早上怒赶了一份关于Vim的自动化配置的Shell脚本,之前在github上见过一个这么一个类似的脚本项目,然后又见到同校的有一位师兄也写过这么一个类似的脚本文件,然后我也抽分跟着写一份属 ...

  5. ubuntu中pytesseract 安装与使用示例

    1. 安装 tesseract-ocr 包 安装方法: sudo apt-get install tesseract-ocr 2. 安装 PIL PIL(python imaging library) ...

  6. uoj 30 tourists

    题目大意: 一个无向图 每个点有权值 支持两个操作 1 修改某个点的权值 2 查询a-b所有简单路径的点上的最小值 思路: 可以把图变成圆方树 然后树链剖分 维护 对于每个方点使用可删堆维护 #inc ...

  7. IJ:IJ来了2-调试开发环境

    ylbtech-IJ:IJ来了2 1.返回顶部 1. 2. 3. 4. 2. 配置SVN返回顶部 1.SVN安装时,要选上command line client tools 2. 3.   4. 3. ...

  8. 小程序-文章:微信小程序常见的UI框架/组件库总结

    ylbtech-小程序-文章:微信小程序常见的UI框架/组件库总结 1.返回顶部 1. 想要开发出一套高质量的小程序,运用框架,组件库是省时省力省心必不可少一部分,随着小程序日渐火爆,各种不同类型的小 ...

  9. H5的draggable属性和jqueryUI.sortable

    拖放 拖放是一种常见的特性,即抓取对象以后拖到另一个位置. 一.HTML5 新特性 在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放. Event On Event Handler 描述 d ...

  10. 洛谷 P4014 分配问题 【最小费用最大流+最大费用最大流】

    其实KM更快--但是这道题不卡,所以用了简单粗暴的费用流,建图非常简单,s向所有人连流量为1费用为0的边来限制流量,所有工作向t连流量为1费用为0的边,然后对应的人和工作连(i,j,1,cij),跑一 ...