So beschränken Sie die Neuordnung von UITableView-Zeilen auf einen Abschnitt


121

Ich habe meinen Kopf über diesen geschlagen, und Google hat nichts aufgetaucht. Ich habe es schließlich ausgearbeitet und dachte, ich würde es hier für die nächste Person aufschreiben.

Sie haben eine UITableViewmit mehreren Abschnitten. Jeder Abschnitt ist homogen, aber die Tabelle insgesamt ist heterogen. So möchten Sie vielleicht Nachbestellung von Zeilen innerhalb eines Abschnitts ermöglichen, aber nicht über Abschnitte. Vielleicht möchten Sie nur, dass ein Abschnitt überhaupt nachbestellbar ist (das war mein Fall). Wenn Sie wie ich auf die schauen, werden UITableViewDataSourceDelegateSie keine Benachrichtigung finden, wann Sie eine Zeile zwischen Abschnitten verschieben können. Sie erhalten eine, wenn eine Zeile verschoben wird (was in Ordnung ist), und eine, wenn sie bereits verschoben wurde, und Sie haben die Möglichkeit, sich mit Ihren internen Daten zu synchronisieren. Nicht hilfreich.

Wie können Sie Nachbestellungen zwischen Abschnitten verhindern?

Ich werde das, was ich getan habe, als separate Antwort veröffentlichen und es jemand anderem offen lassen, eine noch bessere Antwort zu veröffentlichen!


1
Auf welche Benachrichtigung beziehen Sie sich, wenn Sie sagen "Sie erhalten eine, wenn eine Zeile verschoben wird"? Ich sehe keinen, hoffe aber zu erkennen, wann die Neuordnung der Zellen beginnt.
TomSwift

Antworten:


181

Diese Implementierung verhindert eine Neuordnung außerhalb des ursprünglichen Abschnitts wie Phils Antwort, fängt jedoch auch den Datensatz in der ersten oder letzten Zeile des Abschnitts ein, je nachdem, wohin das Ziehen gegangen ist, anstatt wo es begonnen hat.

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

Gibt es eine Möglichkeit, zu verhindern, dass die Tabelle automatisch (beim Ziehen einer Zelle) außerhalb des zulässigen Abschnitts gescrollt wird?
Palimondo

1
In Xamarin ist die Wrapper-Methode UIKit.UITableViewController.CustomizeMoveTargetfür alle, die sich fragen.
Bunkerdive

74

Wirklich einfach genug.

Das UITableViewDelegate hat die Methode:


tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:

Dies wird aufgerufen, während der Benutzer über einem potenziellen Ablagepunkt schwebt. Sie haben die Möglichkeit zu sagen: "Nein! Lassen Sie es nicht dort fallen! Lassen Sie es stattdessen hier fallen." Sie können einen anderen Indexpfad als den vorgeschlagenen zurückgeben.

Ich habe nur überprüft, ob die Abschnittsindizes übereinstimmen. Wenn sie dann großartig abschneiden, geben Sie den vorgeschlagenen Pfad zurück. Wenn nicht, geben Sie den Quellpfad zurück. Dies verhindert auch, dass sich die Zeilen in anderen Abschnitten beim Ziehen sogar aus dem Weg räumen - und die gezogene Zeile wird an ihre ursprüngliche Position zurückschnappen, wenn Sie versuchen, sie in einen anderen Abschnitt zu verschieben.


- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
    if( sourceIndexPath.section != proposedDestinationIndexPath.section )
    {
        return sourceIndexPath;
    }
    else
    {
        return proposedDestinationIndexPath;
    }
}

Wenn Sie genau dies tun, treten in meinem Setup einige wirklich seltsame Anzeigefehler auf, die sich deutlich von Apples eigenem Beispielcode unterscheiden. FWIW! Ich sage nicht, dass es falsch ist, nur dass ich mich frage, ob es tatsächlich komplizierter ist.
Billy Gray

Ich kann eine Zeile in einen anderen Abschnitt ziehen, auch wenn diese Zeile dort nicht festgelegt wird. aber es ist sichtbar, wann zu anderen kraftvoll.? irgendeine Idee
Sandy

27

Schnelle schnelle Version von Jasons Antwort für Sie faulen Leute:

Swift 3, 4 & 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 & 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
}

7

Sie können die Verschiebung von Zeilen zwischen Abschnitten mithilfe der folgenden Methode verhindern. Lassen Sie einfach keine Bewegung zwischen den Abschnitten zu. Sie können sogar die Bewegung einer bestimmten Zeile innerhalb eines Abschnitts steuern. zB letzte Zeile in einem Abschnitt.

Hier ist das Beispiel:

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

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
}

3

Als @Jason Harwig funktioniert der folgende Code korrekt.

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

1

Um die Position zwischen den Abschnitten Swift3 nicht zu ändern

override func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath {
    if originalIndexPath.section != proposedIndexPath.section
    {
        return originalIndexPath
    }
    else
    {
        return proposedIndexPath
    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.