2010-05-26 35 views
40

Tôi đang cố gắng để có được một UIGestureRecognizer làm việc với một UIWebview mà là một subview của một UIScrollView. Điều này nghe có vẻ kỳ lạ nhưng khi tôi có numberOfTouchesRequired đặt thành 2 bộ chọn, nhưng khi numberOfTouchesRequired được đặt thành một bộ chọn không kích hoạt.Trình UIGestureRecognizer có hoạt động trên UIWebView không?

Đây là mã của tôi:

UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(select1:)]; 
    tap1.numberOfTouchesRequired = 2; 
    tap1.numberOfTapsRequired = 1; 
    tap1.delegate = self; 
    [self.ans1WebView addGestureRecognizer:tap1]; 
    [tap1 release]; 

- (void) select1:(UILongPressGestureRecognizer *)sender { 
    //Do Stuff 
} 

Tôi đã xác nhận điều này bằng cách sử dụng các mẫu Apple cho UIGestureRecognizer và chèn một webview trong nib của họ. Mã chạm của họ hoạt động ở mọi nơi nhưng bên trong khu vực của chế độ xem web.

Trả lời

66

Từ những gì tôi đã thấy, UIWebView không hoạt động tốt với người khác. Đối với công cụ nhận dạng cử chỉ, bạn có thể thử trả lại CÓ từ:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer; 

Tôi phải tương thích ngược với 3.0 vì vậy tôi đã thực hiện tất cả xử lý cử chỉ bằng Javascript bên trong UIWebView. Không phải là một giải pháp tốt, nhưng nó làm việc cho nhu cầu của tôi. Tôi đã có thể chụp một báo dài trên một phần tử, cũng như chạm, vuốt, chụm và xoay. Tất nhiên, tôi chỉ sử dụng nội dung địa phương.

Edit:

Bạn có thể tìm trong PhoneGap cho một ví dụ về việc gửi tin nhắn đến các đại biểu của UIWebView. Tóm lại, bạn sử dụng document.location = "myscheme:mycommand?myarguments" sau đó phân tích ra các lệnh và đối số từ callback delegate này:

-(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType { 
    if ([[[inRequest URL] absoluteString] hasPrefix:@"myscheme:"]) { 
    //.. parse arguments 
    return NO; 
    } 
} 

Bạn có thể thấy trong các mã PhoneGap rằng họ thiết lập một hàng đợi và hẹn giờ để gửi tin nhắn. Tùy thuộc vào cách sử dụng của bạn, bạn có thể cần phải làm điều tương tự. Có những câu hỏi khác về SO về chủ đề này.

Đây là tài liệu Event Handling. Trong trường hợp của tôi, tôi thêm thính giả sự kiện để document từ <body onload="myloader();">

function myloader() { 
    document.addEventListener('touchcancel' , touch_cancel , false); 
    document.addEventListener('touchstart' , touch_start , false); 
    document.addEventListener('touchmove' , touch_move , false); 
    document.addEventListener('touchend' , touch_end , false); 
}; 

Việc xử lý sự kiện thực tế phụ thuộc rất nhiều vào nhu cầu của bạn. Mỗi trình xử lý sự kiện sẽ nhận được một TouchEvent với thuộc tính chạm, trong đó mỗi mục là Touch. Bạn có thể ghi lại thời gian bắt đầu và vị trí trong trình xử lý cảm ứng của bạn. Nếu chạm di chuyển đến xa hoặc sai số lượng thời gian vượt qua nó không phải là một liên lạc dài.

WebKit có thể cố gắng xử lý một lần chạm dài để bắt đầu lựa chọn và sao chép. Trong trình xử lý sự kiện của bạn, bạn có thể sử dụng event.preventDefault(); để dừng hành vi mặc định. Tôi cũng tìm thấy thuộc tính css -webkit-user-select:none tiện dụng cho một số thứ.

var touch = {}; 
function touch_start(event /*TouchEvent*/ { 
    event.preventDefault(); 
    touch = {}; 
    touch.startX = event.touches.item(0).pageX; 
    touch.startY = event.touches.item(0).pageY; 
    touch.startT = (new Date()).getTime(); 
} 

Đây chỉ là dự án thứ hai tôi đã sử dụng javascript với. Bạn có thể tìm thấy các ví dụ tốt hơn ở nơi khác.

Như bạn có thể thấy đây không phải là câu trả lời nhanh cho vấn đề của bạn. Tôi khá hài lòng với kết quả tôi nhận được. Html tôi đã làm việc với không có yếu tố tương tác ngoài một hoặc hai liên kết.

+3

Cảm ơn, tôi không biết gì về Javascript; bạn sẽ được như vậy loại để chỉ cho tôi đi đúng hướng trên làm thế nào để phát hiện một vòi nước trong một UIWebView thông qua Javascript và gọi một Objective-C phương pháp? Tôi sẽ không nhớ tương thích với 3.0 cho mục tiêu không phải iPad. Đối với bất kỳ người nào khác chỉ quan tâm đến 3,2+, tôi đã khắc phục sự cố của mình bằng cách chỉ cần tạo chế độ xem trong suốt ngay trên đầu UIWebView và phát hiện các thao tác nhấn trong đó. – rscott

+0

Cảm ơn bạn đã làm việc – user578386

+0

Cảm ơn bạn, nó hoạt động tốt –

1

Bạn cũng có thể tìm thấy câu trả lời của mình here hữu ích. Đó là một ví dụ làm việc về xử lý cử chỉ chụm trong javascript của UIWebView.

(Bạn có thể liên lạc sự kiện này với Mục tiêu-C nếu bạn muốn. Xem my answer here.)

44

UIWebView có chế độ xem riêng tư, cũng có các trình nhận dạng cử chỉ được đính kèm. Do đó, các quy tắc ưu tiên giữ cho bất kỳ trình nhận dạng cử chỉ nào được thêm vào UIWebView hoạt động bình thường.

Một tùy chọn là triển khai giao thức UIGestureRecognizerDelegate và triển khai phương thức gestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer. Trả lại CÓ từ phương pháp này cho các cử chỉ nhấn khác. Bằng cách này, bạn sẽ nhận được trình xử lý nhấn được gọi và chế độ xem web sẽ vẫn được gọi.

Xem this on the Apple dev forums.

+1

Xem câu trả lời thứ hai được đề cập để biết thông tin bổ sung: http://stackoverflow.com/questions/2627934/simultaneous-gesture-recognizers-in-iphone-sdk – ChrisP

+0

Tôi ước Tôi có thể upvote điều này nhiều hơn một lần. –

+0

Điều này cực kỳ hữu ích, cảm ơn bạn! –

4

Tôi gặp sự cố tương tự. Giải pháp này làm việc cho tôi:

1) Hãy chắc chắn để thêm giao thức để giao diện của bạn: UIGestureRecognizerDelegate ví dụ:

@interface ViewController : UIViewController <SlideViewProtocol, UIGestureRecognizerDelegate> 

2) Thêm dòng mã này

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { 
return YES 
} 

