60 votes

UIScrollView : pagination horizontale, défilement vertical ?

Comment puis-je forcer un UIScrollView dans lequel la pagination et le défilement sont activés à ne se déplacer que verticalement ou horizontalement à un moment donné ?

Je crois savoir que le directionalLockEnabled devrait permettre d'atteindre cet objectif, mais un balayage diagonal fait toujours défiler la vue en diagonale au lieu de limiter le mouvement à un seul axe.

Edit : pour être plus clair, j'aimerais permettre à l'utilisateur de défiler horizontalement OU verticalement, mais pas les deux simultanément.

1voto

user422756 Points 11

Ma vue se compose de 10 vues horizontales, et certaines de ces vues se composent de plusieurs vues verticales, de sorte que vous obtiendrez quelque chose comme ceci :

1.0   2.0   3.1    4.1
      2.1   3.1
      2.2
      2.3

Avec la pagination activée sur l'axe horizontal et vertical

La vue possède également les attributs suivants :

[self setDelaysContentTouches:NO];
[self setMultipleTouchEnabled:NO];
[self setDirectionalLockEnabled:YES];

Maintenant, pour empêcher le défilement diagonal, faites ceci :

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
    int pageWidth = 768;
    int pageHeight = 1024;
    int subPage =round(self.contentOffset.y / pageHeight);
    if ((int)self.contentOffset.x % pageWidth != 0 && (int)self.contentOffset.y % pageHeight != 0) {
        [self setContentOffset:CGPointMake(self.contentOffset.x, subPage * pageHeight];
    } 
}

Ça marche comme un charme pour moi !

1voto

Mattias Wadman Points 6542

Voici mon implémentation d'une pagination UIScrollView qui n'autorisent que les défilements orthogonaux. Veillez à définir pagingEnabled a YES .

PagedOrthoScrollView.h

@interface PagedOrthoScrollView : UIScrollView
@end

PagedOrthoScrollView.m

#import "PagedOrthoScrollView.h"

typedef enum {
  PagedOrthoScrollViewLockDirectionNone,
  PagedOrthoScrollViewLockDirectionVertical,
  PagedOrthoScrollViewLockDirectionHorizontal
} PagedOrthoScrollViewLockDirection; 

@interface PagedOrthoScrollView ()
@property(nonatomic, assign) PagedOrthoScrollViewLockDirection dirLock;
@property(nonatomic, assign) CGFloat valueLock;
@end

@implementation PagedOrthoScrollView
@synthesize dirLock;
@synthesize valueLock;

- (id)initWithFrame:(CGRect)frame {
  self = [super initWithFrame:frame];
  if (self == nil) {
    return self;
  }

  self.dirLock = PagedOrthoScrollViewLockDirectionNone;
  self.valueLock = 0;

  return self;
}

- (void)setBounds:(CGRect)bounds {
  int mx, my;

  if (self.dirLock == PagedOrthoScrollViewLockDirectionNone) {
    // is on even page coordinates, set dir lock and lock value to closest page 
    mx = abs((int)CGRectGetMinX(bounds) % (int)CGRectGetWidth(self.bounds));
    if (mx != 0) {
      self.dirLock = PagedOrthoScrollViewLockDirectionHorizontal;
      self.valueLock = (round(CGRectGetMinY(bounds) / CGRectGetHeight(self.bounds)) *
                        CGRectGetHeight(self.bounds));
    } else {
      self.dirLock = PagedOrthoScrollViewLockDirectionVertical;
      self.valueLock = (round(CGRectGetMinX(bounds) / CGRectGetWidth(self.bounds)) *
                        CGRectGetWidth(self.bounds));
    }

    // show only possible scroll indicator
    self.showsVerticalScrollIndicator = dirLock == PagedOrthoScrollViewLockDirectionVertical;
    self.showsHorizontalScrollIndicator = dirLock == PagedOrthoScrollViewLockDirectionHorizontal;
  }

  if (self.dirLock == PagedOrthoScrollViewLockDirectionHorizontal) {
    bounds.origin.y = self.valueLock;
  } else {
    bounds.origin.x = self.valueLock;
  }

  mx = abs((int)CGRectGetMinX(bounds) % (int)CGRectGetWidth(self.bounds));
  my = abs((int)CGRectGetMinY(bounds) % (int)CGRectGetHeight(self.bounds));

  if (mx == 0 && my == 0) {
    // is on even page coordinates, reset lock
    self.dirLock = PagedOrthoScrollViewLockDirectionNone;
  }

  [super setBounds:bounds];
}

@end

1voto

Kurt Horimoto Points 26

J'ai également dû résoudre ce problème et, bien que la réponse d'Andrey Tarantsov contienne de nombreuses informations utiles pour comprendre le fonctionnement des UIScrollViews, je pense que la solution est un peu trop compliquée. Ma solution, qui n'implique aucune sous-classe ni aucun transfert de touche, est la suivante :

  1. Créez deux vues de défilement imbriquées, une pour chaque direction.
  2. Créez deux UIPanGestureRecognizers fictifs, à nouveau un pour chaque direction.
  3. Créez des dépendances d'échec entre les propriétés panGestureRecognizer des UIScrollViews et le UIPanGestureRecognizer fictif correspondant à la direction perpendiculaire à la direction de défilement souhaitée de votre UIScrollView en utilisant le sélecteur -requireGestureRecognizerToFail : de UIGestureRecognizer.
  4. Dans les callbacks -gestureRecognizerShouldBegin : de vos UIPanGestureRecognizers fictifs, calculez la direction initiale du panoramique en utilisant le sélecteur -translationInView : du geste (vos UIPanGestureRecognizers n'appelleront pas ce callback délégué tant que votre toucher n'aura pas été suffisamment translaté pour être enregistré comme un panoramique). Autorisez ou non votre reconnaissance de geste à commencer en fonction de la direction calculée, qui à son tour devrait contrôler si la reconnaissance de geste perpendiculaire UIScrollView pan sera autorisée à commencer.
  5. Dans -gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer :, ne permettez pas à votre UIPanGestureRecognizers factice de fonctionner en même temps que le défilement (à moins que vous n'ayez un comportement supplémentaire à ajouter).

0voto

Tim Keating Points 2942

Si vous n'avez pas essayé de le faire dans la version bêta 3.0, je vous recommande d'essayer. J'utilise actuellement une série de tableaux à l'intérieur d'une vue défilante, et cela fonctionne comme prévu. (Enfin, le défilement fonctionne, en tout cas. J'ai trouvé cette question en cherchant une solution à un problème totalement différent...)

0voto

Chandan Shetty SP Points 2389

Si vous avez un grand scrollview... et vous voulez restreindre le défilement diagonal http://chandanshetty01.blogspot.in/2012/07/restricting-diagonal-scrolling-in.html

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X