Come limitare il riordino delle righe UITableView a una sezione


121

Stavo sbattendo la testa su questo e Google non ha trovato nulla. Alla fine ho capito e ho pensato di scriverlo qui per il bene della persona successiva.

Hai un UITableViewcon più sezioni. Ogni sezione è omogenea, ma la tabella nel complesso è eterogenea. Quindi potresti voler consentire il riordino delle righe all'interno di una sezione, ma non tra le sezioni. Forse vuoi anche solo che una sezione sia riordinabile (questo era il mio caso). Se stai guardando, come me, al UITableViewDataSourceDelegatenon troverai una notifica per quando sta per farti spostare una riga tra le sezioni. Ne ottieni uno quando inizia a spostare una riga (che va bene) e uno quando è già spostato e hai la possibilità di sincronizzarti con le tue cose interne. Non d'aiuto.

Quindi come puoi impedire i riordini tra le sezioni?

Pubblicherò ciò che ho fatto come risposta separata, lasciando che qualcun altro possa pubblicare una risposta ancora migliore!


1
A quale notifica ti riferisci quando dici "ne ricevi una quando inizia a spostare una riga"? Non ne vedo uno, ma spero di capire quando inizierà il riordino delle celle.
TomSwift

Risposte:


181

Questa implementazione impedirà il riordino al di fuori della sezione originale come la risposta di Phil, ma aggancerà anche il record alla prima o all'ultima riga della sezione, a seconda di dove è andato il trascinamento, invece di dove è iniziato.

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

C'è un modo per impedire lo scorrimento automatico della tabella (durante il trascinamento di una cella) al di fuori della sezione consentita?
Palimondo

1
In Xamarin, il metodo wrapper è UIKit.UITableViewController.CustomizeMoveTarget, per chiunque se lo chieda.
bunkerdive

74

Abbastanza semplice, davvero.

UITableViewDelegate ha il metodo:


tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:

Questo viene chiamato mentre l'utente passa con il mouse su un potenziale punto di rilascio. Hai la possibilità di dire "no! Non lasciarlo cadere lì! Lascialo invece cadere qui". È possibile restituire un percorso di indice diverso da quello proposto.

Tutto quello che ho fatto è stato controllare se gli indici di sezione corrispondono. Se lo fanno alla grande, restituisci il percorso proposto. in caso contrario, restituisce il percorso di origine. Questo impedisce anche che le righe in altre sezioni si spostino mentre trascini e la riga trascinata tornerà alla sua posizione originale quando provi a spostarla in un'altra sezione.


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

Fare esattamente questo fa sì che si verifichino alcuni bug di visualizzazione davvero strani sulla mia configurazione, ed è notevolmente diverso dal codice di esempio di Apple su come farlo. FWIW! non dico che sia sbagliato, solo che mi chiedo se in realtà sia più complicato di così.
Billy Grey

Posso trascinare la riga in un'altra sezione anche quella riga non viene impostata lì. ma è visibile quando ad altri con forza.? qualsiasi idea
Sandy

27

Versione rapida e rapida della risposta di Jason per voi pigri:

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

È possibile impedire il movimento delle righe tra le sezioni utilizzando il metodo seguente. Basta non consentire alcun movimento tra le sezioni. Puoi persino controllare il movimento di una riga specifica all'interno di una sezione. ad esempio l'ultima riga in una sezione.

Ecco l'esempio:

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

Rispetto a @Jason Harwig, il codice seguente funziona correttamente.

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

Per non cambiare posizione tra le sezioni Swift3

override func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath {
    if originalIndexPath.section != proposedIndexPath.section
    {
        return originalIndexPath
    }
    else
    {
        return proposedIndexPath
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.