Xamarin.iOS에서 데이터로 테이블 채우기

행을 UITableView 추가하려면 하위 클래스를 UITableViewSource 구현하고 테이블 뷰에서 자체 채우기 위해 호출하는 메서드를 재정의해야 합니다.

이 가이드에서는 다음을 다룹니다.

  • UITableViewSource 서브클래싱
  • 셀 재사용
  • 인덱스 추가
  • 머리글 및 바닥글 추가

서브클래싱 UITableViewSource

UITableViewSource 하위 클래스는 모든 UITableView에 할당됩니다. 테이블 뷰는 원본 클래스를 쿼리하여 자체 렌더링 방법을 결정합니다(예: 필요한 행 수 및 기본값과 다른 경우 각 행의 높이). 가장 중요한 것은 원본이 데이터로 채워진 각 셀 뷰를 제공합니다.

테이블 표시 데이터를 만드는 데 필요한 필수 메서드는 두 가지뿐입니다.

  • RowsInSection – 테이블이 표시해야 하는 총 데이터 행 수를 반환 nint 합니다.
  • GetCell – 메서드에 UITableViewCell 전달된 해당 행 인덱스 데이터로 채워진 값을 반환합니다.

BasicTable 샘플 파일 TableSource.cs 가능한 가장 간단한 구현이 있습니다 UITableViewSource. 아래 코드 조각에서는 표에 표시할 문자열 배열을 허용하고 각 문자열을 포함하는 기본 셀 스타일을 반환한다는 것을 확인할 수 있습니다.

public class TableSource : UITableViewSource {

        string[] TableItems;
        string CellIdentifier = "TableCell";

        public TableSource (string[] items)
        {
            TableItems = items;
        }

        public override nint RowsInSection (UITableView tableview, nint section)
        {
            return TableItems.Length;
        }

        public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
        {
            UITableViewCell cell = tableView.DequeueReusableCell (CellIdentifier);
            string item = TableItems[indexPath.Row];

            //if there are no cells to reuse, create a new one
            if (cell == null)
            {
                cell = new UITableViewCell (UITableViewCellStyle.Default, CellIdentifier);
            }

            cell.TextLabel.Text = item;

            return cell;
        }
}

A는 UITableViewSource 간단한 문자열 배열(이 예제와 같이)에서 List <> 또는 기타 컬렉션에 이르기까지 모든 데이터 구조를 사용할 수 있습니다. 메서드의 UITableViewSource 구현은 기본 데이터 구조에서 테이블을 격리합니다.

이 하위 클래스를 사용하려면 문자열 배열을 만들어 원본을 생성한 다음 다음 인스턴스 UITableView에 할당합니다.

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();
    table = new UITableView(View.Bounds); // defaults to Plain style
    string[] tableItems = new string[] {"Vegetables","Fruits","Flower Buds","Legumes","Bulbs","Tubers"};
    table.Source = new TableSource(tableItems);
    Add (table);
}

결과 테이블은 다음과 같습니다.

실행 중인 샘플 테이블

대부분의 테이블을 통해 사용자는 행을 터치하여 이를 선택하고 다른 작업(예: 노래 재생, 연락처 호출 또는 다른 화면 표시)을 수행할 수 있습니다. 이를 위해 몇 가지 작업을 수행해야 합니다. 먼저 사용자가 메서드에 다음을 추가하여 행을 클릭할 때 메시지를 표시하는 AlertController를 RowSelected 만들어 보겠습니다.

public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
    UIAlertController okAlertController = UIAlertController.Create ("Row Selected", tableItems[indexPath.Row], UIAlertControllerStyle.Alert);
    okAlertController.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
    ...

    tableView.DeselectRow (indexPath, true);
}

다음으로 뷰 컨트롤러의 인스턴스를 만듭니다.

HomeScreen owner;

뷰 컨트롤러를 매개 변수로 사용하여 필드에 저장하는 생성자를 UITableViewSource 클래스에 추가합니다.

public TableSource (string[] items, HomeScreen owner)
{
    ...
    this.owner = owner;

}

