Compartilhar via


Arraste e solte no Xamarin.iOS

Implementando arrastar e soltar para iOS 11

O iOS 11 inclui suporte para arrastar e soltar para copiar dados entre aplicativos no iPad. Os usuários podem selecionar e arrastar todos os tipos de conteúdo de aplicativos posicionados lado a lado ou arrastando sobre um ícone de aplicativo que acionará o aplicativo para abrir e permitir que os dados sejam soltos:

Exemplo de arrastar e soltar do aplicativo personalizado para o aplicativo Notes

Observação

Antes do iOS 15, arrastar e soltar só estava disponível dentro do mesmo aplicativo no iPhone. O iOS 15 introduz o recurso de arrastar e soltar entre aplicativos.

Considere oferecer suporte a operações de arrastar e soltar em qualquer lugar onde o conteúdo possa ser criado ou editado:

  • Os controles de texto oferecem suporte a arrastar e soltar para todos os aplicativos criados no iOS 11, sem qualquer trabalho adicional.
  • As exibições de tabela e de coleção incluem aprimoramentos no iOS 11 que simplificam a adição do comportamento de arrastar e soltar.
  • Qualquer outra exibição pode ser feita para suportar arrastar e soltar com personalização adicional.

Ao adicionar suporte a arrastar e soltar aos seus aplicativos, você pode fornecer diferentes níveis de fidelidade de conteúdo; Por exemplo, você pode fornecer uma versão de texto formatado e texto sem formatação dos dados para que o aplicativo de recebimento possa escolher qual se encaixa melhor no destino de arrastar. Também é possível personalizar a visualização de arrastar e também ativar o arrastar de vários itens de uma só vez.

Arrastar e soltar com controles de texto

UITextView e UITextField suporta automaticamente arrastar o texto selecionado para fora e soltar o conteúdo de texto para dentro.

Arrastar e soltar com UITableView

UITableView tem manipulação interna para interações de arrastar e soltar com linhas de tabela, exigindo apenas alguns métodos para habilitar o comportamento padrão.

Há duas interfaces envolvidas:

  • IUITableViewDragDelegate – Informações de pacotes quando um arrastar é iniciado na visualização de tabela.
  • IUITableViewDropDelegate – Processa informações quando uma queda está sendo tentada e concluída.

No exemplo, essas duas interfaces são implementadas na UITableViewController classe, juntamente com o delegado e a fonte de dados. Eles são atribuídos no ViewDidLoad método:

this.TableView.DragDelegate = this;
this.TableView.DropDelegate = this;

O código mínimo necessário para essas duas interfaces é explicado abaixo.

Modo de Exibição de Tabela Arrastar Delegado

O único método necessário para dar suporte ao arrastar uma linha de um modo de exibição de tabela é GetItemsForBeginningDragSession. Se o usuário começar a arrastar uma linha, esse método será chamado.

Uma implementação é mostrada abaixo. Ele recupera os dados associados à linha arrastada, codifica-os e configura um NSItemProvider que determina como os aplicativos lidarão com a parte "soltar" da operação (por exemplo, se eles podem manipular o tipo de dados, PlainText, no exemplo):

public UIDragItem[] GetItemsForBeginningDragSession (UITableView tableView,
  IUIDragSession session, NSIndexPath indexPath)
{
  // gets the 'information' to be dragged
  var placeName = model.PlaceNames[indexPath.Row];
  // convert to NSData representation
  var data = NSData.FromString(placeName, NSStringEncoding.UTF8);
  // create an NSItemProvider to describe the data
  var itemProvider = new NSItemProvider();
  itemProvider.RegisterDataRepresentation(UTType.PlainText,
                                NSItemProviderRepresentationVisibility.All,
                                (completion) =>
  {
    completion(data, null);
    return null;
  });
  // wrap in a UIDragItem
  return new UIDragItem[] { new UIDragItem(itemProvider) };
}

Há muitos métodos opcionais no delegado de arrastar que podem ser implementados para personalizar o comportamento de arrastar, como fornecer várias representações de dados que podem ser aproveitadas em aplicativos de destino (como texto formatado, bem como texto sem formatação ou versões vetoriais e bitmap de um desenho). Você também pode fornecer representações de dados personalizadas para serem usadas ao arrastar e soltar no mesmo aplicativo.

