Impedire a UIWebView di "rimbalzare" verticalmente?


225

Qualcuno sa come impedire a UIWebView di rimbalzare verticalmente? Voglio dire quando un utente tocca lo schermo dell'iPhone, trascina il dito verso il basso e la visualizzazione Web mostra un punto vuoto sopra la pagina Web che avevo caricato?

Ho esaminato le seguenti possibili soluzioni, ma nessuna di queste ha funzionato per me:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/996-turn-off-scrolling-bounces-uiwebview.html

http://forums.macrumors.com/showthread.php?t=619534

Come posso impedire a UIScrollView di rimbalzare in senso orizzontale?


1
Spero che tu abbia considerato le implicazioni sull'usabilità della disabilitazione di tale funzione. È lì per un motivo. Detto questo, sono anche curioso di sapere come lo faresti.
Michael Haren,

Il modo in cui l'ho incorporato nella mia app, sembra apparentemente con alcuni altri elementi di visualizzazione che ho, e l'unica volta che non appare così è quando si verifica il rimbalzo ... Sicuramente un buon punto però!
Brad Parks,

Risposte:


424
for (id subview in webView.subviews)
  if ([[subview class] isSubclassOfClass: [UIScrollView class]])
    ((UIScrollView *)subview).bounces = NO;

... sembra funzionare bene.

Sarà accettato anche sull'App Store.

Aggiornamento : in iOS 5.x + c'è un modo più semplice - UIWebViewha scrollViewproprietà, quindi il tuo codice può apparire così:

webView.scrollView.bounces = NO;

Lo stesso vale per WKWebView.


Funziona. Nessuna sottoclasse richiesta e se Apple dovesse mai cambiare la gerarchia di UIWebView, non dovrebbe andare in crash.
leolobato,

2
Questa correzione sembra funzionare solo nel mio OS 4.1 Simulator, non sul mio OS 3.1.3 iPhone. Qualcuno sa se questa correzione funziona solo su particolari versioni del sistema operativo?
Dan J,

@MirukRusin - Come puoi garantire che questa app venga accettata in base a tre righe di codice? : P
Moshe,

@Mirek - Ti sei perso il punto. Come fai a sapere che nient'altro nell'app verrà rifiutata?
Moshe,

6
Questo ha funzionato bene per me. Per comodità, ho aggiunto una categoria in UIWebViewmodo da poter chiamare [webView setBounces:NO]ovunque volessi.
zekel,

46

Stavo guardando un progetto che semplifica la creazione di app Web come applicazioni installabili complete sull'iPhone chiamato QuickConnect e ho trovato una soluzione che funziona, se non vuoi che lo schermo sia scorrevole, che nel mio caso Non l'ho fatto

Nel summenzionato post sul progetto / blog, menzionano una funzione javascript che puoi aggiungere per disattivare il rimbalzo, che si riduce essenzialmente a questo:

    document.ontouchmove = function(event){
        event.preventDefault();
    }

Se vuoi vedere di più su come lo implementano, basta scaricare QuickConnect e verificarlo .... Ma fondamentalmente tutto ciò che fa è chiamare javascript al caricamento della pagina ... Ho provato a metterlo in testa al mio documento, e sembra funzionare bene.


Questa risposta è il modo corretto per interrompere lo scorrimento verticale del contenuto all'interno di UIWebView.
Jessedc

3
Avresti potuto dare l'intera risposta, in primo luogo non voglio scaricare un intero codice risorsa di un'altra app e non riesco nemmeno a trovarlo. La tua risposta si basa sul fatto che un altro sito Web è lo stesso di quando hai risposto.
Jonathan.

Questa risposta e la risposta accettata sopra sembrano essere richieste a volte. Nel mio caso, ho scoperto che se la vista Web non fosse stata ancora caricata, il rimbalzo sarebbe rimasto lì fino a quando il JS sopra non sarebbe stato effettivamente caricato nel sistema. Quindi la risposta sembra essere che questa e la risposta accettata sopra siano entrambe, a volte, richieste.
Kalle,

3
come ha detto Jessedc, questo fermerà lo scorrimento verticale, non solo il rimbalzo. ciò significa che se hai div o meno che richiede lo scorrimento, non scorrerà.
memical

