Xamarin.iOS에서 끌어서 놓기
iOS 11에 대한 끌어서 놓기 구현
iOS 11에는 iPad의 애플리케이션 간에 데이터를 복사하는 끌어서 놓기 지원이 포함되어 있습니다. 사용자는 나란히 배치된 앱에서 모든 유형의 콘텐츠를 선택하고 끌거나 앱 아이콘 위로 끌어서 앱을 열고 데이터를 삭제할 수 있도록 할 수 있습니다.
참고 항목
iOS 15 이전에는 i전화 동일한 앱 내에서만 끌어서 놓기를 사용할 수 있습니다. iOS 15에는 앱 간 끌어서 놓기가 도입되었습니다.
콘텐츠를 만들거나 편집할 수 있는 모든 위치에서 끌어서 놓기 작업을 지원하는 것이 좋습니다.
- 텍스트 컨트롤은 추가 작업 없이 iOS 11에 대해 빌드된 모든 앱에 대해 끌어서 놓기를 지원합니다.
- 테이블 뷰 및 컬렉션 뷰에는 끌어서 놓기 동작 추가를 간소화하는 iOS 11의 향상된 기능이 포함되어 있습니다.
- 추가 사용자 지정을 통해 끌어서 놓기를 지원하기 위해 다른 모든 보기를 만들 수 있습니다.
앱에 끌어서 놓기 지원을 추가할 때 다양한 수준의 콘텐츠 충실도를 제공할 수 있습니다. 예를 들어 수신 앱이 끌기 대상에 가장 적합한 항목을 선택할 수 있도록 서식이 지정된 텍스트와 일반 텍스트 버전의 데이터를 모두 제공할 수 있습니다. 끌기 시각화를 사용자 지정하고 한 번에 여러 항목을 끌 수도 있습니다.
텍스트 컨트롤을 사용하여 끌어서 놓기
UITextView
선택한 UITextField
텍스트를 끌어서 텍스트 콘텐츠를 삭제할 수 있습니다.
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);
}
}
놓기 작업은 , Move
또는 Copy
. 중 Cancel
하나일 수 있습니다.
삭제 의도는 새 행을 삽입하거나 기존 행에 데이터를 추가/추가하는 것입니다.
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);
});
}
큰 데이터 개체를 비동기적으로 로드하기 위해 추가 코드를 추가할 수 있습니다.