2010-10-22 33 views
5

Tôi có phân cấp chế độ xem có chứa các chế độ xem nhỏ hơn trên chế độ xem cuộn. Mỗi chế độ xem có thể có các bản xem trước trong đó, chẳng hạn như các nút, v.v.hitTest trả về sai UIView

Vì một số lý do, các nút trên chế độ xem không được nhấp; khám phá thêm điều này cho thấy trong khi chế độ xem cuộn sẽ nhận được sự kiện touchBegan, thì nút đó không. Gọi thông báo hitTest: event: thông báo cho biết nút không được trả lại, mặc dù nó nằm trong giới hạn.

Tôi đã bao gồm đầu ra nhật ký mô tả vị trí của cảm ứng trên chế độ xem cuộn, mục được trả về từ hitTest, vị trí của cảm ứng nếu tôi gọi locationInView: sử dụng mục được mong đợi và thứ bậc của mục được mong đợi (với khung được in). Từ đầu ra này, tôi có thể suy ra rằng nút nên đã được gọi là ...

Bất cứ ai có thể giải thích điều này? Tui bỏ lỡ điều gì vậy?

touched ({451, 309}) on <VCViewContainersView: 0x4b31ee0; frame = (0 0; 748 1024); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x4b32130>> (location in expected item: {17, 7.5}) 
expected touched item is: 
view: <UIButtonLabel: 0x482b920; frame = (32 5; 36 19); text = 'Click'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x4831370>>, layer transform: [1, 0, 0, 1, 0, 0] 
view: <UIRoundedRectButton: 0x482c100; frame = (50 50; 100 30); opaque = NO; layer = <CALayer: 0x482c450>>, layer transform: [1, 0, 0, 1, 0, 0] 
    view: <UIImageView: 0x480f290; frame = (0 0; 320 255); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x480e840>>, layer transform: [1, 0, 0, 1, 0, 0] 
    view: <VCViewContainer: 0x4b333c0; frame = (352 246.5; 320 471.75); layer = <CALayer: 0x4b33d50>>, layer transform: [1, 0, 0, 1, 0, 0] 
    view: <UIScrollView: 0x4b32600; frame = (0 0; 1024 748); clipsToBounds = YES; autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x4b32780>>, layer transform: [1, 0, 0, 1, 0, 0] 
    view: <VCViewsContainerView: 0x4b31ee0; frame = (0 0; 748 1024); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x4b32130>>, layer transform: [0, 1, -1, 0, 0, 0] 
     view: <UIWindow: 0x4b1d590; frame = (0 0; 768 1024); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x4b1d6d0>>, layer transform: [1, 0, 0, 1, 0, 0] 

Cập nhật: Khác hơn UIWindowVCViewsContainerView, tất cả các quan điểm được tạo ra theo chương trình sử dụng initWithFrame: hoặc trong trường hợp của các nút, buttonWithType:. VCViewContainer được khởi tạo bằng cách sử dụng CGRectZero và khi UIImageView được tạo, khung của nó được đặt thành kích thước của hình ảnh + không gian bổ sung cho các nhãn ở dưới cùng của nó.

Cập nhật 2: Khi gọi [self.layer hitTest: vị trí] với cùng một vị trí, tôi nhận được lớp đúng xem ! Những gì đang xảy ra ở đây...?

+0

UIRoundedRectButton * là * nút. – kennytm

+0

Chúng ta cần phải xem cách bạn tạo hệ thống cấp bậc của bạn xem ... InterfaceBuilder, mã, vv ... – jv42

+0

@KennyTM: Nếu nó không được rõ ràng, nó nói "chạm (vị trí) trên (mục thực sự đụng đến)". Lưu ý rằng mục được chạm là VCViewContainerView và _not_ UIRoundedRectButton. –

Trả lời

0

Nếu tôi hiểu khung nhìn chính xác thì nút của bạn là chế độ xem phụ của một số UIImageView - nó có userInteractionEnabled thuộc tính được đặt thành NO (theo mặc định) - vì vậy chế độ xem hình ảnh và tất cả các bản phụ sẽ không nhận được bất kỳ sự kiện chạm nào.

Thiết sở hữu userInteractionEnabled xem hình ảnh để YES phải giải quyết vấn đề

+0

Chỉ trong trường hợp tôi đã thử điều đó - nhưng tiếc là không phải như vậy. Tôi không nghĩ những gì bạn nói là đúng; Các tài liệu xác định rằng việc tìm kiếm một trình xử lý sự kiện là từ trên xuống dưới, do đó nút phải được kiểm tra trước. Và trong mọi trường hợp, hitTest: không bị ảnh hưởng bởi tương tác của người dùng .. –

