2010-05-26 58 views
40

我正在嘗試使用UIScrollView的子視圖UIWebview來獲取UIGestureRecognizer。這聽起來很奇怪,但是當我將numberOfTouchesRequired設置爲2時,選擇器會觸發,但當numberOfTouchesRequired設置爲1時,選擇器不會觸發。UIGestureRecognizer是否在UIWebView上工作?

這裏是我的代碼:

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 
} 

我已經證實了這一點通過使用UIGestureRecognizer蘋果樣品和插入他們的筆尖網頁視圖。他們的tap代碼無處不在,但在webview的區域內。

回答

66

從我所看到的情況來看,UIWebView並不能很好地與其他人玩。對於手勢識別器,你可以嘗試從返回YES:

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

我不得不向後兼容3.0,所以我結束了做所有的動作與UIWebView的Javascript中處理。這不是一個好的解決方案,但它可以滿足我的需求。我能夠捕捉元素上的長按,以及輕拍,輕掃,捏和旋轉。當然,我只使用本地內容。

編輯:

你可以看看在PhoneGap發送消息到一個UIWebView的委託的一個例子。簡而言之,您使用document.location = "myscheme:mycommand?myarguments"然後從該委託回調解析出命令和參數:

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

您可以在他們成立了一個隊列和定時器發送消息的PhoneGap的代碼中看到。根據您的使用情況,您可能需要做同樣的事情。關於這個話題還有其他的問題。

這裏是Event Handling文檔。在我來說,我添加的事件監聽器document<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); 
}; 

實際的事件處理在很大程度上取決於你的需求。每個事件處理程序將收到一個TouchEvent與觸摸屬性,其中每個項目是Touch。你可以在你的touchstart處理程序中記錄開始時間和位置。如果觸摸移動得太遠或錯過了一段時間,則觸摸不夠長。

WebKit可能會嘗試處理長按以開始選擇和複製。在您的事件處理程序中,您可以使用event.preventDefault();來停止默認行爲。我還發現一些東西方便的cs屬性-webkit-user-select:none

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

這只是我用過的第二個javascript項目。你可以在別處找到更好的例子。

正如你所看到的,這不是你的問題的快速答案。我對我得到的結果很滿意。我正在使用的html沒有超過一個或兩個鏈接的交互式元素。

+3

謝謝,我對Javascript一無所知;你會如此友善,指出我在正確的方向如何檢測通過Javascript的UIWebView的龍頭,並調用Objective-C方法?我不介意與非iPad定位的3.0兼容。 對於任何其他只關心3.2+的人,我通過在UIWebView頂部創建一個透明視圖並檢測其中的水龍頭來解決我的問題。 – rscott 2010-05-26 03:24:35

+0

感謝DAT工作 – user578386 2013-08-24 09:02:08

+0

謝謝你,它工作得很好 – 2017-01-23 01:09:37

1

您可能還會發現我的答案here有幫助。這是一個在UIWebView的javascript中處理捏手勢的工作示例。

(如果需要,您可以將事件傳回給Objective-C,請參閱my answer here。)

44

UIWebView具有自己的私人視圖,該視圖還附帶了手勢識別器。因此,優先規則會使添加到UIWebView的任何手勢識別器無法正常工作。

一種選擇是實現UIGestureRecognizerDelegate協議並實現方法gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer。對於其他輕擊手勢,從此方法返回YES。這樣你就可以調用你的tap處理程序,並且web view仍然會被調用。

請參閱this on the Apple dev forums

+1

見的補充信息問題的第2個答案: http://stackoverflow.com/questions/2627934/simultaneous-gesture-recognizers-in-iphone-sdk – ChrisP 2011-04-11 21:35:45

+0

祝我可以不止一次地對此讚賞。 – 2012-06-06 03:58:51

+0

這非常有幫助,謝謝! – 2017-01-22 03:10:12

4

我遇到了同樣的問題。該解決方案爲我工作:

1)確保將協議添加到您的接口:UIGestureRecognizerDelegate例如:

@interface ViewController : UIViewController <SlideViewProtocol, UIGestureRecognizerDelegate> 

2)添加這行代碼

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

3)設置手勢

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

應該編輯此答案以在步驟#2中返回正確的代碼(即該API需要返回BOOL)。 – 2013-11-16 11:12:28

+0

這是最簡單的解決方案,適用於我,有兩個注意事項。你需要返回YES。你必須設置swipeGesture.delegate = self; – JScarry 2014-02-20 20:21:19

+0

我編輯了帖子以反映這些建議。 – chrisallick 2014-06-16 18:30:08

2

另一種方法是在UIWebView頂部放置一個透明的UIButton並處理水龍頭從這個按鈕。在某些情況下,這可能是一個好的解決方案。

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

哈哈,這絕對是最好的解決方案:)爲黑客+1。 – chrisallick 2013-12-12 00:09:29

+3

如果我不需要滾動UIWebView,則使用此方法。但是如果你需要滾動,它不起作用,因爲UIButton會陷入所有的用戶輸入。 – JScarry 2014-02-20 19:41:59

13

這是一個有點黑客解決方案,但它的工作原理。 UIWebView具有許多內部手勢識別器,如果不使用私有API,您通常無法訪問它們。但是,當你實施gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:時,你可以免費得到它們。此時,您可以告訴所有內部UITapGestureRecognizer僅在您自己的UITapGestureRecognizer失敗時觸發。你只做一次,然後從你自己的手勢識別器中刪除委託。結果是,您仍然可以平移和滾動webView,但不會再收到任何(單一)輕擊手勢。

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

Enjoy!

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