iOS Programming Touch Events and UIResponder,iosuiresponder

來源:互聯網
上載者:User

iOS Programming Touch Events and UIResponder,iosuiresponder

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

}

 

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.