uiscrollview drag-and-drop scroll order uicollectionview

uiscrollview - UICollectionView efectiva arrastrar y soltar



drag-and-drop order (5)

Esto podría ayudar

https://github.com/lxcid/LXReorderableCollectionViewFlowLayout

Esto extiende el UICollectionView para permitir que cada una de las UICollectionViewCells sea ​​reorganizada manualmente por el usuario con un toque largo (también conocido como tocar y mantener). El usuario puede arrastrar la Celda a cualquier otra posición en la colección y las otras celdas se reordenarán automáticamente. Gracias a lxcid por esto.

Actualmente estoy intentando implementar el comportamiento de reordenamiento UITableView usando UICollectionView.

Llamemos a un televisor UItableView y un CV de UICollectionView (para aclarar la siguiente explicación)

Básicamente estoy tratando de reproducir arrastrando y soltando el televisor, pero no estoy usando el modo de edición, la celda está lista para moverse tan pronto como se active el gesto de presión prolongada. Funciona perfectamente, estoy usando el método de movimiento del CV, todo está bien.

Actualizo la propiedad contentOffset del CV para manejar el desplazamiento cuando el usuario está arrastrando una celda. Cuando un usuario va a un rect concreto en la parte superior e inferior, actualizo contentOffset y CV scroll. El problema es cuando el usuario deja de mover su dedo, el gesto no envía ninguna actualización que hace que el desplazamiento se detenga y vuelva a comenzar tan pronto como el usuario mueva su dedo.

Este comportamiento definitivamente no es natural, prefiero continuar desplazándome hasta que el usuario libere el CV como es el caso en el televisor. La experiencia de arrastrar y soltar de TV es increíble y realmente quiero reproducir la misma sensación. ¿Alguien sabe cómo manejan el rollo en la TV durante el reordenamiento?

  • Intenté usar un temporizador para disparar una acción de desplazamiento repetidamente siempre que la posición del gesto esté en el lugar correcto, el desplazamiento fue horrible y no muy productivo (muy lento y nervioso).
  • También traté de usar GCD para escuchar la posición del gesto en otro hilo, pero el resultado es aún peor.

Me quedé sin idea sobre eso, así que si alguien tiene la respuesta, ¡me casaría con él!

Aquí está la implementación del método longPress:

- (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 hacer que CV se desplace, estoy usando ese 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]; }


A partir de iOS 9, UICollectionView ahora admite reordenamiento.

Para UICollectionViewController , simplemente anule collectionView(collectionView: UICollectionView, moveItemAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath)

Para UICollectionView s, tendrá que manejar los gestos usted mismo además de implementar el método UICollectionViewDataSource anterior.

Aquí está el código de la fuente:

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() } }

Fuentes: 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/


Si desea experimentar su propia implementación, acabo de escribir un tutorial basado en Swift que puede consultar. Traté de construir el más básico de los casos para que sea más fácil seguir esto .


Aquí hay otro enfoque:

La diferencia clave es que esta solución no requiere una celda "fantasma" o "falsa" para proporcionar la funcionalidad de arrastrar y soltar. Simplemente usa la celda misma. Las animaciones están en línea con UITableView. Funciona al ajustar el origen de datos privado del diseño de vista de colección mientras se mueve. Una vez que lo dejes ir, le dirá a tu controlador que puedes comprometer el cambio a tu propia fuente de datos.

Creo que es un poco más sencillo trabajar con la mayoría de los casos de uso. Todavía es un trabajo en progreso, pero es otra forma de lograr esto. La mayoría debería encontrar esto bastante fácil de incorporar a sus propios UICollectionViewLayouts personalizados.


Aquí hay una alternativa:

Las diferencias entre DraggableCollectionView y LXReorderableCollectionViewFlowLayout son:

  • La fuente de datos solo se cambia una vez. Esto significa que mientras el usuario está arrastrando un elemento, las celdas se vuelven a colocar sin modificar la fuente de datos.
  • Está escrito de tal manera que hace posible su uso con diseños personalizados.
  • Utiliza un CADisplayLink para desplazamiento y animación sin problemas.
  • Las animaciones se cancelan con menos frecuencia mientras se arrastra. Se siente más "natural".
  • El protocolo extiende UICollectionViewDataSource con métodos similares a UITableViewDataSource .

Es un trabajo en progreso. Múltiples secciones ahora son compatibles.

Para usarlo con un diseño personalizado, consulte DraggableCollectionViewFlowLayout . La mayor parte de la lógica existe en LSCollectionViewLayoutHelper . También hay un ejemplo en CircleLayoutDemo que muestra cómo hacer que el ejemplo de CircleLayout de Apple de la WWDC 2012 funcione.