UICollectionView эффективное перетаскивание
в настоящее время я пытаюсь реализовать поведение переупорядочения UITableView с помощью UICollectionView.
давайте назовем a UItableView ТВ и UICollectionView CV (чтобы прояснить следующее объяснение)
Я в основном пытаюсь воспроизвести перетаскивание телевизора, но я не использую режим редактирования, ячейка готова к перемещению, как только запускается жест длительного нажатия. Он работает превосходно, я использую метод Move резюме, все отлично.
Я обновляю свойство contentOffset CV для обработки прокрутки, когда пользователь перетаскивает ячейку. Когда пользователь переходит к определенной прямой линии вверху и внизу, я обновляю contentOffset и прокрутку CV. Проблема в том, что когда пользователь перестает двигать пальцем, жест не отправляет никакого обновления, которое заставляет прокрутку останавливаться и начинать снова, как только пользователь перемещает палец.
такое поведение не естественно, я бы предпочел продолжайте прокручивать, пока пользователь не выпустит CV, как это происходит в телевизоре. Телевизор drag&drop опыт является удивительным, и я действительно хочу, чтобы воспроизвести то же самое чувство. Кто-нибудь знает, как они управляют прокруткой в телевизоре во время переупорядочения ?
- я попытался использовать таймер, чтобы вызвать действие прокрутки несколько раз, пока положение жеста находится в нужном месте, прокрутка была ужасной и не очень продуктивной (очень медленной и прыгучей).
- я также попытался использовать GCD для прослушивания положение жеста в другом потоке, но результат еще хуже.
у меня закончилась идея об этом, поэтому, если у кого-то есть ответ, я выйду за него замуж!
вот реализация метода 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];}];
}
}
чтобы сделать прокрутку CV, я использую этот метод:
- (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];
}
5 ответов:
Это может помочь
https://github.com/lxcid/LXReorderableCollectionViewFlowLayout
Это расширяет
UICollectionViewразрешить всеUICollectionViewCellsдля перестановки вручную пользователем с помощью длинного касания (он же touch-and-hold). Пользователь может перетащить ячейку в любую другую позицию в коллекции, и другие ячейки будут автоматически переупорядочены. Спасибо перейти к lxcid для этого.
здесь альтернатива:
различия между DraggableCollectionView и LXReorderableCollectionViewFlowLayout являются:
- источник данных изменяется только один раз. Это означает, что в то время как пользователь перетаскивает элемент, ячейки перемещаются без изменения источника данных.
- он написан таким образом, что позволяет использовать с пользовательскими макетами.
- использует
CADisplayLinkдля плавная прокрутка и анимация.- анимация отменяется реже при перетаскивании. Он чувствует себя более "естественным".
- протокол расширяет
UICollectionViewDataSourceс методами, подобнымиUITableViewDataSource.это работа в прогрессе. Теперь поддерживаются несколько разделов.
чтобы использовать его с пользовательским макетом см.
DraggableCollectionViewFlowLayout. Большая часть логики существует вLSCollectionViewLayoutHelper. Существует также пример в CircleLayoutDemo, показывающий, как сделать пример CircleLayout от Apple из работы WWDC 2012.
начиная с iOS 9,
UICollectionViewтеперь поддерживает порядка.на
UICollectionViewControllers, просто переопределитьcollectionView(collectionView: UICollectionView, moveItemAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath)на
UICollectionViews, вам придется обрабатывать жесты самостоятельно в дополнение к реализацииUICollectionViewDataSourceвыше способ.вот код от источник:
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() } }http://nshint.io/blog/2015/07/16/uicollectionviews-now-have-easy-reordering/
Если вы хотите поэкспериментировать с развертыванием своего собственного, я просто написал учебник на основе Swift, который вы можете посмотреть. Я попытался построить самые основные случаи, чтобы было легче следовать этой.
здесь другой подход:
ключевое различие заключается в том, что это решение не требует "призрака" или "фиктивной" ячейки для обеспечения функции перетаскивания. Он просто использует саму клетку. Анимация соответствует UITableView. Он работает путем настройки частного источника данных макета представления коллекции при перемещении. Как только вы отпустите, он сообщит вашему контроллеру, что вы можете зафиксировать изменение в своем собственном источнике данных.
Я считаю, что это немного проще работать в большинстве случаев. Все еще продолжается работа, но еще один способ достичь этого. Большинство должно найти это довольно легко включить в свои собственные пользовательские UICollectionViewLayouts.
Comments