60 votes

UICollectionView efficace glisser-déposer

Je suis en train d'essayer de mettre en œuvre la UITableView réorganisation de comportement à l'aide de UICollectionView.

Appelons un UItableView TÉLÉVISION et un UICollectionView CV (pour clarifier l'explication suivante)

Je suis en fait, d'essayer de reproduire le drag&drop de la TV, mais je ne suis pas en utilisant le mode d'édition, la cellule est prête à être déplacée dès que la presse à long geste est déclenchée. Il fonctionne parfaitement, je suis en utilisant la méthode de déplacement de la CV, tout va bien.

- Je mettre à jour le contentOffset propriété de la CV pour gérer le défilement lorsque l'utilisateur fait glisser une cellule. Lorsqu'un utilisateur accède à un particulier rect en haut et en bas, je l'ai mise à jour de la contentOffset et le CV de défilement. Le problème, c'est lorsque l'utilisateur arrêter le déplacement du doigt, le geste ne pas envoyer de mise à jour qui rend le défilement s'arrêter et recommencer dès que l'utilisateur déplace son doigt.

Ce comportement est certainement pas naturel, je préfère continuer à faire défiler jusqu'à l'utilisateur de libérer le CV comme c'est le cas à la TÉLÉVISION. La TÉLÉVISION drag&drop expérience est géniale et j'ai vraiment envie de reproduire le même sentiment. Personne ne sait comment ils gèrent les faire défiler à la TÉLÉVISION lors de la réorganisation ?

  • J'ai essayé d'utiliser une minuterie pour déclencher le défilement de l'action à plusieurs reprises, tant que le geste, il est placé au bon endroit, le défilement a été terrible et pas très productif (très lente et irrégulière).
  • J'ai aussi essayé d'utiliser le PGCD pour écouter la geste de la poste dans un autre fil, mais le résultat est encore pire.

J'ai manqué de l'idée à ce sujet, donc si quelqu'un a la réponse je l'épouser!

Ici est la mise en œuvre de la appuyez de manière prolongée sur la méthode:

- (void)handleLongPress:(UILongPressGestureRecognizer *)sender
{
    ReorganizableCVCLayout *layout = (ReorganizableCVCLayout *)self.collectionView.collectionViewLayout;
    CGPoint gesturePosition = [sender locationInView:self.collectionView];
    NSIndexPath *selectedIndexPath = [self.collectionView indexPathForItemAtPoint:gesturePosition];

    if (sender.state == UIGestureRecognizerStateBegan)
    {
        layout.selectedItem = selectedIndexPath;
        layout.gesturePoint = gesturePosition; // Setting gesturePoint invalidate layout
    }
    else if (sender.state == UIGestureRecognizerStateChanged)
    {
        layout.gesturePoint = gesturePosition; // Setting gesturePoint invalidate layout
        [self swapCellAtPoint:gesturePosition];
        [self manageScrollWithReferencePoint:gesturePosition];
    }
    else
    {
        [self.collectionView performBatchUpdates:^
        {
            layout.selectedItem = nil;
            layout.gesturePoint = CGPointZero; // Setting gesturePoint invalidate layout
        } completion:^(BOOL completion){[self.collectionView reloadData];}];
    }
}

Pour rendre le CV de défilement, je suis en utilisant cette méthode:

- (void)manageScrollWithReferencePoint:(CGPoint)gesturePoint
{
    ReorganizableCVCLayout *layout = (ReorganizableCVCLayout *)self.collectionView.collectionViewLayout;
    CGFloat topScrollLimit = self.collectionView.contentOffset.y+layout.itemSize.height/2+SCROLL_BORDER;
    CGFloat bottomScrollLimit = self.collectionView.contentOffset.y+self.collectionView.frame.size.height-layout.itemSize.height/2-SCROLL_BORDER;
    CGPoint contentOffset = self.collectionView.contentOffset;

    if (gesturePoint.y < topScrollLimit && gesturePoint.y - layout.itemSize.height/2 - SCROLL_BORDER > 0)
        contentOffset.y -= SCROLL_STEP;
    else if (gesturePoint.y > bottomScrollLimit &&
             gesturePoint.y + layout.itemSize.height/2 + SCROLL_BORDER < self.collectionView.contentSize.height)
        contentOffset.y += SCROLL_STEP;

    [self.collectionView setContentOffset:contentOffset];
}

70voto

dantes85 Points 496

Cela peut vous aider

https://github.com/lxcid/LXReorderableCollectionViewFlowLayout

C'est s'étend de l' UICollectionView afin de permettre à chacun de l' UICollectionViewCells à être modifié manuellement par l'utilisateur avec un appui long (aka touch-and-hold). L'utilisateur peut faire glisser la Cellule à toute autre position dans la collection et les autres cellules de réorganiser automatiquement. Merci à lxcid pour cela.

47voto

Luke Points 4282

Voici une alternative:

https://github.com/lukescott/DraggableCollectionView

Les différences entre DraggableCollectionView et LXReorderableCollectionViewFlowLayout sont:

  • La source de données n'est changé une fois. Cela signifie que lorsque l'utilisateur est en faisant glisser un élément, les cellules sont re-positionné sans modifier la source de données.
  • C'est écrit de telle manière qu'il est possible de l'utiliser avec des mises en page personnalisées.
  • Il utilise un CADisplayLink pour un défilement fluide et de l'animation.
  • Des Animations sont annulés moins fréquemment, tout en le faisant glisser. Il se sent plus "naturel".
  • Le protocole s'étend UICollectionViewDataSource avec des méthodes similaires à UITableViewDataSource.

C'est un travail en cours. Plusieurs sections sont maintenant pris en charge.

Pour l'utiliser avec une mise en page personnalisée voir DraggableCollectionViewFlowLayout. La plupart de la logique existe en LSCollectionViewLayoutHelper. Il est aussi un exemple dans CircleLayoutDemo montrant comment faire d'Apple CircleLayout exemple de la WWDC 2012.

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