참조를 전달하기 위해 UITableViewSource 클래스가 만들어지는 ViewDidLoad 메서드를 this 수정합니다.

table.Source = new TableSource(tableItems, this);

마지막으로 메서드로 RowSelected 돌아가서 캐시된 필드를 호출 PresentViewController 합니다.

public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
    ...
    owner.PresentViewController (okAlertController, true, null);

    ...
}

이제 사용자가 행을 터치할 수 있으며 경고가 표시됩니다.

선택한 행 경고

셀 재사용

이 예제에는 6개의 항목만 있으므로 셀 재사용이 필요하지 않습니다. 그러나 수백 또는 수천 개의 행을 표시할 때 한 번에 몇 개만 화면에 맞을 때 수백 또는 수천 UITableViewCell 개의 개체를 만드는 것은 메모리 낭비입니다.

이 상황을 방지하기 위해 화면에서 셀이 사라지면 해당 보기가 재사용을 위해 큐에 배치됩니다. 사용자가 스크롤할 때 표는 표시할 새 보기를 요청하기 위해 호출 GetCell 합니다. 기존 셀(현재 표시되지 않음)을 다시 사용하기 위해 메서드를 호출 DequeueReusableCell 하기만 하면 됩니다. 다시 사용할 수 있는 셀이 반환되면 null이 반환되고 코드에서 새 셀 인스턴스를 만들어야 합니다.

이 예제의 코드 조각은 패턴을 보여 줍니다.

// request a recycled cell to save memory
UITableViewCell cell = tableView.DequeueReusableCell (cellIdentifier);
// if there are no cells to reuse, create a new one
if (cell == null)
    cell = new UITableViewCell (UITableViewCellStyle.Default, cellIdentifier);

서로 cellIdentifier 다른 유형의 셀에 대해 별도의 큐를 효과적으로 만듭니다. 이 예제에서는 모든 셀이 동일하게 표시되므로 하드 코드된 식별자 하나만 사용됩니다. 다른 유형의 셀이 있는 경우 인스턴스화될 때와 재사용 큐에서 요청될 때 각각 다른 식별자 문자열이 있어야 합니다.

iOS 6 이상에서 셀 재사용

iOS 6은 컬렉션 뷰의 소개와 유사한 셀 재사용 패턴을 추가했습니다. 위에 표시된 기존 재사용 패턴은 이전 버전과의 호환성을 위해 계속 지원되지만 이 새 패턴은 셀에서 null 검사 대한 필요성을 제거하므로 바람직합니다.

새 패턴을 사용하면 애플리케이션이 컨트롤러의 생성자 중 하나 RegisterClassForCellReuse 또는 생성자를 호출하여 사용할 셀 클래스 또는 RegisterNibForCellReuse xib를 등록합니다. 그런 다음 메서드에서 셀을 큐에서 GetCell 제거하는 경우 셀 클래스 또는 xib 및 인덱스 경로에 대해 등록한 식별자 전달을 호출 DequeueReusableCell 하기만 하면 됩니다.

예를 들어 다음 코드는 UITableViewController에 사용자 지정 셀 클래스를 등록합니다.

public class MyTableViewController : UITableViewController
{
  static NSString MyCellId = new NSString ("MyCellId");

  public MyTableViewController ()
  {
    TableView.RegisterClassForCellReuse (typeof(MyCell), MyCellId);
  }
  ...
}

MyCell 클래스를 등록하면 아래와 같이 추가 null 검사 필요 없이 셀을 UITableViewSource 메서드에서 큐에서 GetCell 제거할 수 있습니다.

class MyTableSource : UITableViewSource
{
  public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
  {
    // if cell is not available in reuse pool, iOS will create one automatically
    // no need to do null check and create cell manually
    var cell = (MyCell) tableView.DequeueReusableCell (MyCellId, indexPath);

    // do whatever you need to with cell, such as assigning properties, etc.

    return cell;
  }
}

