Editando tabelas com o Xamarin.iOS
Os recursos de edição de tabela são habilitados substituindo métodos em uma UITableViewSource
subclasse. O comportamento de edição mais simples é o gesto de passar o dedo para excluir que pode ser implementado com uma única substituição de método.
Edições mais complexas (incluindo mover linhas) podem ser feitas com a tabela no modo de edição.
Deslize para excluir
O recurso de deslizar para excluir é um gesto natural no iOS que os usuários esperam.
Há três substituições de método que afetam o gesto de passar o dedo para mostrar um botão Excluir em uma célula:
- CommitEditingStyle – A origem da tabela detecta se esse método é substituído e habilita automaticamente o gesto de passar o dedo para excluir. A implementação do método deve chamar
DeleteRows
oUITableView
para fazer com que as células desapareçam e também remover os dados subjacentes do seu modelo (por exemplo, uma matriz, dicionário ou banco de dados). - CanEditRow – Se CommitEditingStyle for substituído, todas as linhas serão consideradas editáveis. Se esse método for implementado e retornar false (para algumas linhas específicas ou para todas as linhas), o gesto de passar o dedo para excluir não estará disponível nessa célula.
- TitleForDeleteConfirmation – Opcionalmente especifica o texto para o botão Excluir . Se esse método não for implementado, o texto do botão será "Excluir".
Esses métodos são implementados na classe a TableSource
seguir:
public override void CommitEditingStyle (UITableView tableView, UITableViewCellEditingStyle editingStyle, Foundation.NSIndexPath indexPath)
{
switch (editingStyle) {
case UITableViewCellEditingStyle.Delete:
// remove the item from the underlying data source
tableItems.RemoveAt(indexPath.Row);
// delete the row from the table
tableView.DeleteRows (new NSIndexPath[] { indexPath }, UITableViewRowAnimation.Fade);
break;
case UITableViewCellEditingStyle.None:
Console.WriteLine ("CommitEditingStyle:None called");
break;
}
}
public override bool CanEditRow (UITableView tableView, NSIndexPath indexPath)
{
return true; // return false if you wish to disable editing for a specific indexPath or for all rows
}
public override string TitleForDeleteConfirmation (UITableView tableView, NSIndexPath indexPath)
{ // Optional - default text is 'Delete'
return "Trash (" + tableItems[indexPath.Row].SubHeading + ")";
}
Para este exemplo, o UITableViewSource
foi atualizado para usar um List<TableItem>
(em vez de uma matriz de cadeia de caracteres) como a fonte de dados porque ele oferece suporte à adição e exclusão de itens da coleção.
Modo de edição
Quando uma tabela está no modo de edição, o usuário vê um widget vermelho 'parar' em cada linha, que revela um botão Excluir quando tocado. A tabela também exibe um ícone de 'alça' para indicar que a linha pode ser arrastada para alterar a ordem. O exemplo TableEditMode implementa esses recursos conforme mostrado.
Há vários métodos diferentes que UITableViewSource
afetam o comportamento do modo de edição de uma tabela:
- CanEditRow – se cada linha pode ser editada. Retorne false para impedir que o gesto de percorrer para excluir e a exclusão enquanto estiver no modo de edição.
- CanMoveRow – retorna true para habilitar a 'alça' de movimentação ou false para impedir a movimentação.
- EditingStyleForRow – quando a tabela está no modo de edição, o valor de retorno desse método determina se a célula exibe o ícone de exclusão vermelho ou o ícone de adição verde. Retorne
UITableViewCellEditingStyle.None
se a linha não puder ser editável. - MoveRow – chamado quando uma linha é movida para que a estrutura de dados subjacente possa ser modificada para corresponder aos dados como eles são exibidos na tabela.
A implementação para os três primeiros métodos é relativamente direta – a menos que você deseje usar o indexPath
para alterar o comportamento de linhas específicas, basta codificar os valores de retorno para a tabela inteira.
public override bool CanEditRow (UITableView tableView, NSIndexPath indexPath)
{
return true; // return false if you wish to disable editing for a specific indexPath or for all rows
}
public override bool CanMoveRow (UITableView tableView, NSIndexPath indexPath)
{
return true; // return false if you don't allow re-ordering
}
public override UITableViewCellEditingStyle EditingStyleForRow (UITableView tableView, NSIndexPath indexPath)
{
return UITableViewCellEditingStyle.Delete; // this example doesn't support Insert
}
A MoveRow
implementação é um pouco mais complicada porque precisa alterar a estrutura de dados subjacente para corresponder à nova ordem. Como os dados são implementados como um List
código abaixo, exclui o item de dados em seu local antigo e o insere no novo local. Se os dados foram armazenados em uma tabela de banco de dados SQLite com uma coluna 'ordem' (por exemplo), esse método precisaria executar algumas operações SQL para reordenar os números nessa coluna.
public override void MoveRow (UITableView tableView, NSIndexPath sourceIndexPath, NSIndexPath destinationIndexPath)
{
var item = tableItems[sourceIndexPath.Row];
var deleteAt = sourceIndexPath.Row;
var insertAt = destinationIndexPath.Row;
// are we inserting
if (destinationIndexPath.Row < sourceIndexPath.Row) {
// add one to where we delete, because we're increasing the index by inserting
deleteAt += 1;
} else {
// add one to where we insert, because we haven't deleted the original yet
insertAt += 1;
}
tableItems.Insert (insertAt, item);
tableItems.RemoveAt (deleteAt);
}
Finalmente, para colocar a tabela no modo de edição, o botão Editar precisa chamar SetEditing
assim
table.SetEditing (true, true);
e quando o usuário terminar de editar, o botão Concluído deve desativar o modo de edição:
table.SetEditing (false, true);
Estilo de edição de inserção de linha
A inserção de linha de dentro da tabela é uma interface de usuário incomum – o principal exemplo nos aplicativos iOS padrão é a tela Editar contato . Esta captura de tela mostra como a funcionalidade de inserção de linha funciona – no modo de edição, há uma linha adicional que (quando clicada) insere linhas adicionais nos dados. Quando a edição estiver concluída, a linha temporária (adicionar nova) será removida.
Há vários métodos diferentes que UITableViewSource
afetam o comportamento do modo de edição de uma tabela. Esses métodos foram implementados da seguinte maneira no código de exemplo:
- EditingStyleForRow – retorna
UITableViewCellEditingStyle.Delete
para as linhas que contêm dados e retornaUITableViewCellEditingStyle.Insert
para a última linha (que será adicionada especificamente para se comportar como um botão de inserção). - CustomizeMoveTarget – Enquanto o usuário estiver movendo uma célula, o valor de retorno desse método opcional pode substituir sua escolha de local. Isso significa que você pode impedir que eles "soltem" a célula em determinadas posições – como este exemplo que impede que qualquer linha seja movida após a linha (adicionar nova).
- CanMoveRow – retorna true para habilitar a 'alça' de movimentação ou false para impedir a movimentação. No exemplo, a última linha tem o 'identificador' de movimentação oculto porque se destina apenas ao servidor como um botão de inserção.
Também adicionamos dois métodos personalizados para adicionar a linha 'inserir' e, em seguida, removê-la novamente quando não for mais necessário. Eles são chamados a partir dos botões Editar e Concluído :
- WillBeginTableEditing – Quando o botão Editar é tocado, ele chama
SetEditing
para colocar a tabela no modo de edição. Isso aciona o método WillBeginTableEditing onde exibimos a linha (adicionar nova) no final da tabela para atuar como um 'botão de inserção'. - DidFinishTableEditing – Quando o botão Concluído é tocado
SetEditing
é chamado novamente para desativar o modo de edição. O código de exemplo remove a linha (adicionar nova) da tabela quando a edição não é mais necessária.
Essas substituições de método são implementadas no arquivo de exemplo TableEditModeAdd/Code/TableSource.cs:
public override UITableViewCellEditingStyle EditingStyleForRow (UITableView tableView, NSIndexPath indexPath)
{
if (tableView.Editing) {
if (indexPath.Row == tableView.NumberOfRowsInSection (0) - 1)
return UITableViewCellEditingStyle.Insert;
else
return UITableViewCellEditingStyle.Delete;
} else // not in editing mode, enable swipe-to-delete for all rows
return UITableViewCellEditingStyle.Delete;
}
public override NSIndexPath CustomizeMoveTarget (UITableView tableView, NSIndexPath sourceIndexPath, NSIndexPath proposedIndexPath)
{
var numRows = tableView.NumberOfRowsInSection (0) - 1; // less the (add new) one
if (proposedIndexPath.Row >= numRows)
return NSIndexPath.FromRowSection(numRows - 1, 0);
else
return proposedIndexPath;
}
public override bool CanMoveRow (UITableView tableView, NSIndexPath indexPath)
{
return indexPath.Row < tableView.NumberOfRowsInSection (0) - 1;
}
Esses dois métodos personalizados são usados para adicionar e remover a linha (adicionar nova) quando o modo de edição da tabela está habilitado ou desabilitado:
public void WillBeginTableEditing (UITableView tableView)
{
tableView.BeginUpdates ();
// insert the 'ADD NEW' row at the end of table display
tableView.InsertRows (new NSIndexPath[] {
NSIndexPath.FromRowSection (tableView.NumberOfRowsInSection (0), 0)
}, UITableViewRowAnimation.Fade);
// create a new item and add it to our underlying data (it is not intended to be permanent)
tableItems.Add (new TableItem ("(add new)"));
tableView.EndUpdates (); // applies the changes
}
public void DidFinishTableEditing (UITableView tableView)
{
tableView.BeginUpdates ();
// remove our 'ADD NEW' row from the underlying data
tableItems.RemoveAt ((int)tableView.NumberOfRowsInSection (0) - 1); // zero based :)
// remove the row from the table display
tableView.DeleteRows (new NSIndexPath[] { NSIndexPath.FromRowSection (tableView.NumberOfRowsInSection (0) - 1, 0) }, UITableViewRowAnimation.Fade);
tableView.EndUpdates (); // applies the changes
}
Finalmente, esse código instancia os botões Editar e Concluído, com lambdas que ativam ou desabilitam o modo de edição quando são tocados:
done = new UIBarButtonItem(UIBarButtonSystemItem.Done, (s,e)=>{
table.SetEditing (false, true);
NavigationItem.RightBarButtonItem = edit;
tableSource.DidFinishTableEditing(table);
});
edit = new UIBarButtonItem(UIBarButtonSystemItem.Edit, (s,e)=>{
if (table.Editing)
table.SetEditing (false, true); // if we've half-swiped a row
tableSource.WillBeginTableEditing(table);
table.SetEditing (true, true);
NavigationItem.LeftBarButtonItem = null;
NavigationItem.RightBarButtonItem = done;
});
Esse padrão de interface do usuário de inserção de linha não é usado com muita frequência, no entanto, você também pode usar os UITableView.BeginUpdates
métodos e EndUpdates
para animar a inserção ou remoção de células em qualquer tabela. A regra para usar esses métodos é que a diferença no valor retornado por RowsInSection
entre as BeginUpdates
chamadas e EndUpdates
deve corresponder ao número líquido de células adicionadas/excluídas com os InsertRows
métodos e DeleteRows
. Se a fonte de dados subjacente não for alterada para corresponder às inserções/exclusões na exibição de tabela, ocorrerá um erro.