88 votes

La pagination UIScrollView en incréments plus petits que la taille d'image

J'ai un défilement de l'affichage, qui est la largeur de l'écran, mais seulement environ 70 pixels de haut. Il contient de nombreux 50 x 50 icônes (avec de l'espace autour d'eux) que je veux que l'utilisateur puisse choisir. Mais j'ai toujours envie de la faire défiler la vue de se comporter dans une paginé manière, toujours à l'arrêt avec une icône dans le centre exact.

Si les icônes ont la largeur de l'écran, ce ne serait pas un problème, car la UIScrollView d'échange prendrait soin d'elle. Mais parce que mon petit icônes sont beaucoup moins que la taille du contenu, il ne fonctionne pas.

J'ai vu ce problème avant dans une application d'appel AllRecipes. Je ne sais pas comment le faire.

Toutes les idées sur la façon d'obtenir la pagination par l'icône de la taille de base de travail?

123voto

Ben Gottlieb Points 59900

Essayez de faire votre scrollview moins de la taille de l'écran (largeur), mais de décocher la case "Clip des sous-vues" case à cocher dans l'IB. Ensuite, la superposition transparente, userInteractionEnabled = PAS d'affichage sur le dessus de celui-ci (à pleine largeur), qui remplace hitTest:withEvent: de retour de votre barre de défilement de la vue. Cela devrait vous donner ce que vous cherchez. Voir cette réponse pour plus de détails.

63voto

Split Points 1816

Il y a aussi une autre solution qui est probablement un peu mieux que la superposition de défilement de la vue avec un autre point de vue et dominante hitTest.

Vous pouvez sous-classe UIScrollView et de remplacer son pointInside. Ensuite, faites défiler la vue peuvent répondre pour touche en dehors de son cadre. Bien sûr, le reste est le même.

@interface PagingScrollView : UIScrollView {

    UIEdgeInsets responseInsets;
}

@property (nonatomic, assign) UIEdgeInsets responseInsets;

@end


@implementation PagingScrollView

@synthesize responseInsets;

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    CGPoint parentLocation = [self convertPoint:point toView:[self superview]];
    CGRect responseRect = self.frame;
    responseRect.origin.x -= responseInsets.left;
    responseRect.origin.y -= responseInsets.top;
    responseRect.size.width += (responseInsets.left + responseInsets.right);
    responseRect.size.height += (responseInsets.top + responseInsets.bottom);

    return CGRectContainsPoint(responseRect, parentLocation);
}

@end

6voto

colinta Points 682

L'on a accepté la réponse est très bon, mais il ne fonctionnera que pour l' UIScrollView classe, et aucun de ses descendants. Par exemple, si vous avez beaucoup de points de vue et de le convertir en UICollectionView, vous ne serez pas en mesure d'utiliser cette méthode, car la collecte de vue de supprimer les points de vue qu'il pense ne sont pas "visibles" (donc, même si elles ne sont pas coupées, elles disparaîtront).

Le commentaire à propos de qui mentionne scrollViewWillEndDragging:withVelocity:targetContentOffset: est, à mon avis, la réponse correcte.

Ce que vous pouvez faire est, à l'intérieur de ce délégué de la méthode de calcul de la page en cours/index. Vous pourrez ainsi décider de la vitesse et de la cible décalage mérite une "page suivante" du mouvement. Vous pouvez obtenir assez proche de l' pagingEnabled comportement.

note: je suis habituellement un RubyMotion dev ces jours-ci, de sorte que quelqu'un la preuve de ce Obj-C du code de la décision correcte. Désolé pour le mélange de camelCase et snake_case, je copie et collé une grande partie de ce code.

- (void) scrollViewWillEndDragging:(UIScrollView *)scrollView
         withVelocity:(CGPoint)velocity
         targetContentOffset:(inout CGPoint *)targetOffset
{
    CGFloat x = targetOffset->x;
    int index = [self convertXToIndex: x];
    CGFloat w = 300f;  // this is your custom page width
    CGFloat current_x = w * [self convertXToIndex: scrollView.contentOffset.x];

    // even if the velocity is low, if the offset is more than 50% past the halfway
    // point, proceed to the next item.
    if ( velocity.x < -0.5 || (current_x - x) > w / 2 ) {
      index -= 1
    } 
    else if ( velocity.x > 0.5 || (x - current_x) > w / 2 ) {
      index += 1;
    }

    if ( index >= 0 || index < self.items.length ) {
      CGFloat new_x = [self convertIndexToX: index];
      targetOffset->x = new_x;
    }
} 

3voto

Noah Witherspoon Points 35239

Jetez un oeil à l' -scrollView:didEndDragging:willDecelerate: méthode UIScrollViewDelegate. Quelque chose comme:

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    int x = scrollView.contentOffset.x;
    int xOff = x % 50;
    if(xOff < 25)
    	x -= xOff;
    else
    	x += 50 - xOff;

    int halfW = scrollView.contentSize.width / 2; // the width of the whole content view, not just the scroll view
    if(x > halfW)
    	x = halfW;

    [scrollView setContentOffset:CGPointMake(x,scrollView.contentOffset.y)];
}

Il n'est pas parfait-dernière j'ai essayé ce code j'ai un peu de comportement laid (en sautant, comme je le rappel) lors du retour à partir de caoutchouc de la bande de défilement. Vous pourriez être en mesure d'éviter que, par simple réglage du défilement de la vue d' bounces de la propriété d' NO.

3voto

Jacob Persson Points 181

Puisque je ne semble pas être autorisé à commenter mais je vais ajouter mes commentaires à Noé de réponse ici.

J'ai réussi à atteindre cet objectif en la méthode que Noé Witherspoon décrit. J'ai travaillé autour de la sauter comportement par tout simplement pas à l'appel de la setContentOffset: méthode lors de la scrollview est passé de ses bords.

         - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
         {      
             // Don't snap when at the edges because that will override the bounce mechanic
             if (self.contentOffset.x < 0 || self.contentOffset.x + self.bounds.size.width > self.contentSize.width)
                 return;

             ...
         }

J'ai aussi constaté que j'avais besoin de mettre en œuvre l' -scrollViewWillBeginDecelerating: méthode de UIScrollViewDelegate pour attraper tous les cas.

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