18

Bene, tutto ciò che ho fatto per raggiungere questo obiettivo è:

UIView *firstView = [webView.subviews firstObject];

if ([firstView isKindOfClass:[UIScrollView class]]) {

    UIScrollView *scroll = (UIScrollView*)firstView;
   [scroll setScrollEnabled:NO];  //to stop scrolling completely
   [scroll setBounces:NO]; //to stop bouncing 

}

Funziona bene per me ... Inoltre, la risposta selezionata per questa domanda è quella che Apple rifiuterà se la usi nella tua app per iPhone.


3
Questo è il modo migliore e più semplice. Questa dovrebbe essere la risposta accettata! +1
PostCodeism

3
Non farlo: la mia app è stata rifiutata per l'utilizzo della prima riga. Ho perso così tanto tempo per me. ho usato [[webView.subviews lastObject] setScrollEnabled: NO]; e apple ha detto che era un'API privata e quindi l'ha respinta; sto per inviare nuovamente ma ho usato "userInteractionEnabled: NO" poiché non ho bisogno di collegamenti attivi nell'app.
Veeru,

UIWebView eredita da UIView. UIView ha una panoramica delle proprietà. Cosa è privato qui? Tutto questo lo puoi trovare su developer.apple.com
Valerii Pavlov

3
Ho qualcosa come 4 app sull'appstore che usa questo. L'app è stata chiaramente respinta per un altro motivo. questa non è un'API privata.
Zigglzworth,

4
Questa non è davvero una buona idea. Stai facendo affidamento sul fatto che per ora potrebbe essere UIScrollViewla prima sottoview, UIWebViewma questo potrebbe facilmente cambiare in futuri (anche minori) aggiornamenti di iOS o configurazioni particolari. Dovresti davvero fare unfor un'iterazione subviewsper trovare effettivamente il UIScrollView(non è davvero tanto lavoro e almeno sei sicuro di ottenere un UIScrollViewprogramma senza crash ...
Jonathan Ellis

17

Nell'SDK di iOS 5 è possibile accedere direttamente alla vista di scorrimento associata a una vista Web anziché scorrere le relative visualizzazioni secondarie.

Quindi per disabilitare il 'rimbalzo' nella vista di scorrimento puoi usare:

myWebView.scrollView.bounces = NO;

Vedere il riferimento alla classe UIWebView .

