Jak ograniczyć zmianę kolejności wierszy UITableView do sekcji

121

Uderzałem się w głowę nad tym, a Google nic nie pokazało. W końcu to opracowałem i pomyślałem, że napiszę to tutaj ze względu na następną osobę.

Masz UITableViewz wieloma sekcjami. Każda sekcja jest jednorodna, ale ogólnie tabela jest niejednorodna. Możesz więc chcieć zezwolić na zmianę kolejności wierszy w sekcji, ale nie w sekcjach. Może nawet chcesz, aby w ogóle można było ponownie zamówić tylko jedną sekcję (tak było w moim przypadku). Jeśli patrzysz, tak jak ja, na UITableViewDataSourceDelegatenie znajdziesz powiadomienia, kiedy ma zamiar przenieść wiersz między sekcjami. Dostajesz jeden, gdy zaczyna przesuwać wiersz (co jest w porządku), a drugi, gdy został już przeniesiony, i masz szansę zsynchronizować się z wewnętrznymi elementami. Niepomocne.

Jak więc możesz zapobiec ponownemu zamawianiu między sekcjami?

Opublikuję to, co zrobiłem, jako osobną odpowiedź, pozostawiając otwartą dla kogoś innego, aby opublikował jeszcze lepszą odpowiedź!

philsquared
źródło
1
Do którego powiadomienia odnosisz się, gdy mówisz „Otrzymujesz powiadomienie, gdy zacznie przesuwać wiersz”? Nie widzę żadnego, ale mam nadzieję, że rozpoznam, kiedy zacznie się zmiana kolejności komórek.
TomSwift

Odpowiedzi:

181

Ta implementacja zapobiegnie ponownej kolejności poza oryginalną sekcją, taką jak odpowiedź Phila, ale także przyciągnie rekord do pierwszego lub ostatniego wiersza sekcji, w zależności od tego, gdzie poszło przeciągnięcie, zamiast od miejsca, w którym się zaczęło.

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
  if (sourceIndexPath.section != proposedDestinationIndexPath.section) {
    NSInteger row = 0;
    if (sourceIndexPath.section < proposedDestinationIndexPath.section) {
      row = [tableView numberOfRowsInSection:sourceIndexPath.section] - 1;
    }
    return [NSIndexPath indexPathForRow:row inSection:sourceIndexPath.section];     
  }

  return proposedDestinationIndexPath;
}
Jason Harwig
źródło
Czy istnieje sposób, aby zapobiec automatycznemu przewijaniu tabeli (podczas przeciągania komórki) poza dozwoloną sekcję?
Palimondo
1
W oprogramowaniu Xamarin metoda otoki jest UIKit.UITableViewController.CustomizeMoveTargetdla każdego, kto się zastanawia.
nurkowanie z bunkrem
74

Naprawdę dość proste.

UITableViewDelegate ma metodę:


tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:

Jest to wywoływane, gdy użytkownik znajduje się nad potencjalnym punktem zrzutu. Masz szansę powiedzieć: „nie! Nie upuszczaj tego tam! Rzuć to tutaj”. Możesz zwrócić inną ścieżkę indeksu do proponowanej.

Wszystko, co zrobiłem, to sprawdzenie, czy wskaźniki sekcji są zgodne. Jeśli im się to uda, wróć proponowaną ścieżką. jeśli nie, zwróć ścieżkę źródłową. To również ładnie zapobiega przesuwaniu się wierszy w innych sekcjach podczas przeciągania - a przeciągnięty wiersz wróci do pierwotnej pozycji, w której spróbujesz przenieść go do innej sekcji.


- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
    if( sourceIndexPath.section != proposedDestinationIndexPath.section )
    {
        return sourceIndexPath;
    }
    else
    {
        return proposedDestinationIndexPath;
    }
}
philsquared
źródło
Zrobienie tego dokładnie powoduje, że w mojej konfiguracji pojawiają się naprawdę dziwne błędy wyświetlania i wyraźnie różni się od własnego przykładowego kodu firmy Apple, jak to zrobić. FWIW! nie mówię, że to źle, po prostu zastanawiam się, czy to rzeczywiście jest bardziej skomplikowane niż to.
Billy Grey
Mogę przeciągnąć wiersz do innej sekcji, nawet jeśli ten wiersz nie jest tam ustawiony. ale widać, kiedy do innych siłą.? jakikolwiek pomysł
Sandy
28

Szybka, szybka wersja odpowiedzi Jasona dla leniwych ludzi:

Swift 3, 4 i 5

override func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath {
    if sourceIndexPath.section != proposedDestinationIndexPath.section {
        var row = 0
        if sourceIndexPath.section < proposedDestinationIndexPath.section {
            row = self.tableView(tableView, numberOfRowsInSection: sourceIndexPath.section) - 1
        }
        return IndexPath(row: row, section: sourceIndexPath.section)
    }
    return proposedDestinationIndexPath
}

Swift 1 i 2

override func tableView(tableView: UITableView, targetIndexPathForMoveFromRowAtIndexPath sourceIndexPath: NSIndexPath, toProposedIndexPath proposedDestinationIndexPath: NSIndexPath) -> NSIndexPath {
    if sourceIndexPath.section != proposedDestinationIndexPath.section {
        var row = 0
        if sourceIndexPath.section < proposedDestinationIndexPath.section {
            row = self.tableView(tableView, numberOfRowsInSection: sourceIndexPath.section) - 1
        }
        return NSIndexPath(forRow: row, inSection: sourceIndexPath.section)
    }
    return proposedDestinationIndexPath
}
Alexander of Norway
źródło
Skopiowałem, wkleiłem. Prowadziłem to, uwielbiałem to. Wróciłem. Dzięki, to poczucie winy, ale akceptuję! ;)
Joshua Hart
7

Możesz zapobiec przesuwaniu się rzędów między sekcjami, używając poniższej metody. Po prostu nie pozwól na jakikolwiek ruch pomiędzy sekcjami. Możesz nawet kontrolować ruch określonego wiersza w sekcji. np. ostatni wiersz w sekcji.

Oto przykład:

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {

    // Do not allow any movement between section
    if ( sourceIndexPath.section != proposedDestinationIndexPath.section) {
        return sourceIndexPath;
    }
    // You can even control the movement of specific row within a section. e.g last row in a     Section

    // Check if we have selected the last row in section
    if (sourceIndexPath.row < sourceIndexPath.length) {
        return proposedDestinationIndexPath;
    } 
    else {
        return sourceIndexPath;
    }
}
ASM11
źródło
7

Swift 3:

override func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath {
    if sourceIndexPath.section != proposedDestinationIndexPath.section {
        var row = 0
        if sourceIndexPath.section < proposedDestinationIndexPath.section {
            row = self.tableView(tableView, numberOfRowsInSection: sourceIndexPath.section) - 1
        }
        return IndexPath(row: row, section: sourceIndexPath.section)
    }
    return proposedDestinationIndexPath
}
Henz
źródło
3

Niż @Jason Harwig, poniższy kod działa poprawnie.

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
    {
      if (sourceIndexPath.section != proposedDestinationIndexPath.section) {
        NSInteger row = 0;
        if (sourceIndexPath.section < proposedDestinationIndexPath.section) {
          row = [tableView numberOfRowsInSection:sourceIndexPath.section] - 1;
        }
        return [NSIndexPath indexPathForRow:row inSection:sourceIndexPath.section];     
      }

      return proposedDestinationIndexPath;
    }
Bkillnest
źródło
1

Brak zmiany pozycji między sekcjami Swift3

override func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath {
    if originalIndexPath.section != proposedIndexPath.section
    {
        return originalIndexPath
    }
    else
    {
        return proposedIndexPath
    }
}
ayalcin
źródło