Como limitar o reordenamento de linhas do UITableView a uma seção

121

Eu estava batendo minha cabeça sobre este, e o google não estava aparecendo nada. Acabei resolvendo e pensei em escrever aqui para o bem da próxima pessoa.

Você tem um UITableViewcom várias seções. Cada seção é homogênea, mas a tabela geral é heterogênea. Portanto, convém permitir o reordenamento das linhas em uma seção, mas não nas seções. Talvez você só queira que uma seção seja reordenada (esse foi o meu caso). Se você estiver olhando, como eu estava, no local UITableViewDataSourceDelegate, não encontrará uma notificação de quando está prestes a permitir que você mova uma linha entre as seções. Você obtém um quando ele começa a mover uma linha (o que é bom) e um quando já está movido e você tem a chance de sincronizar com o material interno. Não ajuda.

Então, como você pode impedir novos pedidos entre as seções?

Vou postar o que fiz como resposta separada, deixando em aberto para outra pessoa postar uma resposta ainda melhor!

philsquared
fonte
1
A que notificação você se refere quando diz "recebe uma quando começa a mover uma linha"? Não estou vendo uma, mas espero discernir quando a reordenação de células começar.
precisa saber é o seguinte

Respostas:

181

Essa implementação impedirá o reordenamento fora da seção original, como a resposta de Phil, mas também encaixará o registro na primeira ou na última linha da seção, dependendo de onde foi o arrasto, em vez de onde começou.

- (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
fonte
Existe uma maneira de impedir que a tabela role automaticamente (enquanto arrasta uma célula) fora da seção permitida?
Palimondo 8/12/12
1
No Xamarin, o método wrapper é UIKit.UITableViewController.CustomizeMoveTarget, para quem quer saber.
23917 bunkerdive
74

Simples o suficiente, realmente.

O UITableViewDelegate possui o método:


tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:

Isso é chamado enquanto o usuário está passando o mouse sobre um ponto de queda em potencial. Você tem a chance de dizer: "não! Não largue lá! Largue aqui em vez disso". Você pode retornar um caminho de índice diferente para o caminho proposto.

Tudo o que fiz foi verificar se os índices da seção correspondem. Se eles forem excelentes, retorne o caminho proposto. caso contrário, retorne o caminho de origem. Isso também evita que as linhas de outras seções se afastem enquanto você arrasta - e a linha arrastada volta à sua posição original quando você tenta movê-la para outra seção.


- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
    if( sourceIndexPath.section != proposedDestinationIndexPath.section )
    {
        return sourceIndexPath;
    }
    else
    {
        return proposedDestinationIndexPath;
    }
}
philsquared
fonte
Fazer exatamente isso faz com que alguns bugs de exibição verdadeiramente estranhos ocorram na minha configuração, e é notavelmente diferente do exemplo de código da Apple sobre como fazer isso. FWIW! não dizendo que está errado, só que eu me pergunto se é realmente mais complicado do que isso.
Billy Gray
Eu posso arrastar a linha em outra seção, mesmo que a linha não esteja sendo definida lá. mas é visível quando outro com força. qualquer ideia
Sandy
27

Versão rápida e rápida da resposta de Jason para pessoas preguiçosas:

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
}
Alexandre da Noruega
fonte
7

Você pode impedir o movimento de linhas entre as seções usando o método abaixo. Apenas não permita nenhum movimento entre as seções. Você pode até controlar o movimento de uma linha específica dentro de uma seção. por exemplo, última linha em uma seção.

Aqui está o exemplo:

- (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
fonte
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
}
Henry
fonte
3

Than @Jason Harwig, o código abaixo funciona corretamente.

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

Para não mudar de posição entre as seções Swift3

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