57 votes

UICollectionView aligner manque de logique dans le sens horizontal de pagination scrollview

J'ai un UICollectionView, ce qui fonctionne bien, jusqu'à ce que je commence à défiler. Voici quelques photos de la première: enter image description here

Comme vous pouvez le voir c'est génial. Comme je l'ai démarrer le défilement (la pagination est activée) le premier va un peu à l'écran: enter image description here

C'est le problème. À l'origine de mon point de vue 3 points de vue et je veux faire défiler et afficher les 3 points de vue. Mais comme il défile (la pagination est activée) il se cache un peu de la première vue et de montrer peu de la prochaine première vue à partir de la page suivante.

Et voici une vidéo, parce que c'est un peu dur à expliquer: Vidéo du problème (Dropbox)

Voici une photo de mon UICollectionViewparamètres de: enter image description here

Ça va être génial si quelqu'un peut vous aider!

76voto

Ji Fang Points 671

La question fondamentale est la Disposition de Flux n'est pas conçu pour soutenir la pagination. Pour atteindre la pagination effet, vous aurez à sacrifier l'espace entre les cellules. Et bien calculer les cellules image et en faire peut-être divisé par l'affichage de la collection frame sans restes. Je vais vous expliquer la raison.

Dire la disposition suivante est ce que tu voulais.

enter image description here

Avis, le plus de marge de gauche (vert) ne fait pas partie de l'espacement entre les cellules. Il est déterminé par le flux de la section mise en médaillon. Depuis la disposition de flux ne prend pas en charge hétérogène valeur d'espacement. Ce n'est pas une tâche triviale.

Par conséquent, après le réglage de l'espacement et l'encart. La disposition suivante est ce que vous obtiendrez.

enter image description here

Après faites défiler jusqu'à la page suivante. Vos cellules sont évidemment pas alignés, comme ce que vous attendiez.

enter image description here

Faire de l'espacement entre les cellules 0 peut résoudre ce problème. Cependant, il limite votre conception si vous voulez la marge supplémentaire sur la page, surtout si la marge est différent de l'espacement entre les cellules. Il exige également le point de vue image doit être divisible par la cellule de trame. Parfois, c'est une douleur si votre point de vue image n'est pas fixe (en tenant compte de la rotation des cas).

La véritable solution est de la sous-classe UICollectionViewFlowLayout et de redéfinir des méthodes suivantes

- (CGSize)collectionViewContentSize
{
    // Only support single section for now.
    // Only support Horizontal scroll 
    NSUInteger count = [self.collectionView.dataSource collectionView:self.collectionView
                                               numberOfItemsInSection:0];

    CGSize canvasSize = self.collectionView.frame.size;
    CGSize contentSize = canvasSize;
    if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal)
    {
        NSUInteger rowCount = (canvasSize.height - self.itemSize.height) / (self.itemSize.height + self.minimumInteritemSpacing) + 1;
        NSUInteger columnCount = (canvasSize.width - self.itemSize.width) / (self.itemSize.width + self.minimumLineSpacing) + 1;
        NSUInteger page = ceilf((CGFloat)count / (CGFloat)(rowCount * columnCount));
        contentSize.width = page * canvasSize.width;
    }

    return contentSize;
}


- (CGRect)frameForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CGSize canvasSize = self.collectionView.frame.size;

    NSUInteger rowCount = (canvasSize.height - self.itemSize.height) / (self.itemSize.height + self.minimumInteritemSpacing) + 1;
    NSUInteger columnCount = (canvasSize.width - self.itemSize.width) / (self.itemSize.width + self.minimumLineSpacing) + 1;

    CGFloat pageMarginX = (canvasSize.width - columnCount * self.itemSize.width - (columnCount > 1 ? (columnCount - 1) * self.minimumLineSpacing : 0)) / 2.0f;
    CGFloat pageMarginY = (canvasSize.height - rowCount * self.itemSize.height - (rowCount > 1 ? (rowCount - 1) * self.minimumInteritemSpacing : 0)) / 2.0f;

    NSUInteger page = indexPath.row / (rowCount * columnCount);
    NSUInteger remainder = indexPath.row - page * (rowCount * columnCount);
    NSUInteger row = remainder / columnCount;
    NSUInteger column = remainder - row * columnCount;

    CGRect cellFrame = CGRectZero;
    cellFrame.origin.x = pageMarginX + column * (self.itemSize.width + self.minimumLineSpacing);
    cellFrame.origin.y = pageMarginY + row * (self.itemSize.height + self.minimumInteritemSpacing);
    cellFrame.size.width = self.itemSize.width;
    cellFrame.size.height = self.itemSize.height;

    if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal)
    {
        cellFrame.origin.x += page * canvasSize.width;
    }

    return cellFrame;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes * attr = [super layoutAttributesForItemAtIndexPath:indexPath];
    attr.frame = [self frameForItemAtIndexPath:indexPath];
    return attr;
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSUInteger count = [self.collectionView.dataSource collectionView:self.collectionView
                                               numberOfItemsInSection:0];

    NSMutableArray * attrs = [NSMutableArray array];

    for (NSUInteger idx = 0; idx < count; ++idx)
    {
        UICollectionViewLayoutAttributes * attr = nil;
        NSIndexPath * idxPath = [NSIndexPath indexPathForRow:idx inSection:0];
        CGRect itemFrame = [self frameForItemAtIndexPath:idxPath];
        if (CGRectIntersectsRect(itemFrame, rect))
        {
            attr = [self layoutAttributesForItemAtIndexPath:idxPath];
            [attrs addObject:attr];
        }
    }

    return attrs;
}