(Tuttavia, se è necessario supportare versioni dell'SDK precedenti alla 5.0, è necessario seguire i consigli di Mirek Rusin .)



9

Avvertimento. Ho usato setAllowsRubberBanding: nella mia app e Apple lo ha rifiutato, affermando che le funzioni API non pubbliche non sono consentite (cita: 3.3.1)



3

Il metodo di Brad ha funzionato per me. Se lo usi potresti voler renderlo un po 'più sicuro.

id scrollView = [yourWebView.subviews objectAtIndex: 0];
if ([scrollView respondsToSelector: @selector (setAllowsRubberBanding :)])
{
    [scrollView performSelector: @selector (setAllowsRubberBanding :) withObject: NO];
}

Se apple cambia qualcosa, il rimbalzo tornerà, ma almeno l'app non si arresterà in modo anomalo.


3

Su iOS5 solo se prevedi di consentire agli utenti di ingrandire i contenuti della visualizzazione web (ei: tocca due volte) l'impostazione di rimbalzo non è sufficiente. È necessario impostare anche le proprietà alwaysBounceHorizontal e alwaysBounceVertical su NO, altrimenti quando eseguono lo zoom indietro (un altro doppio tocco ...) per impostazione predefinita rimbalzerà di nuovo.


2

Ho attraversato la raccolta delle sottoview di UIWebView e ho impostato i loro sfondi su [UIColor blackColor], lo stesso colore dello sfondo della pagina web. La vista continuerà a rimbalzare ma non mostrerà quel brutto sfondo grigio scuro.


1
In realtà è piuttosto brutto, perché se Apple dovesse mai cambiare gli interni di UIWebView, questo hack potrebbe rompersi.
bpapa,

2

Mi sembra che UIWebView abbia un UIScrollView. A tale scopo puoi utilizzare API documentate, ma il rimbalzo è impostato per entrambe le direzioni, non singolarmente. Questo è nei documenti API. UIScrollView ha una proprietà di rimbalzo, quindi qualcosa del genere funziona (non so se c'è più di una vista di scorrimento):

NSArray *subviews = myWebView.subviews;
NSObject *obj = nil;
int i = 0;
for (; i < subviews.count ; i++)
{
    obj = [subviews objectAtIndex:i];

    if([[obj class] isSubclassOfClass:[UIScrollView class]] == YES)
    {
        ((UIScrollView*)obj).bounces = NO;
    }
}

2

Sono stato infastidito nello scoprire che UIWebView non è una vista di scorrimento, quindi ho creato una sottoclasse personalizzata per accedere alla vista di scorrimento della vista Web. Questa sottoclasse contiene una vista di scorrimento in modo da poter personalizzare il comportamento della vista Web. I punti di forza di questa classe sono:

@class CustomWebView : UIWebview
...

- (id) initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
// WebViews are subclass of NSObject and not UIScrollView and therefore don't allow customization.
// However, a UIWebView is a UIScrollViewDelegate, so it must CONTAIN a ScrollView somewhere.
// To use a web view like a scroll view, let's traverse the view hierarchy to find the scroll view inside the web view.
for (UIView* v in self.subviews){
    if ([v isKindOfClass:[UIScrollView class]]){
        _scrollView = (UIScrollView*)v; 
        break;
    }
}
return self;

}

Quindi, quando si crea una visualizzazione Web personalizzata, è possibile disabilitare il rimbalzo con:

customWebView.scrollView.bounces = NO; //(or customWebView.scrollView.alwaysBounceVertically = NO)

Questo è un ottimo modo generale per creare una visualizzazione Web con comportamento di scorrimento personalizzabile. Ci sono solo alcune cose a cui prestare attenzione:

  • come con qualsiasi vista, dovrai anche sovrascrivere - (id) initWithCoder: se lo usi in Interface Builder
  • quando si crea inizialmente una vista Web, la sua dimensione del contenuto è sempre uguale alla dimensione del riquadro della vista. Dopo aver fatto scorrere il Web, la dimensione del contenuto rappresenta la dimensione del contenuto Web effettivo all'interno della vista. Per ovviare a questo, ho fatto qualcosa di strano - chiamando -setContentOffset: CGPointMake (0,1) animato: SÌ per forzare una modifica impercettibile che imposterà la dimensione del contenuto corretta della vista web.

2

Mi sono imbattuto in questa ricerca di una risposta e alla fine ho solo avuto fortuna con una mia risposta facendo casino. L'ho fatto

[[webview scrollView] setBounces:NO];

e ha funzionato.


2

Questo ha funzionato anche per me e magnificamente (sto usando phonegap con webView)

[[webView.webView scrollView] setScrollEnabled:NO];

o

[[webView scrollView] setScrollEnabled:NO];

1

Ho provato un approccio leggermente diverso per impedire agli oggetti UIWebView di scorrere e rimbalzare: l'aggiunta di un riconoscimento di gesti per sovrascrivere altri gesti.

Sembra che UIWebView o la sua sottoview scroller utilizzino il proprio riconoscimento dei gesti di panoramica per rilevare lo scorrimento dell'utente. Ma secondo la documentazione di Apple esiste un modo legittimo di scavalcare un riconoscitore di gesti con un altro. Il protocollo UIGestureRecognizerDelegate ha un metodo gestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer: - che consente di controllare il comportamento di eventuali riconoscitori di gesti in collisione.

Quindi, quello che ho fatto è stato

nel metodo viewDidLoad del controller di visualizzazione:

// Install a pan gesture recognizer                                                                                        // We ignore all the touches except the first and try to prevent other pan gestures                                                     
// by registering this object as the recognizer's delegate                                                                                        
UIPanGestureRecognizer *recognizer;                                                                                                               
recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanFrom:)];                                                   
recognizer.delegate = self;                                                                                                                       
recognizer.maximumNumberOfTouches = 1;                                                                                                            
[self.view addGestureRecognizer:recognizer];                                                                                                          
self.panGestureFixer = recognizer;                                                                                                                  
[recognizer release]; 

