Wyłączanie wyboru użytkownika w UIWebView

121

Mam aplikację, w której ładuję zawartość do pliku UIWebViewi przedstawiam to. Nie mogę całkowicie wyłączyć interakcji użytkownika, ponieważ chcę, aby użytkownik mógł klikać linki. Muszę tylko wyłączyć wybór użytkownika. Znalazłem gdzieś w Internetach, z których możesz skorzystać:

document.body.style.webkitUserSelect='none';

Próbowałem wstawić to jako

[self.contentView stringByEvaluatingJavaScriptFromString:@"document.body.style.webkitUserSelect='none';"]; 

w webViewDidFinishLoad:

Jednak to nie działa. Nadal mogę zaznaczać i kopiować tekst w WebView.

Jakieś pomysły, co może się nie udać?

Aktualizacja: wydaje się, że dzieje się tak dopiero od iOS 4.3

Engin Kurutepe
źródło

Odpowiedzi:

280

Oto kilka sposobów wyłączenia zaznaczenia:

Dodaj następujące elementy do swoich mobilnych dokumentów internetowych

<style type="text/css">
* {
    -webkit-touch-callout: none;
    -webkit-user-select: none; /* Disable selection/copy in UIWebView */
}
</style>

Programowo załaduj następujący kod JavaScript:

NSString * jsCallBack = @"window.getSelection().removeAllRanges();";    
[webView stringByEvaluatingJavaScriptFromString:jsCallBack];

Wyłącz menu użytkownika Kopiuj / Wklej:

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender 
{    
    if (action == @selector(copy:) ||
        action == @selector(paste:)||
        action == @selector(cut:)) 
    {
        return _copyCutAndPasteEnabled;
    }
    return [super canPerformAction:action withSender:sender];
}
WrightsCS
źródło
1
Rozszerz UIWebViewza pomocą kategorii.
Deepak Danduprolu
4
Engin, pierwszy działa w Mobile Safari, iOS 4.3.1. Ale WrightCS zapomniał dodać selektora. Aby zastosować go do wszystkich elementów, użyj gwiazdki, na przykład: * {/ * css tutaj * /}
fisherwebdev
1
Dodanie stylu działało doskonale przy usuwaniu menu, które pojawiło się podczas wyszukiwania linku w mojej aplikacji PhoneGap.
przestrzenne
7
canPerformActionnie wyłącza menu Wytnij, Kopiuj, Wklej. I wybierz menu Wybierz wszystko. Jak to naprawić? -webkit-touch-callouti removeAllRangesprzerwij wprowadzanie danych przez użytkownika. Nie można użyć wszystkich podanych metod :(
Dmitry,
4
Problem z umieszczeniem tych stylów bez wyboru w *zakresie globalnym polega na tym, że zatrzymuje wprowadzanie danych przez użytkownika w formularzach internetowych. Okazało się, że uzyskałem lepsze wyniki, umieszczając bodyzamiast tego tag.
David Douglas
104

Mogę potwierdzić, że poniższy kod działa w iOS 5.0 - 8.0.

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    // Disable user selection
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
    // Disable callout
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];
}

Działa również na iOS 9 i nowszych. Oto szybki kod:

func webViewDidFinishLoad(webView: UIWebView) {
    // Disable user selection
    webView.stringByEvaluatingJavaScriptFromString("document.documentElement.style.webkitUserSelect='none'")!
    // Disable callout
    webView.stringByEvaluatingJavaScriptFromString("document.documentElement.style.webkitTouchCallout='none'")!
}
TPoschel
źródło
2
Potwierdzone na iOS 7! Uwaga: możliwe jest zgrupowanie dwóch wywołań w jedno poprzez połączenie dwóch ciągów.
Bigood
W iOS 9.x pusty komunikat pojawia się u góry ekranu po długim naciśnięciu, nawet jeśli używasz powyżej.
DwarDoh
jak mogę użyć powyższego kodu… Po prostu znam JS; nie mam pojęcia, jak mogę edytować kod celu C lub zmienić wtyczkę phonegap ... jeśli ktoś może pomóc
Lakshay
Pracuj z idealnym facetem na iOS 9 i 10!
ΩlostA
25

