共用方式為


在 Xamarin.iOS 中拖放

實作 iOS 11 的拖放

iOS 11 包含拖放支援,以在 iPad 上的應用程式之間複製數據。 使用者可以從並排放置的應用程式選取和拖曳所有類型的內容,或拖曳應用程式圖示,以觸發應用程式開啟並允許卸載數據:

將範例從自定義應用程式拖放到 Notes 應用程式

注意

在 iOS 15 之前,拖放功能只能在 i 電話 上的相同應用程式中使用。 iOS 15 引進跨應用程式拖放功能。

請考慮支援可在內容建立或編輯的任何位置拖放作業:

  • 文字控制項支援針對 iOS 11 建置的所有應用程式拖放功能,而不需要任何額外的工作。
  • 數據表檢視和集合檢視包括 iOS 11 中的增強功能,可簡化新增拖放行為。
  • 您可以進行任何其他檢視,以支援具有其他自定義功能的拖放功能。

將拖放支援新增至您的應用程式時,您可以提供不同層級的內容逼真度;例如,您可以同時提供格式化文字和純文本版本的數據,讓接收應用程式可以選擇最適合拖曳目標。 您也可以自定義拖曳視覺效果,也可以一次啟用拖曳多個專案。

使用文字控制件拖放

UITextViewUITextField 會自動支援將選取的文字拖曳到內,以及置放文字內容。

使用 UITableView 拖放

UITableView 具有與數據表數據列的拖放互動的內建處理,只需要幾個方法來啟用預設行為。

涉及兩個介面:

  • IUITableViewDragDelegate – 在數據表檢視中起始拖曳時封裝資訊。
  • IUITableViewDropDelegate – 嘗試卸除並完成時處理資訊。

在範例中,這兩個介面都會在 類別上 UITableViewController 實作,以及委派和數據源。 它們會在 方法中 ViewDidLoad 指派:

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

以下說明這兩個介面的最低必要程序代碼。

數據表檢視拖曳委派

支援從資料表檢視GetItemsForBeginningDragSession拖曳資料列所需的唯一方法是 。 如果用戶開始拖曳數據列,將會呼叫這個方法。

實作如下所示。 它會擷取與拖曳數據列相關聯的數據、編碼數據,並設定 NSItemProvider ,以決定應用程式如何處理作業的「卸除」部分(例如,它們是否可以在範例中處理數據類型 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);
  }
}

卸除作業可以是 、 MoveCopyCancel其中一個。

置放意圖可以是插入新的數據列,或新增/附加數據至現有的數據列。

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

您可以新增其他程序代碼,以異步方式載入大型資料物件。