quindi, il metodo di override del gesto:

// Control gestures precedence                                                                                                                            
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer                                                                                        
        shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer                                                  
{                                                                                                                                                         
        // Prevent all panning gestures (which do nothing but scroll webViews, something we want to disable in                                          
        // the most painless way)                                                                                                                         
        if ([otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]])                                                                        
        {
            // Just disable every other pan gesture recognizer right away                                                                             
            otherGestureRecognizer.enabled = FALSE;
        }                                                                                                                                                  
        return NO;                                                                                                                                        
}              

Naturalmente, questo metodo delegato può essere più complesso in un'applicazione reale: possiamo disabilitare altri riconoscitori in modo selettivo, analizzando otherGestureRecognizer.view e prendendo decisioni in base a quale vista sia.

E, infine, per completezza, il metodo che abbiamo registrato come gestore della panoramica:

- (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer 
{ 
    // do nothing as of yet
}

può essere vuoto se tutto ciò che vogliamo è annullare lo scorrimento e il rimbalzo delle visualizzazioni Web, oppure può contenere il nostro codice per implementare il tipo di movimenti di pan e animazioni che vogliamo davvero ...

Finora sto solo sperimentando tutte queste cose e sembra funzionare più o meno come lo voglio. Tuttavia, non ho ancora provato a inviare alcuna app a iStore. Ma credo di non aver usato nulla di non documentato finora ... Se qualcuno lo trova diversamente, per favore informami.





0

Una delle sottoview di UIWebViewdovrebbe essere a UIScrollView. Impostare la sua scrollEnabledproprietà su NOe la visualizzazione Web avrà lo scorrimento disabilitato del tutto.

Nota: questo utilizza tecnicamente un'API privata e pertanto l'app potrebbe essere rifiutata o arrestata in modo anomalo nelle versioni future del sistema operativo. Usa @tryerespondsToSelector


Ho provato questo, e si guasta quando lo provo ... Stranamente, posso accedere e impostare scrollView.bounces (senza alcun effetto), ma quando provo a impostare scrollEnabled, si guasta ...
Brad Parks

Credo che la sottoview si chiami UIScroller, non UIScrollView. UIScroller è una classe non documentata e non supportata che condivide molto in comune con UIScrollView, ma non puoi dipendere da tutto ciò che funziona allo stesso modo e non cambia nelle future versioni del sistema operativo.
Marco,

L'ho fatto su un'app per iPad (non iPhone) con iOS 3.2 ed è stato in grado di ottenere un UIScrollView dal mio UIWebView. Ho personalizzato con successo questo punto di vista per cambiare qualcosa di più del semplice comportamento di rimbalzo in modo da poter testimoniare che funziona su iPad. La mia app non è passata attraverso l'app store, ma non credo che ci sarà un problema con le API non documentate qui. La parte intelligente di questa soluzione è che stai solo attraversando una gerarchia di UIView e stai usando un UIScrollView, entrambi perfettamente kosher.
Rolf Hendriks,

0

Guarda nella bouncesproprietà di UIScrollView. Dimentica i documenti Apple:

Se il valore della proprietà è YES(impostazione predefinita), la vista di scorrimento rimbalza quando incontra un limite del contenuto. Il rimbalzo indica visivamente che lo scorrimento ha raggiunto un limite del contenuto. Se il valore è NO, lo scorrimento si interrompe immediatamente al limite del contenuto senza rimbalzare.

Assicurati di usare il giusto UIScrollView. Non sono sicuro di come sia la gerarchia per a UIWebView, ma la vista di scorrimento potrebbe essere un genitore, non un figlio, di UIWebView.


0

Per disabilitare lo UIWebViewscorrimento è possibile utilizzare la seguente riga di codice:

[ObjWebview setUserInteractionEnabled:FALSE];

In questo esempio, ObjWebviewè di tipo UIWebView.


0

webView.scrollView.scrollEnabled = NO; webView.scrollView.bounces = NO;

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.