5

hitTest: withEvent: bắt đầu từ cửa sổ. Mỗi chế độ xem sẽ kiểm tra các bản xem trước của nó trước khi tự kiểm tra và cứ như vậy, đệ quy. Tuy nhiên, nếu userInteractionEnabled của chế độ xem là NO, nó trả về nil từ hitTest: withEvent :, mà không kiểm tra các bản xem trước của nó. Một cái nhìn như vậy chắc chắn là đã được thử nghiệm, nhưng nó ngay lập tức trả lời rằng không phải nó cũng không phải bất kỳ phần phụ nào của nó đều là lượt truy cập.

Bạn UIScrollView đã đặt userInteractinonEnabled thành NO. Vì vậy, khi VCViewContainersView kiểm tra subview của nó UIScrollView, và UIScrollView trả về nil vì userInteractionEnabled của nó là NO, VCViewContainersView sử dụng pointInside: withEvent: trên chính nó, thấy rằng touch nằm bên trong chính nó, và trả về chính nó như là view hit (và tìm kiếm kết thúc). Điều này giải thích kết quả bạn đang nhận được.

Lý do điều này không xảy ra khi bạn thực hiện kiểm tra bằng cách xếp lớp là không thể chạm vào và không biết gì về quy tắc chạm, vì vậy, họ bỏ qua userInteractionEnabled, đây là tính năng chế độ xem chứ không phải một tính năng lớp. Kiểm tra hit lớp là loại kludge, chỉ dành cho khi một khung nhìn chứa toàn bộ hệ thống phân cấp lớp (không có phân cấp khung nhìn) và bạn muốn mô phỏng rằng một lớp cụ thể có thể chạm được.Các tài liệu làm cho bạn biết rằng logic là khác nhau cho hitTest của một lớp: hơn là cho một cái nhìn hitTest: withEvent :, dù họ thất bại trong việc giải thích chính xác như thế nào. Tôi không biết tại sao bạn đã đặt chế độ xem cuộn của mình thành không thể chạm được, nhưng nếu điều đó quan trọng đối với bạn, bạn có thể ghi đè hitTest: withEvent: trong lớp con UIScrollView để nó kiểm tra các bản xem phụ nhưng trả về nil nếu tất cả đều trở về không.

+0

+1 cảm ơn lời giải thích rằng 'hitTest: withEvent:' trả về 'nil' khi' userInteractionEnabled' là 'NO' –

+2

@AlexanderFarber -kiểm tra phân phối cảm ứng và thử nghiệm hit, xem tại đây: http://www.apeth.com/iOSBook/ch18.html#_hit_testing – matt

+0

Cảm ơn bạn Matt, tôi đã đọc cuốn sách của bạn tại Safari - nó rất hữu ích. Bạn có bất kỳ lời khuyên nào cho vấn đề hiện tại của tôi (bounty 500) tại http://stackoverflow.com/questions/22582649/dragging-views-on-a-scroll-view-touchesbegan-is-received-but-no- touchesended-o? Tôi không thể tìm ra đúng 'hitTest: withEvent: 'ở đó. –

1

Bạn có thể muốn thử subclassing UIScrollView của bạn để nhận chạm trên các đối tượng bên trong nó.

Theo mặc định chạm của bạn sẽ được nhận bởi UIScrollView của bạn, vì vậy nếu bạn muốn nhận chạm trên các đối tượng bên trong của nó, bạn cần phải thiết lập khả năng một cách rõ ràng.

Dưới đây là một lớp con làm việc để làm việc đó. Nhờ cộng đồng SO vì điều này, bởi vì tôi tin rằng ban đầu tôi đã tìm thấy một cái gì đó như thế này ở đây, chỉ cần không thể đào bài gốc ngay bây giờ.

Đây là .h:

#import <Foundation/Foundation.h> 
#import <UIKit/UIKit.h> 

@interface TouchScroller : UIScrollView 
{ 
} 

@end 

Và .m:

#import "TouchScroller.h" 


@implementation TouchScroller 

- (id)initWithFrame:(CGRect)frame 
{ 
return [super initWithFrame:frame]; 
} 

- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event 
{ 
// If not dragging, send event to next responder 
if (!self.dragging) 
    [self.nextResponder touchesEnded: touches withEvent:event]; 
else 
    [super touchesEnded: touches withEvent: event]; 
} 

@end 

Điều đó sẽ làm điều đó.

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