Używam tej techniki w aplikacji internetowej na Androida / iPhone'a (w pakiecie z Trigger.IO) i stwierdziłem, że będzie działać tylko ze składnią łańcuchową dla pseudoklasy: not (),:

*:not(input):not(textarea) {
-webkit-user-select: none; /* disable selection/Copy of UIWebView */
    -webkit-touch-callout: none; /* disable the IOS popup when long-press on a link */

}
Johno Scott
źródło
Używam jQuery Mobile i Phonegap Build i to zadziałało. Najpierw spróbowałem, *:not(input,textarea) {-webkit-touch-callout: none; -webkit-user-select: none;}ale to nie pomogło. Dzięki!
Mark Rummel,
18

Podoba mi się rozwiązanie WrightsCS, ale użyję go, aby użytkownicy mogli nadal używać kopiowania, wklejania i wybierania działań na wejściach

<style type="text/css">
*:not(input,textarea) {
    -webkit-touch-callout: none;
    -webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
</style>
pablobart
źródło
2
Jeśli masz zamiar to zrobić, nie zapomnij o textarea!
Ryan
9

Nie jestem pewien, jak wygląda konfiguracja, ale dlaczego po prostu nie wyczyścisz pasteBoard, gdy wywoływana jest funkcja viewWillDisappear. Może coś takiego w twojej appDelegate.m:

[UIPasteboard generalPasteboard].string = nil;

Dzięki temu wszelkie dane, które użytkownik mógł skopiować, nie będą w stanie wkleić ich poza aplikacją.

Ponadto, jak powiedział Engin, można przesłonić metodę canPerformSelector w klasie kontrolera, która zawiera uiwebview.

Bittu
źródło
1
To jedno z najlepszych rozwiązań. Można to ustawić w - (void) applicationDidEnterBackground: (UIApplication *) obsłudze zdarzeń aplikacji. A to gwarantuje, że żadne dane nie będą wychodzić z aplikacji.
Krishnan
@Krishan, czy jesteś w 100% pewien, że zatrzyma również zrzuty ekranu?
Norman H
Podoba mi się to rozwiązanie, ale ponieważ pozostaje na stole montażowym, gdy aplikacja jest aktywna, inna (złośliwa) aplikacja działająca w tle wątku może uzyskać dostęp do ogólnego stołu montażowego, gdy ma w nim dane.
binary_falcon
czy nie spowoduje to również usunięcia danych nie z aplikacji? Być może uzyskaj dane, które pojawią się i ustaw je z powrotem na zniknięcie, działałoby lepiej
Hamzah Malik
7

Odpowiedź TPoschela jest poprawna, ale w moim przypadku kolejność była ważna.

// this works - locks selection and callout
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];
}

// this doesn't work - locks only callout
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
}
pawelini1
źródło
7

Mogę potwierdzić, że to na pewno zadziała.

<style type="text/css">
  *:not(input):not(textarea) {
   -webkit-user-select: none; /* disable selection/Copy of UIWebView */
   -webkit-touch-callout: none; /* disable the IOS popup when long-press on a link */
   }       
</style>

Jeśli chcesz wyłączyć tylko znacznik przycisku kotwicy, użyj tego.

    a {-webkit-user-select: none; /* disable selection/Copy of UIWebView */
   -webkit-touch-callout: none; /* disable the IOS popup when long-press on a link */
     }
Narsingh Tomar
źródło
5

Efekt wspaniałej pracy przez tydzień! Wszystkie inne odpowiedzi są niepoprawne, jeśli chcesz zapisać zdarzenia myszy i dane wejściowe użytkownika na wielu stronach.

1) Metoda Swizzle (według biblioteki rentzsch / jrswizzle ):

[NSClassFromString(@"UIWebDocumentView") jr_swizzleMethod:@selector(canPerformAction:withSender:) withMethod:@selector(myCanPerformAction:withSender:) error:nil];

NSObject + myCanPerformAction.h:

@interface NSObject (myCanPerformAction)

- (BOOL)myCanPerformAction:(SEL)action withSender:(id)sender;

@end

NSObject + myCanPerformAction.m:

#import "NSObject+myCanPerformAction.h"

