Pergunta

Atualmente, estou tentando implementar o UITableView reordenação de comportamento usando UICollectionView.

Vamos chamar UItableView TV e um UICollectionView CV (para esclarecer a seguinte explicação)

Eu estou basicamente tentando reproduzir o arrastar&cair da TV, mas eu não estou usando o modo de edição, a célula está pronto para ser removido assim que o longa pressione gesto é acionado.Ele funciona perfeitamente, eu estou usando o método mover o CV, está tudo bem.

Eu atualizar o contentOffset propriedade do CV para lidar com a rolagem quando o usuário está arrastando uma célula.Quando um usuário vai a uma determinada rect no topo e no fundo, eu atualizar o contentOffset e o CV de deslocamento.O problema é quando o usuário parar de mover o dedo, o gesto não enviar qualquer atualização que faz com que o deslocamento parar e iniciar novamente assim que o usuário move seu dedo.

Este comportamento é, definitivamente, não é natural, eu prefiro manter a rolagem até que o usuário solte o CV, como é o caso na TV.O PLANO de arrastar&soltar a experiência é incrível e eu realmente queira reproduzir o mesmo sentimento.Alguém sabe como eles gerenciam a rolar na TV durante a reordenação ?

  • Eu tentei usar um timer para desencadear uma ação de rolagem repetidamente enquanto o gesto de posição é o lugar certo, o deslocamento era horrível e não muito produtivo (muito lento e nervoso).
  • Eu também tentei usar GCD para ouvir o gesto posição em outra thread, mas o resultado é ainda pior.

Eu corri para fora de idéia sobre o que, então, se alguém tem a resposta que eu iria casar com ele!

Aqui é a implementação do longPress método:

- (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];}];
    }
}

Para fazer o CV rolar, eu estou usando esse método:

- (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];
}
Foi útil?

Solução

Isso pode ajudar

https://github.com/lxcid/LXReorderableCollectionViewFlowLayout

Isto é, se estende a UICollectionView para permitir que cada uma das UICollectionViewCells para ser reorganizados manualmente pelo usuário, com um toque longo (aka tocar sem soltar).O usuário pode arrastar a Célula para qualquer outra posição na coleção e as outras células irá reordenar automaticamente.Agradecimentos lxcid para este.

Outras dicas

Aqui é uma alternativa:

As diferenças entre DraggableCollectionView e LXReorderableCollectionViewFlowLayout são:

  • A fonte de dados é alterada apenas uma vez.Isso significa que, enquanto o usuário está arrastando um item as células são re-posicionado, sem modificar a fonte de dados.
  • É escrito de tal forma que torna possível o uso com layouts personalizados.
  • Ele usa um CADisplayLink para a rolagem suave e animação.
  • As animações são canceladas com menos frequência enquanto arrasta.Ele se sente mais "natural".
  • O protocolo estende-se UICollectionViewDataSource com métodos semelhantes UITableViewDataSource.

É um trabalho em progresso.Várias seções são agora suportados.

Para usá-lo com um layout personalizado ver DraggableCollectionViewFlowLayout.A maior parte da lógica existe em LSCollectionViewLayoutHelper.Há também um exemplo em CircleLayoutDemo mostrando como fazer da Apple CircleLayout exemplo do WWDC 2012.

Como de iOS 9, UICollectionView agora suporta reordenação.

Para UICollectionViewControllers, basta substituir collectionView(collectionView: UICollectionView, moveItemAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath)

Para UICollectionViews, você vai ter que lidar com os gestos de si mesmo, além de implementar o UICollectionViewDataSource método acima.

Aqui está o código da fonte:

private var longPressGesture: UILongPressGestureRecognizer!

override func viewDidLoad() {
    super.viewDidLoad()

    longPressGesture = UILongPressGestureRecognizer(target: self, action: "handleLongGesture:")
    self.collectionView.addGestureRecognizer(longPressGesture)
}

func handleLongGesture(gesture: UILongPressGestureRecognizer) {

    switch(gesture.state) {

    case UIGestureRecognizerState.Began:
        guard let selectedIndexPath = self.collectionView.indexPathForItemAtPoint(gesture.locationInView(self.collectionView)) else {
            break
        }
        collectionView.beginInteractiveMovementForItemAtIndexPath(selectedIndexPath)
    case UIGestureRecognizerState.Changed:
        collectionView.updateInteractiveMovementTargetPosition(gesture.locationInView(gesture.view!))
    case UIGestureRecognizerState.Ended:
        collectionView.endInteractiveMovement()
    default:
        collectionView.cancelInteractiveMovement()
    }
}

Fontes:https://developer.apple.com/library/ios/documentation/UIKit/Reference/UICollectionView_class/#//apple_ref/doc/uid/TP40012177-CH1-SW67

http://nshint.io/blog/2015/07/16/uicollectionviews-now-have-easy-reordering/

Se você deseja experimentar a rolar para fora o seu próprio, eu só escrevi um rápido tutorial baseado você pode olhar.Eu tentei construir o mais básico dos casos, de forma a ser mais fácil de seguir este.

Aqui é uma outra abordagem:

Diferença fundamental é que esta solução não requer um "fantasma" ou "fictício" célula para fornecer a funcionalidade de arrastar e soltar.Ele simplesmente usa a própria célula.As animações estão em linha com a UITableView.Ele funciona ajustando o modo de exibição de coleção layout privada fonte de dados enquanto se move ao redor.Uma vez que você deixar de ir, ele vai dizer o controlador que você pode se comprometer a mudar a sua própria fonte de dados.

Eu acredito que é um pouco mais simples para trabalhar para a maioria dos casos de uso.Ainda um trabalho em progresso, mas outra maneira de fazer isso.A maioria deve achar isso muito fácil de incorporar em suas próprias UICollectionViewLayouts.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top