Перетаскивание в Xamarin.iOS

Реализация перетаскивания для iOS 11

iOS 11 включает поддержку перетаскивания для копирования данных между приложениями на iPad. Пользователи могут выбирать и перетаскивать все типы содержимого из приложений, расположенных параллельно или перетаскивая значок приложения, который активирует открытие приложения и разрешение удаления данных:

Drag and drop example from custom app into Notes app

Примечание.

До iOS 15 перетаскивание доступно только в одном приложении на i Телефон. В iOS 15 представлено перетаскивание и перетаскивание между приложениями.

Рассмотрите возможность поддержки операций перетаскивания в любом месте, где можно создать или изменить содержимое:

  • Элементы управления текстом поддерживают перетаскивание для всех приложений, созданных в iOS 11, без дополнительной работы.
  • Представления таблиц и представления коллекции включают улучшения в iOS 11, которые упрощают добавление поведения перетаскивания и перетаскивания.
  • Любое другое представление можно сделать для поддержки перетаскивания с дополнительной настройкой.

При добавлении поддержки перетаскивания в приложения можно предоставить различные уровни точности содержимого; Например, можно указать форматированный текст и версию данных обычного текста, чтобы принимающее приложение могло выбрать, что лучше всего подходит в целевой объект перетаскивания. Кроме того, можно настроить визуализацию перетаскивания, а также включить перетаскивание нескольких элементов одновременно.

Перетаскивание с текстовыми элементами управления

UITextView и UITextField автоматически поддерживает перетаскивание выделенного текста и удаление содержимого текста.

Перетаскивание с помощью UITableView

UITableView имеет встроенную обработку для взаимодействия перетаскивания с строками таблиц, требуя только нескольких методов для включения поведения по умолчанию.

Существует два интерфейса:

  • IUITableViewDragDelegate — пакеты сведений при инициировании перетаскивания в представлении таблицы.
  • IUITableViewDropDelegate — обрабатывает сведения при попытке и завершении удаления.

В примере DragAndDropTableView эти два интерфейса реализуются в UITableViewController классе вместе с делегатом и источником данных. Они назначаются в методе ViewDidLoad :

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

Ниже описан минимальный обязательный код для этих двух интерфейсов.

Делегат перетаскивания представления таблиц

Единственный метод , необходимый для поддержки перетаскивания строки из представления GetItemsForBeginningDragSessionтаблицы. Если пользователь начинает перетаскивать строку, этот метод будет вызван.

Ниже показана реализация. Он извлекает данные, связанные с перетаскиваемой строкой, кодирует его и настраивает NSItemProvider способ обработки частью операции "drop" (например, может ли он обрабатывать тип данных, PlainTextв примере):

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

Существует множество необязательных методов делегата перетаскивания, которые можно реализовать для настройки поведения перетаскивания, например предоставления нескольких представлений данных, которые можно использовать в целевых приложениях (например, форматированный текст, обычный текст или векторные и растровые версии рисунка). Можно также предоставить пользовательские представления данных, которые будут использоваться при перетаскивании и удалении в одном приложении.

Делегат раскрывающегося представления таблицы

Методы делегата перетаскивания вызываются, когда операция перетаскивания возникает в представлении таблицы или завершается над ней. Необходимые методы определяют, разрешено ли удалять данные и какие действия выполняются при завершении удаления:

  • CanHandleDropSession — Пока выполняется перетаскивание и потенциально удаляется в приложении, этот метод определяет, разрешено ли перетаскивание данных.
  • DropSessionDidUpdate — Пока выполняется перетаскивание, этот метод вызывается для определения предполагаемого действия. Сведения из представления таблицы, перетаскиваемого поверх, сеанс перетаскивания и возможный путь к индексу, можно использовать для определения поведения и визуальной обратной связи, предоставленной пользователю.
  • PerformDrop — Когда пользователь завершает удаление (поднимая пальцем), этот метод извлекает данные, перетаскиваемые и изменяет представление таблицы, чтобы добавить данные в новую строку (или строки).

CanHandleDropSession

CanHandleDropSession указывает, может ли представление таблицы принимать перетаскиваемые данные. В этом фрагменте кода используется для подтверждения того, CanLoadObjects что это представление таблицы может принимать строковые данные.

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

DropSessionDidUpdate

Метод DropSessionDidUpdate вызывается многократно во время выполнения операции перетаскивания, чтобы предоставить визуальные подсказки пользователю.

В приведенном ниже коде используется для определения того, HasActiveDrag возникла ли операция в текущем представлении таблицы. В этом случае можно переместить только отдельные строки. Если перетаскивание находится из другого источника, операция копирования будет указана:

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

Операция удаления может быть одной из Cancel, Moveили Copy.

Целью удаления может быть вставка новой строки или добавление или добавление данных в существующую строку.

PerformDrop

Метод PerformDrop вызывается, когда пользователь завершает операцию, и изменяет представление таблицы и источник данных для отражения удаленных данных.

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

Для асинхронной загрузки больших объектов данных можно добавить дополнительный код.

Тестирование перетаскивания

Для тестирования примера необходимо использовать iPad. Откройте пример вместе с другим приложением (например, заметки) и перетащите строки и текст между ними:

screenshot of drag operation in progress