Comment limiter la réorganisation des lignes UITableView à une section

121

Je me cognais la tête sur celui-ci et Google ne révélait rien. J'ai finalement travaillé dessus et j'ai pensé l'écrire ici pour le bien de la personne suivante.

Vous avez un UITableViewavec plusieurs sections. Chaque section est homogène, mais le tableau est globalement hétérogène. Vous souhaiterez peut-être autoriser la réorganisation des lignes dans une section, mais pas entre les sections. Peut-être que vous ne voulez même qu'une section soit réorganisable (c'était mon cas). Si vous regardez, comme moi, le, UITableViewDataSourceDelegatevous ne trouverez pas de notification pour savoir quand il est sur le point de vous permettre de déplacer une ligne entre les sections. Vous en obtenez un quand il commence à déplacer une ligne (ce qui est bien) et un quand il est déjà déplacé et vous avez une chance de se synchroniser avec vos éléments internes. Inutile.

Alors, comment pouvez-vous éviter les commandes à nouveau entre les sections?

Je publierai ce que j'ai fait comme une réponse distincte, laissant à quelqu'un d'autre la possibilité de publier une réponse encore meilleure!

philsquared
la source
1
À quelle notification faites-vous référence lorsque vous dites "vous en recevez une quand elle commence à déplacer une ligne"? Je n'en vois pas mais j'espère discerner quand commence la réorganisation des cellules.
TomSwift

Réponses:

181

Cette implémentation empêchera de réorganiser en dehors de la section d'origine comme la réponse de Phil, mais elle accrochera également l'enregistrement à la première ou à la dernière ligne de la section, en fonction de l'endroit où le glissement est allé, au lieu de l'endroit où il a commencé.

- (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
la source
Existe-t-il un moyen d'empêcher le tableau de défiler automatiquement (tout en faisant glisser une cellule) en dehors de la section autorisée?
Palimondo
1
Dans Xamarin, la méthode wrapper est UIKit.UITableViewController.CustomizeMoveTarget, pour quiconque se demande.
bunkerdive
74

Assez simple, vraiment.

UITableViewDelegate a la méthode:


tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:

Ceci est appelé lorsque l'utilisateur survole un point de chute potentiel. Vous avez la possibilité de dire "non! Ne le laissez pas tomber là-bas! Déposez-le plutôt ici". Vous pouvez renvoyer un chemin d'index différent à celui proposé.

Tout ce que j'ai fait, c'est vérifier si les indices de section correspondent. Si c'est le cas, retournez le chemin proposé. sinon, retournez le chemin source. Cela empêche également les lignes d'autres sections de se déplacer même lorsque vous faites glisser - et la ligne déplacée reviendra à sa position d'origine lorsque vous essayez de la déplacer vers une autre section.


- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
    if( sourceIndexPath.section != proposedDestinationIndexPath.section )
    {
        return sourceIndexPath;
    }
    else
    {
        return proposedDestinationIndexPath;
    }
}
philsquared
la source
Faire exactement cela provoque des bogues d'affichage vraiment étranges sur ma configuration, et c'est très différent du propre exemple de code d'Apple sur la façon de procéder. FWIW! ne pas dire que c'est faux, juste que je me demande si c'est réellement plus compliqué que ça.
Billy Gray
Je peux faire glisser la ligne dans une autre section même si cette ligne n'est pas définie ici. mais il est visible quand à d'autres avec force.? toute idée
Sandy
27

Swifty version rapide de la réponse de Jason pour vous les paresseux:

Swift 3, 4 et 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 et 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
}
Alexandre de Norvège
la source
7

Vous pouvez empêcher le mouvement des lignes entre les sections en utilisant la méthode ci-dessous. Ne permettez simplement aucun mouvement entre les sections. Vous pouvez même contrôler le mouvement d'une ligne spécifique dans une section. par exemple, dernière ligne d'une section.

Voici l'exemple:

- (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
la source
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
}
Henri
la source
3

Than @Jason Harwig, le code ci-dessous fonctionne correctement.

- (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
la source
1

Pour ne pas changer de position entre les sections Swift3

override func collectionView(_ collectionView: UICollectionView, targetIndexPathForMoveFromItemAt originalIndexPath: IndexPath, toProposedIndexPath proposedIndexPath: IndexPath) -> IndexPath {
    if originalIndexPath.section != proposedIndexPath.section
    {
        return originalIndexPath
    }
    else
    {
        return proposedIndexPath
    }
}
ayalcine
la source