Ziehen und Ablegen in Xamarin.iOS

Implementieren von Ziehen und Ablegen für iOS 11

iOS 11 umfasst die Drag-and-Drop-Unterstützung zum Kopieren von Daten zwischen Anwendungen auf dem iPad. Benutzer können alle Arten von Inhalten aus Apps auswählen und ziehen, die nebeneinander positioniert sind, oder indem Sie über ein App-Symbol ziehen, das das Öffnen der App auslöst und die Verworfen der Daten ermöglicht:

Drag and drop example from custom app into Notes app

Hinweis

Vor iOS 15 ist Drag and Drop nur in derselben App auf i Telefon verfügbar. iOS 15 führt Quer-App-Ziehen und Ablegen ein.

Erwägen Sie die Unterstützung von Drag- und Drop-Vorgängen, an denen Inhalte erstellt oder bearbeitet werden können:

  • Textsteuerelemente unterstützen Das Ziehen und Ablegen für alle Apps, die mit iOS 11 erstellt wurden, ohne zusätzliche Arbeit.
  • Tabellenansichten und Sammlungsansichten umfassen Verbesserungen in iOS 11, die das Hinzufügen von Drag- und Drop-Verhalten vereinfachen.
  • Jede andere Ansicht kann vorgenommen werden, um das Ziehen und Ablegen mit zusätzlichen Anpassungen zu unterstützen.

Beim Hinzufügen von Zieh- und Drop-Unterstützung zu Ihren Apps können Sie verschiedene Ebenen der Inhaltstreue bereitstellen. Sie können z. B. sowohl eine formatierte Text- als auch eine Nur-Text-Version der Daten bereitstellen, damit die empfangende App auswählen kann, welche am besten in das Ziehziel passt. Es ist auch möglich, die Ziehvisualisierung anzupassen und das Gleichzeitige Ziehen mehrerer Elemente zu ermöglichen.

Ziehen und Ablegen mit Textsteuerelementen

UITextView und UITextField unterstützt das Automatische Ziehen von markiertem Text und das Ablegen von Textinhalten.

Ziehen und Ablegen mit UITableView

UITableView verfügt über eine integrierte Behandlung für Drag- und Drop-Interaktionen mit Tabellenzeilen, die nur einige Methoden erfordern, um das Standardverhalten zu aktivieren.

Es gibt zwei Schnittstellen:

  • IUITableViewDragDelegate – Packt Informationen, wenn ein Ziehen in der Tabellenansicht initiiert wird.
  • IUITableViewDropDelegate – Verarbeitet Informationen, wenn ein Abbruch versucht und abgeschlossen wird.

Im DragAndDropTableView-Beispiel werden diese beiden Schnittstellen sowohl in der UITableViewController Klasse als auch in der Stellvertretung und Datenquelle implementiert. Sie werden in der ViewDidLoad Methode zugewiesen:

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

Der minimale erforderliche Code für diese beiden Schnittstellen wird unten erläutert.

Tabellenansicht– Stellvertretung ziehen

Die einzige Methode , die zum Ziehen einer Zeile aus einer Tabellenansicht erforderlich ist, ist GetItemsForBeginningDragSession. Wenn der Benutzer mit dem Ziehen einer Zeile beginnt, wird diese Methode aufgerufen.

Unten wird eine Implementierung gezeigt. Sie ruft die daten ab, die der gezogenen Zeile zugeordnet sind, codiert sie und konfiguriert eine NSItemProvider , die bestimmt, wie Anwendungen den "Drop"-Teil des Vorgangs behandeln (z. B. ob sie den Datentyp verarbeiten können, PlainTextim Beispiel):

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

Es gibt viele optionale Methoden für den Ziehdelegat, die zum Anpassen des Ziehverhaltens implementiert werden können, z. B. das Bereitstellen mehrerer Datendarstellungen, die in Ziel-Apps genutzt werden können (z. B. formatierter Text sowie Nur-Text oder Vektor- und Bitmapversionen einer Zeichnung). Sie können auch benutzerdefinierte Datendarstellungen bereitstellen, die beim Ziehen und Ablegen innerhalb derselben App verwendet werden sollen.

Dropdowndelegat für Tabellenansichten

Die Methoden für den Drop-Delegaten werden aufgerufen, wenn ein Ziehvorgang über einer Tabellenansicht erfolgt oder darüber abgeschlossen wird. Die erforderlichen Methoden bestimmen, ob die Daten gelöscht werden dürfen und welche Aktionen ausgeführt werden, wenn der Abbruch abgeschlossen ist:

  • CanHandleDropSession – Während ein Ziehen ausgeführt wird und möglicherweise in der Anwendung abgelegt wird, bestimmt diese Methode, ob die gezogenen Daten gelöscht werden dürfen.
  • DropSessionDidUpdate – Während der Ziehvorgang ausgeführt wird, wird diese Methode aufgerufen, um zu bestimmen, welche Aktion beabsichtigt ist. Informationen aus der Tabellenansicht, die gezogen werden, die Ziehsitzung und der mögliche Indexpfad können verwendet werden, um das Verhalten und das visuelle Feedback zu bestimmen, das dem Benutzer zur Verfügung gestellt wird.
  • PerformDrop – Wenn der Benutzer den Ablagevorgang abgeschlossen hat (durch Heben des Fingers), extrahiert diese Methode die gezogenen Daten und ändert die Tabellenansicht, um die Daten in einer neuen Zeile (oder Zeilen) hinzuzufügen.

CanHandleDropSession

CanHandleDropSession gibt an, ob die Tabellenansicht die gezogenen Daten akzeptieren kann. In diesem Codeausschnitt wird verwendet, um zu bestätigen, CanLoadObjects dass diese Tabellenansicht Zeichenfolgendaten akzeptieren kann.

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

DropSessionDidUpdate

Die DropSessionDidUpdate Methode wird wiederholt aufgerufen, während der Ziehvorgang ausgeführt wird, um dem Benutzer visuelle Hinweise bereitzustellen.

Im folgenden Code wird verwendet, um zu bestimmen, HasActiveDrag ob der Vorgang aus der aktuellen Tabellenansicht stammt. Wenn ja, dürfen nur einzelne Zeilen verschoben werden. Wenn der Ziehvorgang aus einer anderen Quelle stammt, wird ein Kopiervorgang angezeigt:

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

Der Ablagevorgang kann einer von Cancel, , Moveoder Copy.

Die Ablageabsicht kann das Einfügen einer neuen Zeile oder das Hinzufügen/Anfügen von Daten zu einer vorhandenen Zeile sein.

PerformDrop

Die PerformDrop Methode wird aufgerufen, wenn der Benutzer den Vorgang abgeschlossen hat, und ändert die Tabellenansicht und -datenquelle so, dass sie die verworfenen Daten widerspiegelt.

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

Zusätzlicher Code kann hinzugefügt werden, um große Datenobjekte asynchron zu laden.

Testen von Drag and Drop

Sie müssen ein iPad verwenden, um das Beispiel zu testen. Öffnen Sie das Beispiel zusammen mit einer anderen App (z. B. Notizen), und ziehen Sie Zeilen und Text dazwischen:

screenshot of drag operation in progress