Delegado de Drop do Modo de Exibição de Tabela

Os métodos no delegado solto são chamados quando uma operação de arrastar ocorre sobre uma exibição de tabela ou é concluída acima dela. Os métodos necessários determinam se os dados podem ser descartados e quais ações são tomadas se a queda for concluída:

  • CanHandleDropSession – Enquanto um arrasto está em andamento e potencialmente sendo solto no aplicativo, esse método determina se os dados que estão sendo arrastados podem ser soltos.
  • DropSessionDidUpdate – Enquanto o arrasto está em andamento, esse método é chamado para determinar qual ação é pretendida. As informações do modo de exibição de tabela que está sendo arrastado, a sessão de arrastar e o possível caminho de índice podem ser usados para determinar o comportamento e o feedback visual fornecidos ao usuário.
  • PerformDrop – Quando o usuário conclui a queda (levantando o dedo), esse método extrai os dados que estão sendo arrastados e modifica a exibição da tabela para adicionar os dados em uma nova linha (ou linhas).

CanHandleDropSession

CanHandleDropSession Indica se o modo de exibição Tabela pode aceitar os dados que estão sendo arrastados. Neste trecho de código, CanLoadObjects é usado para confirmar que esse modo de exibição de tabela pode aceitar dados de cadeia de caracteres.

public bool CanHandleDropSession(UITableView tableView, IUIDropSession session)
{
  return session.CanLoadObjects(typeof(NSString));
}

DropSessionDidUpdate

O DropSessionDidUpdate método é chamado repetidamente enquanto a operação de arrastar está em andamento, para fornecer pistas visuais ao usuário.

No código abaixo, HasActiveDrag é usado para determinar se a operação se originou na exibição de tabela atual. Em caso afirmativo, apenas linhas individuais podem ser movidas. Se o arrasto for de outra fonte, uma operação de cópia será indicada:

public UITableViewDropProposal DropSessionDidUpdate(UITableView tableView, IUIDropSession session, NSIndexPath destinationIndexPath)
{
  // The UIDropOperation.Move operation is available only for dragging within a single app.
  if (tableView.HasActiveDrag)
  {
    if (session.Items.Length > 1)
    {
        return new UITableViewDropProposal(UIDropOperation.Cancel);
    } else {
        return new UITableViewDropProposal(UIDropOperation.Move, UITableViewDropIntent.InsertAtDestinationIndexPath);
    }
  } else {
    return new UITableViewDropProposal(UIDropOperation.Copy, UITableViewDropIntent.InsertAtDestinationIndexPath);
  }
}

A operação de queda pode ser uma de Cancel, Moveou Copy.

A intenção de soltar pode ser inserir uma nova linha ou adicionar/acrescentar dados a uma linha existente.

PerformDrop

O PerformDrop método é chamado quando o usuário conclui a operação e modifica a exibição de tabela e a fonte de dados para refletir os dados descartados.

public void PerformDrop(UITableView tableView, IUITableViewDropCoordinator coordinator)
{
  NSIndexPath indexPath, destinationIndexPath;
  if (coordinator.DestinationIndexPath != null)
  {
    indexPath = coordinator.DestinationIndexPath;
    destinationIndexPath = indexPath;
  }
  else
  {
    // Get last index path of table view
    var section = tableView.NumberOfSections() - 1;
    var row = tableView.NumberOfRowsInSection(section);
    destinationIndexPath = NSIndexPath.FromRowSection(row, section);
  }
  coordinator.Session.LoadObjects(typeof(NSString), (items) =>
  {
    // Consume drag items
    List<string> stringItems = new List<string>();
    foreach (var i in items)
    {
      var q = NSString.FromHandle(i.Handle);
      stringItems.Add(q.ToString());
    }
    var indexPaths = new List<NSIndexPath>();
    for (var j = 0; j < stringItems.Count; j++)
    {
      var indexPath1 = NSIndexPath.FromRowSection(destinationIndexPath.Row + j, destinationIndexPath.Section);
      model.AddItem(stringItems[j], indexPath1.Row);
      indexPaths.Add(indexPath1);
    }
    tableView.InsertRows(indexPaths.ToArray(), UITableViewRowAnimation.Automatic);
  });
}

Código adicional pode ser adicionado para carregar objetos de dados grandes de forma assíncrona.