Arrêter UIWebView de «rebondir» verticalement?

225

Est-ce que quelqu'un sait comment empêcher une UIWebView de rebondir verticalement? Je veux dire lorsqu'un utilisateur touche son écran d'iphone, fait glisser son doigt vers le bas et que la vue Web affiche un espace vide au-dessus de la page Web que j'ai chargée?

J'ai examiné les solutions possibles suivantes, mais aucune n'a fonctionné pour moi:

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

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

Comment empêcher un UIScrollView de rebondir horizontalement?

Brad Parks
la source
1
J'espère que vous avez pris en compte les implications sur la convivialité de la désactivation de cette fonctionnalité. C'est là pour une raison. Cela dit, je suis également curieux de savoir comment vous feriez cela.
Michael Haren
La façon dont je l'ai intégré dans mon application, il apparaît de manière apparente avec certains autres éléments de vue que j'ai, et la seule fois où il n'apparaît pas, c'est quand le rebond se produit .... Certainement un bon point!
Brad Parks

Réponses:

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

... semble bien fonctionner.

Il sera également accepté sur l'App Store.

Mise à jour : dans iOS 5.x +, il existe un moyen plus simple - UIWebViewpossède une scrollViewpropriété, de sorte que votre code peut ressembler à ceci:

webView.scrollView.bounces = NO;

Il en va de même WKWebView.

Mirek Rusin
la source
Ça marche. Aucun sous-classement requis et si Apple modifie jamais la hiérarchie UIWebView, il ne devrait pas se bloquer.
leolobato
2
Ce correctif semble fonctionner uniquement dans mon simulateur OS 4.1, pas sur mon iPhone OS 3.1.3. Quelqu'un sait-il si ce correctif ne fonctionne que sur des versions de système d'exploitation particulières?
Dan J
@MirukRusin - Comment pouvez-vous garantir que cette application sera acceptée sur la base de trois lignes de code? : P
Moshe
@Mirek - Vous avez manqué mon point. Comment savez-vous que rien d'autre dans l'application ne la fera rejeter?
Moshe
6
CA marchait bien pour moi. Pour plus de commodité, j'ai ajouté une catégorie à UIWebViewafin que je puisse appeler [webView setBounces:NO]où je voulais.
zekel
46

Je regardais un projet qui facilite la création d'applications Web en tant qu'applications installables à part entière sur l'iPhone appelé QuickConnect , et j'ai trouvé une solution qui fonctionne, si vous ne voulez pas du tout que votre écran puisse défiler, ce qui dans mon cas Non.

Dans le projet / blog mentionné ci-dessus, ils mentionnent une fonction javascript que vous pouvez ajouter pour désactiver le rebond, ce qui se résume essentiellement à ceci:

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

Si vous voulez en savoir plus sur la façon dont ils l'implémentent, téléchargez simplement QuickConnect et vérifiez-le .... Mais en gros, tout ce qu'il fait, c'est appeler ce javascript au chargement de la page ... J'ai essayé de le mettre en tête de mon document, et cela semble bien fonctionner.

Brad Parks
la source
Cette réponse est la bonne façon d'arrêter le défilement vertical du contenu dans une UIWebView.
Jessedc
3
Vous auriez pu donner toute la réponse, tout d'abord je ne veux pas télécharger tout le code source d'une autre application, et je ne le trouve même pas. Votre réponse repose sur un autre site Web étant le même que lorsque vous avez répondu.
Jonathan.
Cette réponse et la réponse acceptée ci-dessus semblent parfois nécessaires. Dans mon cas, j'ai constaté que si la vue Web n'était pas encore chargée, le rebond serait là jusqu'à ce que le JS ci-dessus soit réellement chargé dans le système. Donc, la réponse semble être que cela et la réponse acceptée ci-dessus sont parfois nécessaires.
Kalle
3
comme l'a dit Jessedc, cela arrêtera le défilement vertical, pas seulement le rebond. cela signifie que si vous avez div ou si cela nécessite un défilement, il ne défilera pas.
mémorable
18

Eh bien, tout ce que j'ai fait pour y parvenir est:

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 

}

Fonctionne bien pour moi ... En outre, la réponse cochée pour cette question est celle qu'Apple rejettera si vous l'utilisez dans votre application iphone.

