Xamarin.iOS でのドラッグ アンド ドロップ
iOS 11 のドラッグ アンド ドロップの実装
iOS 11 には、iPad 上のアプリケーション間でデータをコピーするためのドラッグ アンド ドロップのサポートが組み込まれています。 ユーザーは、並べて配置されたアプリからすべての種類のコンテンツを選択してドラッグすることができます。または、アプリのオープンやデータのドロップの許可をトリガーするアプリ アイコンの上にドラッグすることができます。
Note
iOS 15 より前は、ドラッグ アンド ドロップは iPhone の同じアプリ内でのみ使用できます。 iOS 15 では、アプリ間のドラッグ アンド ドロップが導入されています。
コンテンツを作成または編集できる任意の場所で、ドラッグ アンド ドロップ操作をサポートすることを検討してください。
- テキスト コントロールでは、iOS 11 に対して作成されたすべてのアプリで、追加の作業なくドラッグ アンド ドロップがサポートされます。
- テーブル ビューとコレクション ビューには、ドラッグ アンド ドロップ動作を簡単に追加する iOS 11 の機能強化が含まれています。
- その他のビューでは、追加のカスタマイズを行えば、ドラッグ アンド ドロップをサポートできます。
ドラッグ アンド ドロップのサポートをアプリに追加する場合は、さまざまなレベルのコンテンツの忠実性を提供できます。たとえば、書式設定されたテキストとプレーン テキストの両方のバージョンのデータを指定して、受信アプリがドラッグ先に最適なデータを選択できるようにすることができます。 また、ドラッグの視覚化をカスタマイズしたり、一度に複数の項目をドラッグできるようにしたりすることもできます。
テキスト コントロールを使用したドラッグ アンド ドロップ
UITextView
と UITextField
は、選択したテキストのドラッグと、テキスト コンテンツのドロップを自動的にサポートします。
UITableView を使用したドラッグ アンド ドロップ
UITableView
には、テーブル行とのドラッグ アンド ドロップ操作の処理が組み込まれており、既定の動作を有効にするために必要なメソッドはごくわずかです。
次の 2 つのインターフェイスが関係します。
IUITableViewDragDelegate
– テーブル ビューでドラッグが開始されたときに情報をパッケージ化します。IUITableViewDropDelegate
– ドロップが試行され完了したときに情報を処理します。
サンプルでは、これら 2 つのインターフェイスはどちらも、デリゲートとデータ ソースと共に UITableViewController
クラスに実装されています。 これらは ViewDidLoad
メソッドで割り当てられます。
this.TableView.DragDelegate = this;
this.TableView.DropDelegate = this;
これら 2 つのインターフェイスに必要な最小限のコードを以下で説明します。
テーブル ビューのドラッグ デリゲート
テーブル ビューからの行のドラッグをサポートするために "必要な" メソッドは 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
– ユーザーがドロップを完了すると (指を離すことによって)、このメソッドはドラッグされているデータを抽出し、テーブル ビューを変更して 1 つまたは複数の新しい行にデータを追加します。
CanHandleDropSession
CanHandleDropSession
は、ドラッグされているデータをテーブル ビューが受け入れられるかどうかを示します。 このコード スニペットでは、このテーブル ビューが文字列データを受け入れることを確認するために CanLoadObjects
が使用されます。
public bool CanHandleDropSession(UITableView tableView, IUIDropSession session)
{
return session.CanLoadObjects(typeof(NSString));
}
DropSessionDidUpdate
DropSessionDidUpdate
メソッドは、ドラッグ操作が進行中に繰り返し呼び出され、ユーザーに視覚的な手掛かりを提供します。
次のコードでは、操作が現在のテーブル ビューで開始したかどうかを決定するために HasActiveDrag
が使用されます。 その場合、移動できるのは 1 行だけです。
ドラッグが別のソースからの場合は、コピー操作が示されます。
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);
});
}
大規模なデータ オブジェクトを非同期的に読み込むには、追加のコードを追加できます。