IOS Programming Touch Events and UIResponder, iosuireinform der

Source: Internet
Author: User

IOS Programming Touch Events and UIResponder, iosuireinform der

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:

As a subclass of UIResponder, UIView can rewrite four methods to process touch events.


A finger or fingers touches the screen starts to touch
-(Void) touchesBegan :( NSSet *) touches

WithEvent :( UIEvent *) event;

(2) a finger or fingers moves sliding ss 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 system event. For example, if a call comes in, touch is interrupted before it is enabled.

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


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

When you touch the screen with your fingers, a UITouch instance is created.

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

The UIView with the finger touch will be sent with the message touchesBegan: withEvent. And UITouch is a collection of touch.


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

When the finger moves on the screen, the touch object will be updated to keep its position fresh.

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

The same UIView will be sent with 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.

The NSSet of the passed parameter contains the same 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 will also be updated when the finger moves from the screen. Will be sent to UIView, touchesEnded: withEvent. After this method is completed, UITouch will be destroyed.


(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 es 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.

So if a touch starts from a view, the view has the lifecycle of the touch.

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

You don't need it, and you shouldn't have a reference to UITouch. When its status changes, the application will give you its access.

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.

An event is added to an event queue managed by 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.

The transfer of touch event includes sending a UIResponder message to the view with touch.


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 wrongly ded in the NSSet passed as an argument in the UIResponder messages.

How to deal with multi-point touch?

If multiple fingers do the same thing at the same time, all these touch events will be transmitted once. Each touch object and each finger are included in an NSSet as a parameter of the UIResponder message.

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.

Because the same time is too short, one or more touches of multiple responder messages are replaced.

2 Creating 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.

When the touch starts, the begin and end attributes are set. When moving, the end is updated. When touch is over, line is finished.


-(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.

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

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

If a finger has triggered touchesBegan: withEvent, but it is not over yet, the touch of its subsequence will be ignored because it has not triggered touchesEnded: withEvent.

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 means that BNRDrawView will not be sent to touchesBegan: withEvent or any other UIResponder messages related to redundant touches.


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.

At this time, you can accept the corresponding UIResponder message.

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.

Your UIResponder code assumes that there is only one touch active and only one line can be drawn at a time.


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

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.

In single-touch view, there is only one object in a set, so any object is required to trigger the event.


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

In the multiple touch view, set may contain multiple touch.


While you cocould create a few more properties, like currentLine1 and currentLine2, you wocould 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.

You can use the dictionary to represent line in the program.

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

Keywords stored in the dictionary will be obtained from the UITouch object corresponding to the line.

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.

This method creates an NSValue instance to maintain the address of the UITouch object.

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.

Because a UITouch is created at touch, updated during the lifecycle, and destroyed at touch end, the address of this object is a constant throughout 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 canceled.

The last thing to do when the touch is canceled

A touch can be canceled 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 canceled, any state it set up shocould be reverted.

If a touch is canceled, its setting status should be canceled.

-(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];







Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.