UICollectionView skuteczne przeciąganie i upuszczanie

Obecnie próbuję zaimplementować zachowanie zmiany kolejności UITableView przy użyciu UICollectionView.

Nazwijmy UITableView TV i UICollectionView CV (aby wyjaśnić następujące wyjaśnienie)

Próbuję odtworzyć przeciąganie i upuszczanie telewizora, ale nie używam trybu edycji, komórka jest gotowa do przeniesienia, gdy tylko zostanie wywołany gest długiego naciśnięcia. Działa sprawnie, używam metody move Z CV, wszystko jest dobrze.

Aktualizuję właściwość contentOffset CV, aby obsługiwać przewijanie, gdy użytkownik przeciąga komórkę. Gdy użytkownik przechodzi do konkretnego rect na górze i na dole, aktualizuję contentOffset i CV scroll. Problem polega na tym, że gdy użytkownik przestaje poruszać palcem, gest nie wysyła żadnej aktualizacji, która sprawia, że przewijanie zatrzymuje się i zaczyna od nowa, gdy tylko użytkownik przesunie palec.

To zachowanie na pewno nie jest naturalne, wolałbym continu przewijać aż do user release the CV as it is the case in the TV. Doświadczenie drag&drop TV jest niesamowite i naprawdę chcę odtworzyć to samo uczucie. Czy ktoś wie jak sobie radzą z przewijaniem w TV podczas zmiany kolejności ?

  • próbowałem za pomocą timera, aby uruchomić akcję przewijania wielokrotnie tak długo, jak pozycja gestów jest w odpowiednim miejscu, przewijanie było okropne i niezbyt produktywne (bardzo powolne i skokowe).
  • próbowałem też użyć GCD do odsłuchania pozycji gestu w innym wątku, ale wynik jest nawet najgorszy.
Skończyły mi się pomysły na ten temat, więc jeśli ktoś zna odpowiedź, wyjdę za niego!

Oto implementacja metody 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];}];
    }
}

Aby zrobić CV, używam tej metody:

- (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];
}
Author: Alexander Farber, 2012-10-03

5 answers

To może pomóc

Https://github.com/lxcid/LXReorderableCollectionViewFlowLayout

Jest to rozszerzenie UICollectionView, aby każdy z UICollectionViewCells mógł być przestawiony ręcznie przez Użytkownika za pomocą długiego dotyku (aka touch-and-hold). Użytkownik może przeciągnąć komórkę do dowolnej innej pozycji w kolekcji, a inne komórki automatycznie zmienią kolejność. Dzięki idź do lxcid za to.

 69
Author: dantes85,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-11 17:46:03

Tutaj {[7] } jest alternatywa:

Różnice między DraggableCollectionView i LXReorderableCollectionViewFlowLayout są następujące:

  • źródło danych jest zmieniane tylko raz. Oznacza to, że gdy użytkownik przeciąga element, komórki są ponownie pozycjonowane bez modyfikowania źródła danych.
  • jest napisany w taki sposób, że można go używać z niestandardowymi układami.
  • używa CADisplayLink do płynnego przewijania i animacja.
  • animacje są anulowane rzadziej podczas przeciągania. Wydaje się bardziej "naturalne".
  • protokół rozszerza {[1] } o metody podobne do UITableViewDataSource.
To praca w toku. Wiele sekcji jest teraz obsługiwanych.

Aby użyć go z niestandardowym układem, Zobacz DraggableCollectionViewFlowLayout. Większość logiki istnieje w LSCollectionViewLayoutHelper. Istnieje również przykład w CircleLayoutDemo pokazujący, jak sprawić, by przykład CircleLayout firmy Apple z WWDC 2012 działał.

 47
Author: Luke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-02 19:52:54

Od wersji iOS 9, UICollectionView obsługuje teraz zmianę kolejności.

Dla UICollectionViewController S, wystarczy zastąpić collectionView(collectionView: UICollectionView, moveItemAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath)

Dla UICollectionView s, oprócz implementacji powyższej metody UICollectionViewDataSource będziesz musiał samodzielnie obsługiwać gesty.

Oto kod z źródło:

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

Źródła: 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/

 30
Author: chrisamanse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-28 10:41:24

Jeśli chcesz poeksperymentować, to właśnie napisałem szybki tutorial, który możesz obejrzeć. Starałem się zbudować najbardziej podstawowe przypadki, aby łatwiej było śledzić to .

 3
Author: Mike M,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-02 19:42:22

Tutaj jest inne podejście:

Kluczowa różnica polega na tym, że to rozwiązanie nie wymaga "ducha" lub "atrapy" komórki do zapewnienia funkcji przeciągania i upuszczania. Po prostu używa samej komórki. Animacje są zgodne z UITableView. Działa poprzez dostosowanie prywatnego źródła danych układu widoku kolekcji podczas poruszania się. Gdy puścisz, poinformuje kontrolera, że możesz zatwierdzić zmianę do własnego źródła danych.

Uważam, że praca z w większości przypadków. Wciąż trwają prace, ale jeszcze jeden sposób, aby to osiągnąć. Większość powinna znaleźć to dość łatwe do włączenia do własnych niestandardowych UICollectionViewLayouts.

 2
Author: Henry T Kirk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-02 15:49:36