Compartir a través de


Arrastrar y colocar en Xamarin.iOS

Implementación de arrastrar y colocar para iOS 11

iOS 11 incluye compatibilidad con la opción de arrastrar y colocar para copiar datos entre aplicaciones en el iPad. Los usuarios pueden seleccionar y arrastrar todos los tipos de contenido desde aplicaciones colocadas en paralelo, o arrastrando sobre un icono de aplicación que desencadenará la aplicación para abrir y permitir que se quiten los datos:

Ejemplo de arrastrar y colocar desde una aplicación personalizada a la aplicación Notas

Nota:

Antes de iOS 15, la opción de arrastrar y colocar solo estaba disponible en la misma aplicación en iPhone. iOS 15 presenta la opción de arrastrar y colocar entre aplicaciones.

Considere la posibilidad de admitir operaciones de arrastrar y colocar en cualquier lugar donde se pueda crear o editar contenido:

  • Los controles de texto admiten arrastrar y colocar para todas las aplicaciones compiladas en iOS 11, sin ningún trabajo adicional.
  • Las vistas de tabla y las vistas de colección incluyen mejoras en iOS 11 que simplifican la adición del comportamiento de arrastrar y colocar.
  • Cualquier otra vista se puede realizar para admitir la opción de arrastrar y colocar con personalización adicional.

Al agregar compatibilidad con arrastrar y colocar a las aplicaciones, puede proporcionar diferentes niveles de fidelidad de contenido. Por ejemplo, puede proporcionar una versión de texto con formato y texto sin formato de los datos para que la aplicación receptora pueda elegir cuál se ajusta mejor al destino del arrastre. También es posible personalizar la visualización de arrastre y también habilitar la opción de arrastrar varios elementos a la vez.

Arrastrar y colocar con controles de texto

UITextView y UITextField admiten automáticamente la opción de arrastrar el texto seleccionado y colocar contenido de texto.

Arrastrar y colocar con UITableView

UITableView tiene un control integrado para interacciones de arrastrar y colocar con filas de tabla, lo que requiere solo algunos métodos para habilitar el comportamiento predeterminado.

Hay dos interfaces implicadas:

  • IUITableViewDragDelegate: empaqueta información cuando se inicia una acción de arrastrar en la vista de tabla.
  • IUITableViewDropDelegate: procesa la información cuando se intenta y se consigue arrastrar.

En el ejemplo, estas dos interfaces se implementan en la clase UITableViewController, junto con el delegado y el origen de datos. Se asignan en el método ViewDidLoad:

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

A continuación se explica el código mínimo necesario para estas dos interfaces.

Vista de tabla Delegado de arrastre

El único método necesario para admitir el arrastre de una fila desde una vista de tabla es GetItemsForBeginningDragSession. Si el usuario comienza a arrastrar una fila, se llamará a este método.

A continuación se muestra una implementación. Recupera los datos asociados a la fila arrastrada, lo codifica y configura un NSItemProvider que determina cómo las aplicaciones controlarán la parte "arrastrar" de la operación (por ejemplo, si pueden controlar el tipo de datos, PlainText, en el ejemplo):

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) };
}

Hay muchos métodos opcionales en el delegado de arrastre que se pueden implementar para personalizar el comportamiento de arrastre, como proporcionar varias representaciones de datos que se pueden aprovechar en las aplicaciones de destino (como texto con formato, así como texto sin formato, o una versión de vector y mapa de bits de un dibujo). También puede proporcionar representaciones de datos personalizadas que se usarán al arrastrar y colocar dentro de la misma aplicación.

Vista de tabla Delegado de colocación

Se llama a los métodos del delegado de colocación cuando se produce una operación de arrastrar sobre una vista de tabla o se completa encima de él. Los métodos necesarios determinan si se permiten colocar los datos y qué acciones se realizan si se completa la colocación:

  • CanHandleDropSession: mientras se está arrastrando y se puede colocar en la aplicación, este método determina si se pueden colocar los datos que se arrastran.
  • DropSessionDidUpdate: mientras se está arrastrando, se llama a este método para determinar qué acción se pretende. La información de la vista de tabla que se arrastra, la sesión de arrastre y la posible ruta de acceso de índice se puede usar para determinar el comportamiento y los comentarios visuales proporcionados al usuario.
  • PerformDrop: cuando el usuario completa la colocación (levantando el dedo), este método extrae los datos que se arrastran y modifica la vista de tabla para agregar los datos en una nueva fila (o filas).

CanHandleDropSession

CanHandleDropSession indica si la vista de tabla puede aceptar los datos que se arrastran. En este fragmento de código, CanLoadObjects se usa para confirmar que esta vista de tabla puede aceptar datos de cadena.

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

DropSessionDidUpdate

El método DropSessionDidUpdate se llama repetidamente mientras la operación de arrastre está en curso, para proporcionar indicaciones visuales al usuario.

En el código siguiente, HasActiveDrag se usa para determinar si la operación se originó en la vista de tabla actual. Si es así, solo se permiten mover filas únicas. Si el arrastre es de otro origen, se indicará una operación de copia:

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);
  }
}

La operación de colocación puede ser una de Cancel, Moveo Copy.

La intención de colocar puede ser insertar una nueva fila o agregar o anexar datos a una fila existente.

PerformDrop

Se llama al método PerformDrop cuando el usuario completa la operación y modifica la vista de tabla y el origen de datos para reflejar los datos colocados.

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);
  });
}

Se puede agregar código adicional para cargar de forma asincrónica objetos de datos grandes.