Zigglzworth
la source
3
C'est le moyen le meilleur et le plus simple. Cela devrait être la réponse acceptée! +1
PostCodeism
3
Ne faites pas cela - mon application a été rejetée pour avoir utilisé la première ligne. J'ai perdu tellement de temps pour moi. j'ai utilisé [[webView.subviews lastObject] setScrollEnabled: NO]; et apple a déclaré qu'il s'agissait d'une API privée et l'a donc rejetée; suis sur le point de soumettre à nouveau maintenant mais utilisé "userInteractionEnabled: NO" car je n'ai pas besoin de liens actifs dans l'application.
Veeru
UIWebView hérite de UIView. UIView a des sous-vues de propriété. Qu'est-ce qui est privé ici? Tout cela, vous pouvez le trouver sur developer.apple.com
Valerii Pavlov
3
J'ai quelque chose comme 4 applications sur l'Appstore utilisant cela. Votre application a été clairement rejetée pour une autre raison. ce n'est pas une API privée.
Zigglzworth
4
Ce n'est vraiment pas une bonne idée. Vous comptez sur le fait que la UIScrollViewpremière sous-vue UIWebViewpourrait bien être le cas pour l'instant, mais cela pourrait facilement changer dans les futures mises à jour (même mineures) d'iOS ou de configurations particulières. Vous devriez vraiment faire une foritération subviewspour trouver le UIScrollView(ce n'est vraiment pas beaucoup de travail et au moins vous êtes assuré d'obtenir un UIScrollViewet de ne pas planter votre programme ...
Jonathan Ellis
17

Dans le SDK iOS 5, vous pouvez accéder directement à la vue de défilement associée à une vue Web au lieu de parcourir ses sous-vues.

Donc, pour désactiver le «rebond» dans la vue de défilement, vous pouvez utiliser:

myWebView.scrollView.bounces = NO;

Voir la référence de classe UIWebView .

(Cependant, si vous devez prendre en charge les versions du SDK avant 5.0, vous devez suivre les conseils de Mirek Rusin .)

jstr
la source
12

Swift 3

webView.scrollView.bounces = false
Ego Slayer
la source
9

Avertissement. J'ai utilisé setAllowsRubberBanding: dans mon application, et Apple l'a rejeté, déclarant que les fonctions API non publiques ne sont pas autorisées (cite: 3.3.1)

Raf
la source
4

Dans Swift pour désactiver les rebonds

webViewObj.scrollView.bounces = false
Jugal K Balara
la source
3

La méthode de Brad a fonctionné pour moi. Si vous l'utilisez, vous voudrez peut-être le rendre un peu plus sûr.

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

Si Apple change quelque chose, le rebond reviendra - mais au moins votre application ne plantera pas.

Gavin Maclean
la source
3

Sur iOS5 uniquement si vous prévoyez de laisser les utilisateurs zoomer sur le contenu de la vue Web (ei: appuyez deux fois), le paramètre de rebond n'est pas suffisant. Vous devez également définir les propriétés alwaysBounceHorizontal et alwaysBounceVertical sur NO, sinon lors d'un zoom arrière (un autre double tapotement ...) par défaut, il rebondira à nouveau.

il Malvagio Dottor Prosciutto
la source
2

J'ai parcouru la collection des sous-vues d'UIWebView et défini leurs arrière-plans sur [UIColor blackColor], la même couleur que l'arrière-plan de la page Web. La vue rebondira toujours mais elle ne montrera pas ce laid fond gris foncé.

pedro
la source
1
En fait, c'est assez mauvais, car si Apple modifie jamais les composants internes d'UIWebView, ce piratage pourrait se briser.
bpapa
2

Il me semble que l'UIWebView a un UIScrollView. Vous pouvez utiliser des API documentées pour cela, mais le rebond est défini dans les deux sens, pas individuellement. C'est dans la documentation de l'API. UIScrollView a une propriété de rebond, donc quelque chose comme ça fonctionne (je ne sais pas s'il y a plus d'une scrollview):

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;
    }
}
spymaster
la source
2

J'étais ennuyé de découvrir que UIWebView n'est pas une vue de défilement, j'ai donc créé une sous-classe personnalisée pour accéder à la vue de défilement de la vue Web. Cette sous-classe contient une vue de défilement afin que vous puissiez personnaliser le comportement de votre vue Web. Les punchlines de cette classe sont:

@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;

}

Ensuite, lorsque vous créez une vue Web personnalisée, vous pouvez désactiver le rebond avec:

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

Il s'agit d'un excellent moyen général de créer une vue Web avec un comportement de défilement personnalisable. Il y a juste quelques points à surveiller:

  • comme avec n'importe quelle vue, vous devrez également remplacer - (id) initWithCoder: si vous l'utilisez dans Interface Builder
  • lorsque vous créez initialement une vue Web, sa taille de contenu est toujours la même que la taille du cadre de la vue. Après avoir fait défiler le Web, la taille du contenu représente la taille du contenu Web réel à l'intérieur de la vue. Pour contourner cela, j'ai fait quelque chose de hacky - en appelant -setContentOffset: CGPointMake (0,1) animé: YES pour forcer un changement imperceptible qui définira la taille de contenu appropriée de la vue Web.