사용자 지정 셀 클래스와 함께 새 재사용 패턴을 사용하는 경우 아래 코드 조각에 표시된 것처럼 해당 생성자를 IntPtr구현해야 합니다. 그렇지 않으면 Objective-C 셀 클래스의 인스턴스를 생성할 수 없습니다.

public class MyCell : UITableViewCell
{
  public MyCell (IntPtr p):base(p)
  {
  }
  ...
}

이 문서에 연결된 BasicTable 샘플에서 위에서 설명한 항목의 예를 볼 수 있습니다 .

인덱스 추가

인덱스가 있으면 사용자가 원하는 기준으로 인덱싱할 수 있지만 일반적으로 사전순으로 정렬된 긴 목록을 스크롤할 수 있습니다. BasicTableIndex 샘플은 파일에서 훨씬 더 긴 항목 목록을 로드하여 인덱스를 보여 줍니다. 인덱스의 각 항목은 테이블의 '섹션'에 해당합니다.

인덱스 표시

'섹션'을 지원하려면 테이블 뒤의 데이터를 그룹화해야 하므로 BasicTableIndex 샘플은 각 항목의 첫 글자를 사전 키로 사용하여 문자열 배열에서 만듭니다 Dictionary<> .

indexedTableItems = new Dictionary<string, List<string>>();
foreach (var t in items) {
    if (indexedTableItems.ContainsKey (t[0].ToString ())) {
        indexedTableItems[t[0].ToString ()].Add(t);
    } else {
        indexedTableItems.Add (t[0].ToString (), new List<string>() {t});
    }
}
keys = indexedTableItems.Keys.ToArray ();

UITableViewSource 그런 다음 서브클래스를 사용 Dictionary<> 하려면 다음 메서드를 추가하거나 수정해야 합니다.

  • NumberOfSections – 이 메서드는 선택 사항이며 기본적으로 테이블은 하나의 섹션을 가정합니다. 인덱스를 표시할 때 이 메서드는 인덱스의 항목 수를 반환해야 합니다(예: 인덱스에 영어 알파벳의 모든 문자가 포함된 경우 26).
  • RowsInSection – 지정된 섹션의 행 수를 반환합니다.
  • SectionIndexTitles – 인덱스를 표시하는 데 사용할 문자열 배열을 반환합니다. 샘플 코드는 문자 배열을 반환합니다.

샘플 파일 BasicTableIndex/TableSource.cs 업데이트된 메서드는 다음과 같습니다.

public override nint NumberOfSections (UITableView tableView)
{
    return keys.Length;
}
public override nint RowsInSection (UITableView tableview, nint section)
{
    return indexedTableItems[keys[section]].Count;
}
public override string[] SectionIndexTitles (UITableView tableView)
{
    return keys;
}

인덱스는 일반적으로 일반 테이블 스타일에만 사용됩니다.

머리글 및 바닥글 추가

머리글 및 바닥글을 사용하여 테이블의 행을 시각적으로 그룹화할 수 있습니다. 필요한 데이터 구조는 인덱 Dictionary<> 스 추가와 매우 유사합니다. 이 예제에서는 알파벳을 사용하여 셀을 그룹화하는 대신 식물 유형별로 채소를 그룹화합니다. 출력은 다음과 같습니다.

샘플 머리글 및 바닥글

머리글 및 바닥글을 표시하려면 하위 클래스에 UITableViewSource 다음 추가 메서드가 필요합니다.

  • TitleForHeader – 머리글로 사용할 텍스트를 반환합니다.
  • TitleForFooter – 바닥글로 사용할 텍스트를 반환합니다.

샘플 파일 BasicTableHeaderFooter/Code/TableSource.cs 업데이트된 메서드는 다음과 같습니다.

public override string TitleForHeader (UITableView tableView, nint section)
{
    return keys[section];
}
public override string TitleForFooter (UITableView tableView, nint section)
{
    return indexedTableItems[keys[section]].Count + " items";
}

에 대한 및 메서드 재정의를 사용하여 View 개체를 사용하여 머리글 및 GetViewForFooter 바닥글의 GetViewForHeader 모양을 추가로 사용자 지정할 수 있습니다UITableViewSource.