2012-07-11 43 views
2

我有一個包含3個獨立子視圖的父視圖。孩子的意見分散在父母之間,沒有重疊(並且有一定的空間)。當用戶在屏幕上移動她的手指(而不是提起它)時,我想在他們進入和退出每個子視圖時跟蹤觸摸。在一個動作中觀察多個視圖的觸動

示例如果用戶開始觸摸子視圖外部的屏幕上的某個位置,然後將其手指劃過兒童1,兒童1之外,兒童2之上,然後放開,我期望這些事件被觸發:

  1. 觸摸開始
  2. 觸摸輸入的孩子1
  3. 觸摸退出孩子1
  4. 觸摸輸入的孩子2
  5. 觸摸結束

看來,如果的touchesBegan:withEvent:方法和touchesEnded:withEvent:方法方法將是在這種情況下有益的,但是當我確定他們對孩子視圖控制器,他們不這樣做正是我想要的 - - 如果用戶開始觸摸子視圖外,然後在子視圖上滑動,則不會觸發子項本身的觸摸事件。

當前解決方案:我目前正在使用一種解決方案,覺得很難做到這一點。我正在觀察touchesBegan:withEvent :, touchesEnded:withEvent :,並touchesMoved:withEvent:在父級上,獲取每個事件的座標,並確定它們是否位於孩子的範圍內。如果他們這樣做,我會觸發如上所述的適當事件。

這種方法主要工作,但感覺非常低效。感覺框架應該爲我處理這項工作。我的國家管理代碼有時會錯過一個「輸入」或「退出」的觸發器,我懷疑這是因爲觸摸事件不是按照意想不到的順序丟棄或傳到我的。我在這裏錯過了一個更好的方法嗎?

+0

我相信性能使觸摸獨佔的,所以如果你開始在一個人慣於檢測,我想我讀一些有關啓用兩個觀點的多點觸摸或東西此目的。但我只是在這裏猜測。 – Pochi 2012-07-12 00:13:45

+0

在父視圖上執行此操作,使用CGRectContainsPoint來查看locationInView位於其中一個子項的框架中。我現在不在我的計算機上,但可以在我回家時向您展示一個示例。 – Rob 2012-07-12 01:10:07

回答

2

最簡單的辦法是這樣的:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; 
    [self.view addGestureRecognizer:pan]; 

    // Do any additional setup after loading the view. 
} 

- (void)pan:(UIPanGestureRecognizer *)sender 
{ 
    static NSInteger startViewIndex; 
    static NSInteger endViewIndex; 
    CGPoint location = [sender locationInView:self.view]; 

    if (sender.state == UIGestureRecognizerStateBegan) 
    { 
     if (CGRectContainsPoint(self.view0.frame, location)) 
      startViewIndex = 0; 
     else if (CGRectContainsPoint(self.view1.frame, location)) 
      startViewIndex = 1; 
     else if (CGRectContainsPoint(self.view2.frame, location)) 
      startViewIndex = 2; 
     else 
      startViewIndex = -1; 
    } 
    else if (sender.state == UIGestureRecognizerStateEnded) 
    { 
     if (CGRectContainsPoint(self.view0.frame, location)) 
      endViewIndex = 0; 
     else if (CGRectContainsPoint(self.view1.frame, location)) 
      endViewIndex = 1; 
     else if (CGRectContainsPoint(self.view2.frame, location)) 
      endViewIndex = 2; 
     else 
      endViewIndex = -1; 

     if (startViewIndex != -1 && endViewIndex != -1 && startViewIndex != endViewIndex) 
     { 
      // successfully moved between subviews! 
      NSLog(@"Moved from %1d to %1d", startViewIndex, endViewIndex); 
     } 
    } 
} 

也許有點更優雅是定義自己的自定義手勢識別(這樣,如果你不從子視圖中拖動一個,它會失敗,這將允許其他手勢識別器您可能正在進行其他工作......可能不是一個問題,除非您使用多個手勢識別器;它還將手勢邏輯的血淋淋的細節與視圖控制器的其餘部分隔離開來):

@interface PanBetweenSubviewsGestureRecognizer : UIPanGestureRecognizer 
{ 
    NSMutableArray *_arrayOfFrames; 
} 

@property NSInteger startingIndex; 
@property NSInteger endingIndex; 

@end 

@implementation PanBetweenSubviewsGestureRecognizer 

@synthesize startingIndex = _startingIndex; 
@synthesize endingIndex = _endingIndex; 

- (void)dealloc 
{ 
    _arrayOfFrames = nil; 
} 

- (id)initWithTarget:(id)target action:(SEL)action 
{ 
    self = [super initWithTarget:target action:action]; 
    if (self) 
    { 
     _arrayOfFrames = [[NSMutableArray alloc] init]; 
    } 
    return self; 
} 

- (void)addSubviewToArrayOfFrames:(UIView *)view 
{ 
    [_arrayOfFrames addObject:[NSValue valueWithCGRect:view.frame]]; 
} 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    [super touchesBegan:touches withEvent:event]; 

    UITouch *touch = [touches anyObject]; 
    CGPoint location = [touch locationInView:self.view]; 

    for (NSInteger i = 0; i < [_arrayOfFrames count]; i++) 
    { 
     if (CGRectContainsPoint([[_arrayOfFrames objectAtIndex:i] CGRectValue], location)) 
     { 
      self.startingIndex = i; 
      return; 
     } 
    } 

    self.startingIndex = -1; 
    self.endingIndex = -1; 
    self.state = UIGestureRecognizerStateCancelled; 
} 

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    [super touchesEnded:touches withEvent:event]; 

    UITouch *touch = [touches anyObject]; 
    CGPoint location = [touch locationInView:self.view]; 

    for (NSInteger i = 0; i < [_arrayOfFrames count]; i++) 
    { 
     if (CGRectContainsPoint([[_arrayOfFrames objectAtIndex:i] CGRectValue], location)) 
     { 
      self.endingIndex = i; 
      return; 
     } 
    } 

    self.endingIndex = -1; 
    self.state = UIGestureRecognizerStateCancelled; 
} 

@end 

然後你可以爲使用如下:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    PanBetweenSubviewsGestureRecognizer *pan = [[PanBetweenSubviewsGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; 
    [pan addSubviewToArrayOfFrames:self.view0]; 
    [pan addSubviewToArrayOfFrames:self.view1]; 
    [pan addSubviewToArrayOfFrames:self.view2]; 

    [self.view addGestureRecognizer:pan]; 

    // Do any additional setup after loading the view. 
} 

- (void)pan:(PanBetweenSubviewsGestureRecognizer *)sender 
{ 
    if (sender.state == UIGestureRecognizerStateEnded && sender.startingIndex >= 0 && sender.endingIndex >= 0 && sender.startingIndex != sender.endingIndex) 
    { 
     // successfully moved between subviews! 
     NSLog(@"Moved from %1d to %1d", sender.startingIndex, sender.endingIndex); 
    } 
} 
+0

令人難以置信的詳細答案 - 非常感謝!我想看起來好像我不得不從父類中手動解除這個問題是正確的,但手勢識別器肯定會清理一些事情,並確保觸摸開始/結束事件按照正確的順序進行。 – 2012-07-12 07:45:19

相關問題