2009-05-18 34 views
7

Xin vui lòng ai đó có thể giúp sắp xếp một câu trả lời? Tôi đã đăng vấn đề này trên các diễn đàn khác nhau và không nhận được câu trả lời, trong khi nhiều tìm kiếm cho các câu trả lời khác đã bật lên StackOverflow, vì vậy tôi hy vọng đây là nơi.Chạm vào UIScrollView và chạm vào màn hình phụ

Tôi đã có một BeachView.h (lớp con của UIScrollView, ảnh của một bãi biển đầy cát) được bao phủ bởi một số ngẫu nhiên Stone.h (lớp con của UIImageView, một PNG ngẫu nhiên của một hòn đá, userInteractionEnabled = YES để chấp nhận chạm).

Nếu người dùng chạm và di chuyển trên bãi biển, nó sẽ cuộn. Nếu người dùng nhấn vào một hòn đá, nó sẽ gọi phương thức "touchedStone". Nếu người dùng nhấn vào bãi biển nơi không có đá, nó sẽ gọi phương thức "touchedBeach".

Bây giờ, tôi nhận ra điều này nghe có vẻ đơn giản. Mọi người và mọi thứ đều nói với tôi rằng nếu có điều gì đó trên một UIScrollView chấp nhận các liên lạc mà nó phải vượt qua sự kiểm soát đối với nó. Vì vậy, khi tôi chạm và kéo, nó sẽ cuộn; nhưng nếu tôi gõ, và nó trên một hòn đá, nó nên bỏ qua vòi nước bãi biển và chấp nhận vòi đá, có?

Tuy nhiên, có vẻ như cả hai chế độ xem đều chấp nhận nhấn và gọi cả chạm vàoStone AND touchedBeach. Hơn nữa, các vòi bãi biển xảy ra đầu tiên, vì vậy tôi thậm chí không thể đặt trong một "nếu touchStone sau đó không chạy chạmBeach" loại cờ.

Dưới đây là một số mã. On 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]; 
} 

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

Sau một vòi nước đá, NSLog của tôi trông như thế này:


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

Vì vậy, nó thực sự chạy cả hai. Những gì thậm chí còn xa lạ là nếu tôi lấy touchesBegan và touchesEnded ra khỏi Stone.m nhưng để lại userInteractionEnabled = YES, beachView đăng ký cả hai chạm chính nó, nhưng trả về Stone như xem nó chạm (lần thứ hai).


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

Vì vậy, tôi đã cố gắng sắp xếp điều này trong nhiều ngày. Làm thế nào để làm cho nó như vậy một cuộc gọi đá khai thác chỉ touchStone và một bãi biển khai thác các cuộc gọi chỉ xúc độngBeach? Tôi làm sai ở đâu?

Trả lời

2

Trước iPhone OS 3.0, phương thức hitTest của UIScrollView: phương thức withEvent: luôn trả về tự để nó nhận trực tiếp UIEvent, chỉ chuyển tiếp tới subview thích hợp nếu và khi nó xác định nó không liên quan đến cuộn hoặc phóng to.

Tôi thực sự không thể nhận xét về iPhone OS 3.0 vì nó là theo NDA, nhưng kiểm tra của bạn "iPhone SDK Ghi chú phát hành cho hệ điều hành iPhone 3.0 beta 5" :)

Nếu bạn cần phải nhắm mục tiêu trước 3.0, bạn có thể ghi đè hitTest: withEvent: trong BeachView và thiết lập một lá cờ để bỏ qua các liên lạc bãi biển tiếp theo nếu CGPoint thực sự là một hòn đá.

Nhưng bạn đã thử chỉ đơn giản là chuyển các cuộc gọi của mình sang [super touches *: withEvent:] từ cuối các phương thức ghi đè của bạn đến đầu? Điều này có thể khiến cho việc chạm đá xảy ra trước.

+0

tôi chuyển [siêu] để bắt đầu các phương pháp và nó làm cho một sự khác biệt. Nó vẫn đăng ký hai vòi nhưng ít nhất bây giờ nó nói 1-startedBeach 2-startedStone 3-endedBeach 4-endedStone, do đó, có thời gian để bật một lá cờ trong đó. Tôi chỉ đang nhìn xung quanh tại hitTest nhưng khi nó bắt đầu nói về CAlayers vs UIviews nó có vẻ giống như một cuốn sách tôi đã không hoàn toàn sẵn sàng để mở. Tôi sẽ cung cấp cho nó một shot. Cảm ơn Hatfinch, -k. –

3

Đúng, iPhone SDK 3.0 trở lên, không chuyển các chạm đến -touchesBegan: và - touchesEnded: ** UIScrollview ** các phương thức lớp con nữa.Bạn có thể sử dụng các phương thức touchesShouldBegintouchesShouldCancelInContentView không giống nhau.

Nếu bạn thực sự muốn nhận được chạm này, hãy có một hack cho phép điều này.

Trong lớp con lại UIScrollView override phương pháp hitTest như thế này:

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

này sẽ vượt qua để bạn phân lớp này chạm, tuy nhiên bạn không thể hủy chạm đến UIScrollView siêu lớp.

0

Tôi đã có một vấn đề tương tự với một simpleView và nó được thêm vào một scrollView, và bất cứ khi nào tôi chạm vào simpleView, các scrollView sử dụng để có được các liên lạc và thay vì simpleView, các scrollView di chuyển. Để tránh điều này, tôi đã vô hiệu hóa srcolling của scrollView khi người dùng chạm vào simpleView và nếu không cuộn sẽ được bật.

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

} 
Các vấn đề liên quan