3) Cài đặt cử chỉ

UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(nextSlide)]; 
swipeGesture.numberOfTouchesRequired = 1; 
swipeGesture.direction = (UISwipeGestureRecognizerDirectionLeft); 
swipeGesture.cancelsTouchesInView = YES; [swipeGesture setDelegate:self]; 
[self.view addGestureRecognizer:swipeGesture]; 
+1

câu trả lời này phải được chỉnh sửa để trả về mã đúng trong bướC# 2 (tức là API yêu cầu trả lại BOOL). –

+0

Đây là giải pháp đơn giản nhất được trình bày và làm việc cho tôi, với hai điều kiện tiên quyết. Bạn cần trả lại CÓ. Và bạn phải đặt swipeGesture.delegate = self; – JScarry

+0

Tôi đã chỉnh sửa bài đăng để phản ánh các đề xuất. – chrisallick

2

Một cách khác là đặt UIButton trong suốt lên trên UIWebView và xử lý các thao tác nhấn từ nút này. Trong một số trường hợp, nó có thể là một giải pháp tốt.

UIWebView webView = [UIWebView new]; 
//... 

UIButton *transparentButton = [UIButton buttonWithType:UIButtonTypeCustom]; 
[transparentButton addTarget:self action:@selector(buttonTapped) forControlEvents:(UIControlEventTouchUpInside)]; 
transparentButton.frame = webView.frame; 
transparentButton.layer.backgroundColor = [[UIColor clearColor] CGColor]; 
[self.view transparentButton]; 
+0

Hahah, đây chắc chắn là giải pháp tốt nhất :) +1 cho việc hack. – chrisallick

+3

Tôi sử dụng phương pháp này nếu tôi không cần cuộn UIWebView. Nhưng nếu bạn cần cuộn, nó không hoạt động vì UIButton bẫy tất cả các đầu vào của người dùng. – JScarry

13

Đây là giải pháp phần nào hack-ish, nhưng nó hoạt động. UIWebView có rất nhiều trình nhận dạng cử chỉ bên trong mà bạn thường không thể truy cập mà không sử dụng API riêng tư. Tuy nhiên, bạn nhận được tất cả miễn phí, khi bạn triển khai gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:. Tại thời điểm đó, bạn có thể yêu cầu tất cả các UITapGestureRecognizers nội bộ chỉ kích hoạt khi UITapGestureRecognizer của riêng bạn không thành công. Bạn chỉ làm điều đó một lần và sau đó loại bỏ các đại biểu từ nhận dạng cử chỉ của riêng bạn. Kết quả là bạn vẫn có thể xoay và cuộn webView của mình, nhưng nó sẽ không nhận được bất kỳ cử chỉ chạm (đơn lẻ) nào nữa.

- (void)viewDidLoad 
{  
    [super viewDidLoad]; 

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]; 

    // view is your UIViewController's view that contains your UIWebView as a subview 
    [self.view addGestureRecognizer:tap]; 

    tap.delegate = self; 
} 

- (void)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer 
{ 
    NSLog(@"tap!"); 

    // this is called after gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: so we can safely remove the delegate here 
    if (gestureRecognizer.delegate) { 
     NSLog(@"Removing delegate..."); 
     gestureRecognizer.delegate = nil; 
    } 
} 

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 
{ 
    if ([otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) { 
     [otherGestureRecognizer requireGestureRecognizerToFail:gestureRecognizer]; 

     NSLog(@"added failure requirement to: %@", otherGestureRecognizer); 
    } 

    return YES; 
} 

Tận hưởng!

3
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer { 
    return YES; 
} 
Các vấn đề liên quan