@implementation NSObject (myCanPerformAction)

- (BOOL)myCanPerformAction:(SEL)action withSender:(id)sender {
    if (action == @selector(copy:)) {
        return [self myCanPerformAction:action withSender:sender];
    }
    if (action == @selector(paste:)) {
        return [self myCanPerformAction:action withSender:sender];
    }
    return NO;
}

@end

2) Umieść UIWebView na UIView i dodaj kod:

    UITapGestureRecognizer* singleTap = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)] autorelease];
    singleTap.numberOfTapsRequired = 2;
    singleTap.numberOfTouchesRequired = 1;
    singleTap.delegate = self;
    [self.view addGestureRecognizer:singleTap];

I ten:

- (void)handleSingleTap:(UIGestureRecognizer*)gestureRecognizer {
    return;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    if ([otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
        UITapGestureRecognizer *gesture = (UITapGestureRecognizer *)otherGestureRecognizer;
        if (gesture.numberOfTapsRequired == 2) {
            [otherGestureRecognizer.view removeGestureRecognizer:otherGestureRecognizer];
        }
    }
    return YES;
}
Dmitry
źródło
2
Pewne wyjaśnienie tego, co to ma zrobić, byłoby miłe. W szczególności jestem zdezorientowany, dlaczego twój gest nazywa się jednym dotknięciem, ale wymaga dwóch dotknięć.
arlomedia
5
    let longPress:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: nil, action: nil)
    longPress.minimumPressDuration = 0.2
    webView.addGestureRecognizer(longPress)

Po prostu dodaj ten kod do swojej viewDidLoad (). Użytkownik może kliknąć link, ale nie może skopiować treści.

Samrat Pramanik
źródło
4

Pierwsze podane rozwiązanie działało idealnie dla mnie ... dopóki nie załadowałem pliku .pdf do mojego UIWebView.

Ładowanie pliku .doc działało idealnie, ale ładowanie pliku .pdf spowodowało, że następująca linia kodu nie miała już pożądanego efektu, a menu kopiowania / definiowania pojawiło się ponownie po długim dotknięciu przez użytkownika.

    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];

Po kolejnym wyrywaniu włosów znalazłem tutaj odpowiedź Johnny'ego Rockexa i zadziałała jak mistrz. UIWebView bez kopiowania / wklejania podczas wyświetlania plików PDF

Wielkie dzięki za to łatwe do wdrożenia, genialne rozwiązanie !!

Skuter
źródło
2

Dla mnie, mam przeznaczone do pobierania obrazów NSDataz UIWebViewprzezLongPressGesture .

Ale Lupa i Kopiuj / Wklej / Wytnij zawsze pojawiają się przed wykonaniem mojej funkcji.

I znalazłem to: wprowadź opis obrazu tutaj

Oznacza to, że Lupa i Kopiuj / Wklej / Wytnij potrzebują 0,5 s do wykonania, więc jeśli twoja funkcja może być wykonana w 0,49 s, GOTOWE!

self.longPressPan.minimumPressDuration = 0.3
Kaiyuan Xu
źródło
to działa dla mnie w iOS 9 + Xcode 7 GM, inne metody, które wypróbowałem, są po prostu przydatne w iOS 7 i 8
Kaiyuan Xu
-4

Użyj funkcji interection widoku internetowego

   webView.userInteractionEnabled = false

Mi to pasuje

PS: pamiętaj, aby włączyć interakcję z powrotem, gdy chcesz, aby użytkownik mógł ponownie wejść w interakcję z przeglądarką internetową

Srohr
źródło
1
Witamy w stackoverflow. Czy odpowiedź naprawdę dodaje wartości do tego starego pytania? Zapoznaj się z odpowiedzią .
dbank
1
Rozważ rozszerzenie swojej odpowiedzi (podając mały przykład kodu), aby zwiększyć wartość swojej odpowiedzi. Ponadto odpowiedzi zawierające „to działa dla mnie” tak naprawdę nie budzą zaufania - lepiej przedstawić odpowiedź taką, jaka jest, a następnie rozwiązać problem, jeśli ktoś poprosi o wyjaśnienie Twojej odpowiedzi.
Aaron D