Cómo limitar el reordenamiento de filas de UITableView a una sección

121

Me estaba golpeando la cabeza con este, y Google no encontró nada. Finalmente lo resolví y pensé en escribirlo aquí por el bien de la próxima persona.

Tienes una UITableViewcon varias secciones. Cada sección es homogénea, pero la tabla en general es heterogénea. Por lo tanto, es posible que desee permitir el reordenamiento de filas dentro de una sección, pero no entre secciones. Tal vez solo quieras que una sección se pueda reordenar (ese fue mi caso). Si está mirando, como yo, UITableViewDataSourceDelegateno encontrará una notificación para cuando esté a punto de permitirle mover una fila entre secciones. Obtienes uno cuando comienza a mover una fila (lo cual está bien) y otro cuando ya lo ha movido y tienes la oportunidad de sincronizar con tus cosas internas. No es útil.

Entonces, ¿cómo se pueden evitar nuevos pedidos entre secciones?

Publicaré lo que hice como una respuesta separada, ¡dejándolo abierto para que alguien más publique una respuesta aún mejor!

philsquared
fuente
1
¿A qué notificación te refieres cuando dices "obtienes una cuando comienza a moverse una fila"? No veo ninguno, pero espero discernir cuándo comienza el reordenamiento celular.
TomSwift

Respuestas:

181

Esta implementación evitará el reordenamiento fuera de la sección original como la respuesta de Phil, pero también ajustará el registro a la primera o última fila de la sección, dependiendo de dónde fue el arrastre, en lugar de dónde comenzó.

- (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
fuente
¿Hay alguna forma de evitar que la tabla se desplace automáticamente (mientras se arrastra una celda) fuera de la sección permitida?
Palimondo
1
En Xamarin, el método contenedor es UIKit.UITableViewController.CustomizeMoveTarget, para cualquiera que se pregunte.
bunkerdive
74

Realmente bastante simple.

UITableViewDelegate tiene el método:


tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:

Esto se llama mientras el usuario se desplaza sobre un punto de caída potencial. Tienes la oportunidad de decir: "¡No! ¡No lo dejes ahí! ¡Déjalo aquí!" Puede devolver una ruta de índice diferente a la propuesta.

Todo lo que hice fue comprobar si los índices de sección coinciden. Si lo hacen genial, devuelva la ruta propuesta. si no, devuelve la ruta de origen. Esto también evita que las filas en otras secciones se muevan incluso fuera del camino mientras arrastra, y la fila arrastrada volverá a su posición original si intenta moverla a otra sección.


- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
    if( sourceIndexPath.section != proposedDestinationIndexPath.section )
    {
        return sourceIndexPath;
    }
    else
    {
        return proposedDestinationIndexPath;
    }
}
philsquared
fuente
Hacer exactamente esto provoca que se produzcan algunos errores de visualización realmente extraños en mi configuración, y es notablemente diferente del código de ejemplo de Apple sobre cómo hacer esto. ¡FWIW! No digo que esté mal, solo que me pregunto si en realidad es más complicado que esto.
Billy Gray
Puedo arrastrar la fila en otra sección incluso esa fila no se establece allí. pero es visible cuando a otros con fuerza.? alguna idea
Sandy
27

Versión rápida y rápida de la respuesta de Jason para ustedes, gente perezosa:

Swift 3, 4 y 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 y 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
}
Alejandro de Noruega
fuente
7

Puede evitar el movimiento de filas entre secciones utilizando el método siguiente. Simplemente no permita ningún movimiento entre secciones. Incluso puede controlar el movimiento de una fila específica dentro de una sección. por ejemplo, última fila de una sección.

Aquí está el ejemplo:

- (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
fuente
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
}
Enrique
fuente
3

Que @Jason Harwig, el siguiente código funciona correctamente.

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

Para no cambiar de posición entre secciones Swift3

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