12章 Touch Events and UIResponder 触摸事件touch events,手势 gestures, 调试 debugging application UIView 继承UIResponder,所以可以重写以下四个方法: touchBegan:(NSSet *)touches withEvent: touchMoved:withEvent: touchEnded:withEvent: touchCancel:withEvent: touche中有个UITouch的对象,包含了触碰的位置等信息 你不需要保存UITouch的对象,因为在事件中你可以访问得到。 当手指滑出初始触碰到视图,会受到touchMoved和touchEnded ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 重写几个touch事件,获取location。 // setNeedDisplay,系统自动调用drawRect, // 如何绘制、设置颜色、stoke等。 #import "BNRDrawView.h" #import "BNRLine.h" @interface BNRDrawView() @property (nonatomic,strong) NSMutableArray *finishedLines; @property (nonatomic,strong) BNRLine *currentLine; @end @implementation BNRDrawView -(instanceType)initWithFrame:(CGRect)r { self = [super initWithFrame:r]; if(self) { self.finishedLines = [[NSMutableArray alloc] init]; self.backgroundColor = [UIColor grayColor]; } } - (void) strokeLine: (BNRLine *)line { UIBezierPath *bp = [UIBezierPath bezierPath]; bp.lineWith = 10; bp.lineCapStyle = kCGLineCapRound; [bp moveToPoint:line.begin]; [bp addLineToPoint: line.end]; [bp stroke]; } -(void)drawRect:(CGRect) rect { // 每次都要重新遍历finishedLines再重新绘制??? [[UIColor blackColor] set]; for(BNRLine *line in self.finishedLines] { [self strokeLine:line]; } if(self.currentLine){ [[UIColor redColor] set]; [self strokeLine:self.currentLine]; } } - (void) touchBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView:self]; self.currentLine = [[BNRLine alloc] init]; self.currentLine.begin = location; self.currentLine.end = location; [self setNeedDisplay]; } - (void) touchMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *t = [touches anyObject]; CGPoint location = [t locationInView:self]; self.currentLine.end = location; [self setNeedDisplay]; } -(void) touchEnded:(NSSet *)touches withEvent:(UIEvent *)event { [self.finishedLines addObject:self.currentLine]; self.currentLine = nil; [self setNeedDisplay]; } @end ----------------------------------------------------------------------- 多点触控。 默认情况下一个view只能接受一个finger的touch: 一个手指触发了touchBegan,但是没有ended。则view会忽略其他触碰 self.multipleTouchEnabled = YES; touchCancelled发生在系统事件,比如电话来了~,一般这时候会把当前线段都移除掉 保存多个数据 for (UITouch *t in touches) { CGPoint location = [t locationInView:self]; BNRLine *line = [[BNRLine alloc] init]; line.begin = location; line.end = location; NSValue *key = [NSValue valueWithNonretainedObject:t]; self.linesInProgress[key] = line; } //用NSValue *key来作为字典的key而不是直接用t,因为字典的key是实现了NSCopying协议 ------------------------------------------------------------------------ #import "BNRDrawView.h" #import "BNRLine.h" @interface BNRDrawView { @property (nonatomic,strong) NSMutableDictionary *linesInProgress; @property (nonatomic,strong) NSMutableArray *finishedLines; // @property (nonatomic,strong) BNRLine *currentLine; } @end @implementation BNRDrawView -(instanceType)initWithFrame:(CGRect)r { self = [super initWithFrame:r]; if(self) { self.linesInProgress = [[NSMutableArray] alloc] init]; self.finishedLines = [[NSMutableArray alloc] init]; self.backgroundColor = [UIColor grayColor]; } } - (void) strokeLine: (BNRLine *)line { UIBezierPath *bp = [UIBezierPath bezierPath]; bp.lineWith = 10; bp.lineCapStyle = kCGLineCapRound; [bp moveToPoint:line.begin]; [bp addLineToPoint: line.end]; [bp stroke]; } -(void)drawRect:(CGRect) rect { // finished [[UIColor blackColor] set]; for(BNRLine *line in self.finishedLines] { [self strokeLine:line]; } // current progress [[UIColor redColor] set]; for(BNRLine *line in self.linesInProgress){ [self strokeLine:line]; } } - (void) touchBegan:(NSSet *)touches withEvent:(UIEvent *)event { for(UITouch *t in touches){ CGPoint location = [t locationInView:self]; NSValue *key = [NSValue valueWithNonretainedObject:t]; BNRLine *line = [[BNRLine alloc] init]; line.begin = location; line.end = location; self.linesInProgress[key] = line; } [self setNeedDisplay]; } - (void) touchMoved:(NSSet *)touches withEvent:(UIEvent *)event { for(UITouch *t in touches){ CGPoint location = [t locationInView:self]; NSValue *key = [NSValue valueWithNonretainedObject:t]; BNRLine *line = self.linesInProgress[key]; line.end = location; } [self setNeedDisplay]; } -(void) touchEnded:(NSSet *)touches withEvent:(UIEvent *)event { for(UITouch *t in touches){ NSValue *key = [NSValue valueWithNonretainedObject:t]; BNRLine *line = self.linesInProgress[key]; [self.finishedLines addObject:line]; [self.linesInProgress removeObjectForKey:key]; } [self setNeedDisplay]; } -(void) touchCancelled:(NSSet *)touches withEvent:(UIEvent *)event { for(UITouch *t in touches){ NSValue *key = [NSValue valueWithNonretainedObject:t]; [self.linesInProgress removeObjectForKey:key]; } [self setNeedDisplay]; } @end Responder chain 每个responder有一个nextResponder属性,构成chain。 rootView: window's nextResponder is UIApplication ' UIControl:can set targets and actions the superclass of UIButton,UISlider... [rButton addTarget:tempController action:@selector(resetTemperature:) forControlEvents:UIControlEventTouchUpInSide | UIControlEventTouchUpOutSide] then you can send event: [self sendActionsForControlEvents:UIControlEventTouchUpInSide] 消息不是直接发送给目标view,而是通过UIApplication来找到target -----------重写UIResponder--------------------- - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { // Reference to the touch that is ending UITouch *touch = [touches anyObject]; // Location of that point in this control's coordinate system CGPoint touchLocation = [touch locationInView:self]; // Is that point still in my viewing bounds? if (CGRectContainsPoint(self.bounds, touchLocation)) { // Send out action messages to all targets registered for this event! [self sendActionsForControlEvents:UIControlEventTouchUpInside]; } else { // The touch ended outside the bounds, different control event [self sendActionsForControlEvents:UIControlEventTouchUpOutside]; } }
浙公网安备 33010602011771号