2009-05-18 155 views
7

請有人可以幫助排序一個noob出來嗎?我已經在各種論壇發佈了這個問題,並沒有收到任何答案,而許多搜索其他答案已經變成了stackoverflow,所以我希望這是地方。UIScrollView觸及vs子視圖

我有一個隨機數Stone.h覆蓋的BeachView.h(UIScrollView的子類,沙灘圖片)(UIImageView的子類,一塊石頭的隨機PNG,userInteractionEnabled = YES接受觸摸)。

如果用戶在沙灘上觸摸並移動,它應該滾動。 如果用戶點擊一塊石頭,它應該調用方法「touchedStone」。 如果用戶點擊沒有石頭的海灘,它應該調用方法「touchedBeach」。

現在,我意識到這聽起來很簡單。每個人和每件事都告訴我,如果UIScrollView上有某些東西接受了它應該將控制權交給它的接觸。所以當我觸摸並拖動時,它應該滾動;但如果我點擊,並且它在石頭上,它應該忽略海灘水龍頭並接受石頭水龍頭,是的?

但是,似乎兩個視圖都接受了水龍頭,並調用touchStone和touchedBeach。此外,海灘水龍頭首先發生,所以我甚至不能放入一個「如果碰到石頭然後不碰海灘」類型的旗幟。

這是一些代碼。 在BeachView.m


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    if (self.decelerating) { didScroll = YES; } 
     else { didScroll = NO; } 

    UITouch *touch = [[event allTouches] anyObject]; 
    CGPoint touchLocation = [touch locationInView:touch.view]; 
    NSLog(@"touched beach = %@", [touch view]); 
    lastTouch = touchLocation; 
    [super touchesBegan:touches withEvent:event]; 
} 

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 
    didScroll = YES; 
    [super touchesMoved:touches withEvent:event]; 
} 

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
    if (didScroll == NO && isPaused == NO) { 
      [self touchedBeach:YES location:lastTouch]; 
    } 
    [super touchesEnded:touches withEvent:event]; 
} 

在Stone.m


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    [parent stoneWasTouched]; // parent = ivar pointing from stone to beachview 
} 

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
    UITouch *touch = [[event allTouches] anyObject]; 
    CGPoint touchLocation = [touch locationInView:touch.view]; 
    NSLog(@"touched stone = %@", [touch view]); 
    [parent touchedStone:YES location:touchLocation]; 
} 

石頭水龍頭後,我的NSLog看起來是這樣的:


Touched beach = <BeachView: 0x1276a0> 
ran touchedBeach 
Touched Stone = <Stone: 0x1480c0> 
ran touchedStone 

所以它的實際運行兩者。更奇怪的是,如果我將touchesBegan和touchesEnded從Stone.m中移出,但保留userInteractionEnabled = YES,那麼beachView寄存器都會觸及它自己,但會返回Stone作爲它所觸及的視圖(第二次)。


Touched beach = <BeachView: 0x1276a0> 
ran touchedBeach 
Touched beach = <Stone: 0x1480c0> 
ran touchedBeach 

所以請問,我一直在嘗試對此進行排序幾天。我該如何做到這一點,只有石頭敲響石頭纔會觸動石頭,而一個輕敲的沙灘只能叫到摸着沙灘?我哪裏錯了?

回答

2

在iPhone OS 3.0之前,UIScrollView的hitTest:withEvent:方法總是返回self,以便它直接接收UIEvent,只有當它確定它與滾動或縮放無關時,纔將其轉發到適當的子視圖。

我真的無法在iPhone OS 3.0,因爲它是在保密協議發表評論,但檢查你的「iPhone SDK發行說明的iPhone OS 3.0測試版5」 :)

如果你需要的目標前3.0,可以在BeachView中重寫hitTest:withEvent:並設置一個標誌來忽略下一個沙灘接觸,如果CGPoint實際上在石頭上。

但是您是否嘗試過將您的調用從覆蓋方法的末尾移至[超級碰觸*:withEvent:]?這可能會導致石頭水龍頭首先出現。

+0

我感動[超級]對這些方法的開始,它做了一個差異涉及到的錯誤。它仍然記錄了兩次敲擊,但至少現在它說1-startedBeach 2-startedStone 3-endedBeach 4-endedStone,所以有時間在那裏彈出一個標誌。 我只是環顧hitTest,但是當它開始談論CAlayers vs UIviews時,它看起來像是一本我只是沒有準備好打開的書。我會再試一次。 謝謝Hatfinch, -k。 – 2009-05-18 15:23:13

3

確實,iPhone SDK 3.0及更高版本,不會通過觸摸-touchesBegan:和 - touchesEnded: ** UIScrollview **子類方法了。您可以使用不一樣的touchesShouldBegintouchesShouldCancelInContentView方法。

如果你真的想得到這個接觸,有一個黑客,允許這一點。

在你UIScrollView覆蓋的hitTest方法的子類是這樣的:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 

    UIView *result = nil; 
    for (UIView *child in self.subviews) 
    if ([child pointInside:point withEvent:event]) 
     if ((result = [child hitTest:point withEvent:event]) != nil) 
     break; 

    return result; 
} 

這將傳遞給你繼承這倒是,但是你無法取消潤色UIScrollView超類。

0

我有一個類似的問題與simpleView並且將其添加到scrollView,每當我摸了摸simpleView,該scrollView用來獲取觸摸和,而不是simple查看時,scrollView感動。爲避免這種情況,當用戶觸摸simpleView並禁用滾動功能時,我禁用了scrollView的緩存。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 

    UIView *result = [super hitTest:point withEvent:event] ; 
    if (result == simpleView) 
    { 
     scrollView.scrollEnabled = NO ; 
    } 
    else 
    { 
     scrollView.scrollEnabled = YES ; 
    } 

    return result ; 

}