Xamarin.iOS를 사용하여 테이블 편집
테이블 편집 기능은 서브클래스에서 메서드를 재정의 UITableViewSource
하여 사용하도록 설정됩니다. 가장 간단한 편집 동작은 단일 메서드 재정의로 구현할 수 있는 살짝 밀기-삭제 제스처입니다.
편집 모드에서 테이블을 사용하여 더 복잡한 편집(행 이동 포함)을 수행할 수 있습니다.
살짝 밀어 삭제
삭제할 살짝 밀기 기능은 사용자가 기대하는 iOS의 자연스러운 제스처입니다.
셀에 삭제 단추를 표시하기 위해 살짝 밀기 제스처에 영향을 주는 세 가지 메서드 재정의가 있습니다.
- CommitEditingStyle – 테이블 원본은 이 메서드가 재정의되었는지 감지하고 살짝 밀기-삭제 제스처를 자동으로 사용하도록 설정합니다. 메서드의 구현은 셀이 사라지도록 하고 모델에서 기본 데이터(예: 배열, 사전 또는 데이터베이스)를 제거하도록 호출
DeleteRows
UITableView
해야 합니다. - CanEditRow – CommitEditingStyle이 재정의되면 모든 행을 편집할 수 있는 것으로 간주됩니다. 이 메서드가 구현되고 false를 반환하는 경우(일부 특정 행 또는 모든 행에 대해) 해당 셀에서 살짝 밀기-삭제 제스처를 사용할 수 없습니다.
- TitleForDeleteConfirmation – 선택적으로 삭제 단추의 텍스트를 지정합니다. 이 메서드를 구현하지 않으면 단추 텍스트는 "Delete"가 됩니다.
이러한 메서드는 다음 클래스에서 TableSource
구현됩니다.
public override void CommitEditingStyle (UITableView tableView, UITableViewCellEditingStyle editingStyle, Foundation.NSIndexPath indexPath)
{
switch (editingStyle) {
case UITableViewCellEditingStyle.Delete:
// remove the item from the underlying data source
tableItems.RemoveAt(indexPath.Row);
// delete the row from the table
tableView.DeleteRows (new NSIndexPath[] { indexPath }, UITableViewRowAnimation.Fade);
break;
case UITableViewCellEditingStyle.None:
Console.WriteLine ("CommitEditingStyle:None called");
break;
}
}
public override bool CanEditRow (UITableView tableView, NSIndexPath indexPath)
{
return true; // return false if you wish to disable editing for a specific indexPath or for all rows
}
public override string TitleForDeleteConfirmation (UITableView tableView, NSIndexPath indexPath)
{ // Optional - default text is 'Delete'
return "Trash (" + tableItems[indexPath.Row].SubHeading + ")";
}
이 예제에서는 UITableViewSource
컬렉션에서 항목 추가 및 삭제를 지원하므로 문자열 배열 대신 데이터 원본으로 사용하도록 List<TableItem>
업데이트되었습니다.
편집 모드
테이블이 편집 모드인 경우 각 행에 빨간색 '중지' 위젯이 표시되며, 이 위젯은 터치 시 삭제 단추를 표시합니다. 표에는 행을 끌어 순서를 변경할 수 있음을 나타내는 '핸들' 아이콘도 표시됩니다. TableEditMode 샘플은 표시된 대로 이러한 기능을 구현합니다.
테이블의 편집 모드 동작에 UITableViewSource
영향을 주는 다양한 메서드가 있습니다.
- CanEditRow – 각 행을 편집할 수 있는지 여부입니다. 편집 모드에서 삭제 및 삭제를 모두 방지하려면 false를 반환합니다.
- CanMoveRow – 이동을 방지하기 위해 이동 '핸들' 또는 false를 사용하도록 설정하려면 true를 반환합니다.
- EditingStyleForRow – 테이블이 편집 모드에 있는 경우 이 메서드의 반환 값은 셀에 빨간색 삭제 아이콘 또는 녹색 추가 아이콘이 표시되는지 여부를 결정합니다. 행을 편집할 수 없으면 반환
UITableViewCellEditingStyle.None
합니다. - MoveRow - 행이 테이블에 표시되는 데이터와 일치하도록 기본 데이터 구조를 수정할 수 있도록 행을 이동할 때 호출됩니다.
처음 세 가지 메서드의 구현은 비교적 직선입니다. 특정 행의 동작을 변경하려는 indexPath
경우가 아니면 전체 테이블의 반환 값을 하드 코딩하기만 하면 됩니다.
public override bool CanEditRow (UITableView tableView, NSIndexPath indexPath)
{
return true; // return false if you wish to disable editing for a specific indexPath or for all rows
}
public override bool CanMoveRow (UITableView tableView, NSIndexPath indexPath)
{
return true; // return false if you don't allow re-ordering
}
public override UITableViewCellEditingStyle EditingStyleForRow (UITableView tableView, NSIndexPath indexPath)
{
return UITableViewCellEditingStyle.Delete; // this example doesn't support Insert
}
구현은 MoveRow
새 순서와 일치하도록 기본 데이터 구조를 변경해야 하기 때문에 좀 더 복잡합니다. 데이터는 아래 코드로 List
구현되므로 이전 위치에서 데이터 항목을 삭제하고 새 위치에 삽입합니다. 데이터가 'order' 열이 있는 SQLite 데이터베이스 테이블에 저장된 경우(예:) 이 메서드는 대신 해당 열의 숫자 순서를 다시 지정하기 위해 일부 SQL 작업을 수행해야 합니다.
public override void MoveRow (UITableView tableView, NSIndexPath sourceIndexPath, NSIndexPath destinationIndexPath)
{
var item = tableItems[sourceIndexPath.Row];
var deleteAt = sourceIndexPath.Row;
var insertAt = destinationIndexPath.Row;
// are we inserting
if (destinationIndexPath.Row < sourceIndexPath.Row) {
// add one to where we delete, because we're increasing the index by inserting
deleteAt += 1;
} else {
// add one to where we insert, because we haven't deleted the original yet
insertAt += 1;
}
tableItems.Insert (insertAt, item);
tableItems.RemoveAt (deleteAt);
}
마지막으로 테이블을 편집 모드로 전환하려면 편집 단추가 다음과 같이 호출 SetEditing
해야 합니다.
table.SetEditing (true, true);
사용자가 편집을 마치면 완료 단추가 편집 모드를 해제해야 합니다.
table.SetEditing (false, true);
행 삽입 편집 스타일
테이블 내에서 행 삽입은 일반적이지 않은 사용자 인터페이스입니다. 표준 iOS 앱의 기본 예제는 연락처 편집 화면입니다. 이 스크린샷은 행 삽입 기능의 작동 방식을 보여 줍니다. 편집 모드에서는 클릭할 때 추가 행을 데이터에 삽입하는 추가 행이 있습니다. 편집이 완료되면 임시 (새 추가) 행이 제거됩니다.
테이블의 편집 모드 동작에 UITableViewSource
영향을 주는 다양한 메서드가 있습니다. 이러한 메서드는 예제 코드에서 다음과 같이 구현되었습니다.
- EditingStyleForRow – 데이터가 포함된 행을 반환
UITableViewCellEditingStyle.Delete
하고 마지막 행(삽입 단추로 동작하도록 특별히 추가됨)을 반환UITableViewCellEditingStyle.Insert
합니다. - CustomizeMoveTarget – 사용자가 셀을 이동하는 동안 이 선택적 메서드의 반환 값이 선택한 위치를 재정의할 수 있습니다. 즉, 특정 위치에 있는 셀을 '삭제'하지 못하도록 할 수 있습니다. 예를 들어 (새 추가) 행 이후에 행이 이동되지 않도록 하는 예제입니다.
- CanMoveRow – 이동을 방지하기 위해 이동 '핸들' 또는 false를 사용하도록 설정하려면 true를 반환합니다. 이 예제에서 마지막 행에는 삽입 단추로만 서버용이므로 이동 '핸들'이 숨겨집니다.
또한 두 개의 사용자 지정 메서드를 추가하여 'insert' 행을 추가한 다음 더 이상 필요하지 않은 경우 다시 제거합니다. 편집 및 완료 단추에서 호출됩니다.
- WillBeginTableEditing – 편집 단추가 터치되면 테이블을 편집 모드로 전환하기 위해 호출
SetEditing
합니다. 그러면 테이블 끝에 '삽입 단추'로 작동하도록 (새로 추가) 행을 표시하는 WillBeginTableEditing 메서드가 트리거됩니다. - DidFinishTableEditing – 완료 단추가 터치되면
SetEditing
편집 모드를 해제하기 위해 다시 호출됩니다. 예제 코드는 편집이 더 이상 필요하지 않을 때 테이블에서 새 행을 제거합니다.
이러한 메서드 재정의는 샘플 파일 TableEditModeAdd/Code/TableSource.cs 구현됩니다.
public override UITableViewCellEditingStyle EditingStyleForRow (UITableView tableView, NSIndexPath indexPath)
{
if (tableView.Editing) {
if (indexPath.Row == tableView.NumberOfRowsInSection (0) - 1)
return UITableViewCellEditingStyle.Insert;
else
return UITableViewCellEditingStyle.Delete;
} else // not in editing mode, enable swipe-to-delete for all rows
return UITableViewCellEditingStyle.Delete;
}
public override NSIndexPath CustomizeMoveTarget (UITableView tableView, NSIndexPath sourceIndexPath, NSIndexPath proposedIndexPath)
{
var numRows = tableView.NumberOfRowsInSection (0) - 1; // less the (add new) one
if (proposedIndexPath.Row >= numRows)
return NSIndexPath.FromRowSection(numRows - 1, 0);
else
return proposedIndexPath;
}
public override bool CanMoveRow (UITableView tableView, NSIndexPath indexPath)
{
return indexPath.Row < tableView.NumberOfRowsInSection (0) - 1;
}
이러한 두 가지 사용자 지정 메서드는 테이블의 편집 모드를 사용하거나 사용하지 않도록 설정할 때 (새 추가) 행을 추가 및 제거하는 데 사용됩니다.
public void WillBeginTableEditing (UITableView tableView)
{
tableView.BeginUpdates ();
// insert the 'ADD NEW' row at the end of table display
tableView.InsertRows (new NSIndexPath[] {
NSIndexPath.FromRowSection (tableView.NumberOfRowsInSection (0), 0)
}, UITableViewRowAnimation.Fade);
// create a new item and add it to our underlying data (it is not intended to be permanent)
tableItems.Add (new TableItem ("(add new)"));
tableView.EndUpdates (); // applies the changes
}
public void DidFinishTableEditing (UITableView tableView)
{
tableView.BeginUpdates ();
// remove our 'ADD NEW' row from the underlying data
tableItems.RemoveAt ((int)tableView.NumberOfRowsInSection (0) - 1); // zero based :)
// remove the row from the table display
tableView.DeleteRows (new NSIndexPath[] { NSIndexPath.FromRowSection (tableView.NumberOfRowsInSection (0) - 1, 0) }, UITableViewRowAnimation.Fade);
tableView.EndUpdates (); // applies the changes
}
마지막으로 이 코드는 편집 및 완료 단추를 터치할 때 편집 모드를 사용하거나 사용하지 않도록 설정하는 람다를 사용하여 인스턴스화합니다.
done = new UIBarButtonItem(UIBarButtonSystemItem.Done, (s,e)=>{
table.SetEditing (false, true);
NavigationItem.RightBarButtonItem = edit;
tableSource.DidFinishTableEditing(table);
});
edit = new UIBarButtonItem(UIBarButtonSystemItem.Edit, (s,e)=>{
if (table.Editing)
table.SetEditing (false, true); // if we've half-swiped a row
tableSource.WillBeginTableEditing(table);
table.SetEditing (true, true);
NavigationItem.LeftBarButtonItem = null;
NavigationItem.RightBarButtonItem = done;
});
이 행 삽입 UI 패턴은 자주 사용되지는 않습니다. 그러나 테이블의 셀 삽입 또는 제거에 애니메이션 효과를 줄 수 있는 메서드와 EndUpdates
메서드를 사용할 UITableView.BeginUpdates
수도 있습니다. 이러한 메서드를 사용하는 규칙은 호출 간에 BeginUpdates
반환되는 값의 차이가 추가/삭제된 RowsInSection
셀의 순 번호와 EndUpdates
DeleteRows
메서드와 InsertRows
일치해야 한다는 것입니다. 기본 데이터 원본이 테이블 뷰의 삽입/삭제와 일치하도록 변경되지 않으면 오류가 발생합니다.