Rolf Hendriks
la source
2

Je suis tombé sur cette recherche d'une réponse et j'ai finalement eu de la chance d'avoir ma propre réponse en me moquant. J'ai fait

[[webview scrollView] setBounces:NO];

et ça a marché.

Luc
la source
2

Cela a fonctionné pour moi, et magnifiquement aussi (j'utilise phonegap avec webView)

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

ou

[[webView scrollView] setScrollEnabled:NO];
Jason G
la source
1

J'ai essayé une approche légèrement différente pour empêcher les objets UIWebView de défiler et de rebondir: ajouter un reconnaisseur de gestes pour remplacer les autres gestes.

Il semble que UIWebView ou sa sous-vue de défilement utilise son propre identificateur de mouvement panoramique pour détecter le défilement de l'utilisateur. Mais selon la documentation d'Apple, il existe un moyen légitime de remplacer un identificateur de gestes par un autre. Le protocole UIGestureRecognizerDelegate a une méthode gestureRecognizer: shouldRecognizeSimultaneousWithGestureRecognizer: - qui permet de contrôler le comportement de tout identificateur de mouvements en collision.

Donc, ce que j'ai fait

dans la méthode viewDidLoad du contrôleur de vue:

// 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]; 

puis, la méthode de remplacement de geste:

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

Bien sûr, cette méthode déléguée peut être plus complexe dans une application réelle - nous pouvons désactiver d'autres reconnaisseurs de manière sélective, en analysant otherGestureRecognizer.view et prendre une décision en fonction de la vue.

Et, enfin, par souci d'exhaustivité, la méthode que nous avons enregistrée en tant que gestionnaire de pan:

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

il peut être vide si tout ce que nous voulons est d'annuler le défilement et le rebond des vues Web, ou il peut contenir notre propre code pour implémenter le type de mouvements de panoramique et d'animations que nous voulons vraiment ...

Jusqu'à présent, je ne fais qu'expérimenter avec toutes ces choses, et cela semble fonctionner plus ou moins comme je le veux. Cependant, je n'ai pas encore essayé de soumettre des applications à iStore. Mais je crois que je n'ai encore rien utilisé sans papiers ... Si quelqu'un le trouve autrement, veuillez m'en informer.

PP-RD
la source
0

L'une des sous-vues de UIWebViewdevrait être a UIScrollView. Définissez sa scrollEnabledpropriété sur NOet la vue Web aura le défilement entièrement désactivé.

Remarque: cela utilise techniquement une API privée et votre application pourrait donc être rejetée ou planter dans les futures versions du système d'exploitation. Utiliser @tryetrespondsToSelector

rpetrich
la source
J'ai essayé cela, et cela échoue quand je l'essaye ... Étrangement, je peux accéder et définir scrollView.bounces (sans effet), mais quand j'essaie de définir scrollEnabled, cela échoue ...
Brad Parks
Je crois que la sous-vue s'appelle UIScroller, pas UIScrollView. UIScroller est une classe non documentée et non prise en charge qui partage beaucoup de points communs avec UIScrollView, mais vous ne pouvez pas dépendre que tout fonctionne de la même manière et ne change pas dans les futures versions du système d'exploitation.
Marco
J'ai fait cela sur une application iPad (pas iPhone) exécutant iOS 3.2, et j'ai pu obtenir un UIScrollView de mon UIWebView. J'ai réussi à personnaliser cette vue pour changer plus que son comportement de rebond afin de pouvoir témoigner de ce fonctionnement sur iPad. Mon application n'est pas passée par l'App Store, mais je ne pense pas qu'il y aura un problème avec les API non documentées ici. La partie intelligente de cette solution est que vous traversez simplement une hiérarchie UIView et utilisez un UIScrollView - qui sont tous deux parfaitement casher.
Rolf Hendriks
0

Examinez la bouncespropriété de UIScrollView. Quoth les documents Apple:

Si la valeur de la propriété est YES(par défaut), la vue de défilement rebondit lorsqu'elle rencontre une limite du contenu. Le rebond visuel indique que le défilement a atteint un bord du contenu. Si la valeur est NO, le défilement s'arrête immédiatement à la limite du contenu sans rebond.

Assurez-vous que vous utilisez le bon UIScrollView. Je ne sais pas à quoi ressemble la hiérarchie pour un UIWebView, mais la vue de défilement pourrait être un parent, pas un enfant, du UIWebView.

Alex
la source
0

Pour désactiver le UIWebViewdéfilement, vous pouvez utiliser la ligne de code suivante:

[ObjWebview setUserInteractionEnabled:FALSE];

Dans cet exemple, ObjWebviewest de type UIWebView.

Sandip Patel - SM
la source
0

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

Kumaresan P
la source