Avis, extrait de code ci-dessus ne prend en charge une section de défilement horizontale et la direction. Mais il n'est pas difficile à développer.

Aussi, si vous n'avez pas des millions de cellules. La mise en cache de ces UICollectionViewLayoutAttributes peut être une bonne idée.

28voto

Leszek S Points 331

Vous pouvez désactiver la pagination sur UICollectionView et de mettre en œuvre une coutume de défilement horizontal/mécanisme de pagination avec une page personnalisée largeur/décalage comme ceci:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    float pageWidth = 210;

    float currentOffset = scrollView.contentOffset.x;
    float targetOffset = targetContentOffset->x;
    float newTargetOffset = 0;

    if (targetOffset > currentOffset)
        newTargetOffset = ceilf(currentOffset / pageWidth) * pageWidth;
    else
        newTargetOffset = floorf(currentOffset / pageWidth) * pageWidth;

    if (newTargetOffset < 0)
        newTargetOffset = 0;
    else if (newTargetOffset > scrollView.contentSize.width)
        newTargetOffset = scrollView.contentSize.width;

    targetContentOffset->x = currentOffset;
    [scrollView setContentOffset:CGPointMake(newTargetOffset, 0) animated:YES];
}

19voto

devdavid Points 952

Cette réponse est tardive, mais j'ai juste joué avec ce problème et a trouvé que la cause de la dérive est l' espacement des lignes. Si vous voulez le UICollectionView/FlowLayout à la page exacte des multiples de vos cellules de la largeur, vous devez définir:

UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)collectionView.collectionViewLayout;
flowLayout.minimumLineSpacing = 0.0;

Vous ne voudriez pas que l'espacement de la ligne entre en jeu à défilement horizontal, mais apparemment, il n'.

Dans mon cas, je faisais des expériences avec la pagination de gauche à droite, d'une cellule à un moment, avec aucun espace entre les cellules. À chaque tour de la page introduit un tout petit peu de dérive par rapport à la position désirée, et il semblait à s'accumuler de manière linéaire. ~10.0 pts par tour. J'ai réalisé 10.0 est la valeur par défaut de minimumLineSpacing à la disposition de flux. Quand je l'ai mis à 0.0, pas de dérive, quand je l'ai mis à la moitié de la limite de la largeur, de chaque page dérivé d'un supplément de la moitié de la limite.

La modification de la minimumInteritemSpacing avait aucun effet.

edit -- à partir de la documentation pour UICollectionViewFlowLayout:

@property (nonatomic) CGFloat minimumLineSpacing;

Discussion

...

Pour un défilement vertical de la grille, cette valeur représente le minimum l'espacement entre les lignes successives. Pour un défilement horizontal de la grille, cette valeur représente le minimum d'espacement entre les colonnes. Cet espacement est pas appliqué à l'espace entre la tête et le première ligne, soit entre la dernière ligne et le pied de page.

La valeur par défaut de cette propriété est de 10.0.

7voto

Jonathan Points 1160

Je sais que cette question est ancienne, mais pour quelqu'un qui arrive de tomber sur cette.

Tout ce que vous avez à faire pour corriger cela est de définir la MinimumInterItemSpacing de 0 et de diminuer le contenu de l'image.

6voto

raz0r Points 1195

Je crois que je comprends le problème. Je vais essayer de vous faire comprendre aussi.

Si vous regardez de près, vous verrez que ce problème ne se produit progressivement et pas seulement sur la première page de balayage.

enter image description here

Si je comprends bien, dans votre application, actuellement, tous les UICollectionView élément sont ceux arrondis boîtes qui nous voir, et vous avez quelques offset/marge entre tous qui est constant. C'est ce qui est à l'origine du problème.

Au lieu de cela, ce que vous devez faire, c'est de faire un UICollectionView élément qui est de 1/3ème de la largeur de l'ensemble de la vue, puis ajoutez-arrondi d'affichage de l'image à l'intérieur. Pour se référer à l'image, la couleur verte doit être votre UICollectionViewItem et pas le noir.

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