Xamarin.ios의 데이터로 테이블 채우기Populating a Table with Data in Xamarin.iOS

UITableView에 행을 추가 하려면 UITableViewSource 서브 클래스를 구현 하 고 테이블 뷰에서 자신을 채우기 위해 호출 하는 메서드를 재정의 해야 합니다.To add rows to a UITableView you need to implement a UITableViewSource subclass and override the methods that the table view calls to populate itself.

이 가이드에서는 다음 내용을 다룹니다.This guide covers:

  • UITableViewSource 서브클래싱Subclassing a UITableViewSource
  • 셀 다시 사용Cell Reuse
  • 인덱스 추가Adding an Index
  • 머리글 및 바닥글 추가Adding Headers and Footers

UITableViewSource 서브클래싱Subclassing UITableViewSource

UITableViewSource 서브 클래스는 모든 UITableView에 할당 됩니다.A UITableViewSource subclass is assigned to every UITableView. 원본 클래스를 쿼리하여 원본 클래스를 쿼리하여 자동으로 렌더링 하는 방법 (예: 필요한 행 수 및 기본값과 다른 경우 각 행의 높이)을 결정 합니다.The table view queries the source class to determine how to render itself (for example, how many rows are required and the height of each row if different from the default). 가장 중요 한 점은 원본에서 데이터로 채워진 각 셀 뷰를 제공 하는 것입니다.Most importantly, the source supplies each cell view populated with data.

테이블에 데이터를 표시 하는 데 필요한 두 가지 필수 메서드는 다음과 같습니다.There are only two mandatory methods required to make a table display data:

  • Rowsinsection – 테이블에 표시 해야 하는 총 데이터 행 수의 nint 수를 반환 합니다.RowsInSection – return an nint count of the total number of rows of data the table should display.
  • Getcell – 메서드에 전달 된 해당 행 인덱스의 데이터로 채워진 UITableCellView 반환 합니다.GetCell – return a UITableCellView populated with data for the corresponding row index passed to the method.

BasicTable 샘플 파일 TableSource.cs 에는 가능한 UITableViewSource구현이 가장 간단 합니다.The BasicTable sample file TableSource.cs has the simplest possible implementation of UITableViewSource. 아래 코드 조각에서 확인할 수 있습니다. 아래 코드 조각에서는 테이블에 표시 되는 문자열의 배열을 허용 하 고 각 문자열이 포함 된 기본 셀 스타일을 반환 합니다.You can see in code snippet below that it accepts an array of strings to display in the table and returns a default cell style containing each string:

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

UITableViewSource는 단순 문자열 배열 (이 예제에서 볼 수 있음)에서 > 또는 다른 컬렉션 < 목록에 모든 데이터 구조를 사용할 수 있습니다.A UITableViewSource can use any data structure, from a simple string array (as shown in this example) to a List <> or other collection. UITableViewSource 메서드를 구현 하면 테이블이 기본 데이터 구조와 격리 됩니다.The implementation of UITableViewSource methods isolates the table from the underlying data structure.

이 하위 클래스를 사용 하려면 소스를 생성 하는 문자열 배열을 만든 다음 UITableView인스턴스에 할당 합니다.To use this subclass, create a string array to construct the source then assign it to an instance of 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);
}

결과 테이블은 다음과 같습니다.The resulting table looks like this:

대부분의 테이블을 사용 하면 사용자가 행을 터치 하 여 선택 하 고 다른 작업 (예: 노래 재생, 연락처 호출 또는 다른 화면 표시)을 수행할 수 있습니다.Most tables allow the user to touch a row to select it and perform some other action (such as playing a song, or calling a contact, or showing another screen). 이를 위해서는 몇 가지 작업을 수행 해야 합니다.To achieve this, there are a few things we need to do. 먼저 RowSelected 메서드에 다음을 추가 하 여 사용자가 행을 클릭할 때 메시지를 표시 하는 AlertController를 만들어 보겠습니다.First, let's create an AlertController to display a message when the user click on a row by adding the following to the RowSelected method:

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

다음으로 보기 컨트롤러의 인스턴스를 만듭니다.Next, create an instance of our View Controller:

HomeScreen owner;

뷰 컨트롤러를 매개 변수로 사용 하 고 필드에 저장 하는 UITableViewSource 클래스에 생성자를 추가 합니다.Add a constructor to your UITableViewSource class which takes a view controller as a parameter and saves it in a field:

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

}

this 참조를 전달 하기 위해 UITableViewSource 클래스가 만들어지는 ViewDidLoad 메서드를 수정 합니다.Modify the ViewDidLoad method where the UITableViewSource class is created to pass the this reference:

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

마지막으로, RowSelected 메서드로 돌아가서 캐시 된 필드에 대 한 PresentViewController를 호출 합니다.Finally, back in your RowSelected method, call PresentViewController on the cached field:

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

    ...
}

이제 사용자가 행을 터치 할 수 있으며 경고가 표시 됩니다.Now the user can touch a row and an alert will appear:

셀 다시 사용Cell Reuse

이 예제에서는 6 개의 항목만 있으므로 셀을 다시 사용할 필요가 없습니다.In this example there are only six items, so there is no cell reuse required. 그러나 수백 또는 수천 개의 행을 표시 하는 경우 한 번에 화면에 몇 개의 UITableViewCell 개체를 만들 때 메모리가 낭비 될 수 있습니다.When displaying hundreds or thousands of rows, however, it would be a waste of memory to create hundreds or thousands of UITableViewCell objects when only a few fit on the screen at a time.

이러한 상황을 방지 하기 위해 셀이 화면에서 사라질 때 해당 뷰는 다시 사용할 수 있도록 큐에 배치 됩니다.To avoid this situation, when a cell disappears from the screen its view is placed in a queue for reuse. 사용자가 스크롤하면 테이블이 GetCell를 호출 하 여 표시 되는 새 뷰를 요청 합니다. 현재 표시 되지 않는 기존 셀을 다시 사용 하려면 DequeueReusableCell 메서드만 호출 하면 됩니다.As the user scrolls, the table calls GetCell to request new views to display – to reuse an existing cell (that is not currently being displayed) simply call the DequeueReusableCell method. 다시 사용할 수 있는 셀이 있으면 반환 됩니다. 그렇지 않으면 null이 반환 되 고 코드에서 새 셀 인스턴스를 만들어야 합니다.If a cell is available for reuse it will be returned, otherwise a null is returned and your code must create a new cell instance.

이 예제의 코드 조각은 패턴을 보여 줍니다.This snippet of code from the example demonstrates the pattern:

// 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는 여러 셀 형식에 대 한 별도의 큐를 효율적으로 만듭니다.The cellIdentifier effectively creates separate queues for different types of cell. 이 예제에서는 모든 셀이 동일 하 게 표시 되므로 하드 코드 된 식별자 하나만 사용 됩니다.In this example all the cells look the same so only one hardcoded identifier is used. 서로 다른 형식의 셀이 있는 경우 인스턴스화될 때와 다시 사용 큐에서 요청 될 때 각각 다른 식별자 문자열이 있어야 합니다.If there were different types of cell they should each have a different identifier string, both when they are instantiated and when they are requested from the reuse queue.

IOS 6 이상에서 셀 다시 사용Cell Reuse in iOS 6+

iOS 6 컬렉션 뷰를 사용 하는 것과 비슷한 셀 재사용 패턴을 추가 했습니다.iOS 6 added a cell reuse pattern similar to the one introduction with Collection Views. 위에 나와 있는 기존 재사용 패턴은 이전 버전과의 호환성을 위해 계속 지원 되지만이 새 패턴은 셀에서 null 검사를 수행 하지 않아도 되기 때문에 더 좋습니다.Although the existing reuse pattern shown above is still supported for backwards compatibility, this new pattern is preferable as it removes the need for the null check on the cell.

새 패턴을 사용 하면 응용 프로그램은 RegisterClassForCellReuse 또는 RegisterNibForCellReuse를 호출 하 여 사용할 셀 클래스 또는 xib를 컨트롤러의 생성자에 등록 합니다.With the new pattern an application registers the cell class or xib to be used by calling either RegisterClassForCellReuse or RegisterNibForCellReuse in the controller's constructor. 그런 다음 GetCell 메서드에서 셀을 큐에서 제거 하는 경우 셀 클래스 또는 xib에 대해 등록 한 식별자와 인덱스 경로를 전달 하는 DequeueReusableCell을 호출 하기만 하면 됩니다.Then, when dequeueing the cell in the GetCell method, simply call DequeueReusableCell passing the identifier you registered for the cell class or xib and the index path.

예를 들어 다음 코드는 UITableViewController에 사용자 지정 셀 클래스를 등록 합니다.For example, the following code registers a custom cell class in a UITableViewController:

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

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

MyCell 클래스가 등록 되 면 아래와 같이 추가 null 검사 없이 UITableViewSourceGetCell 메서드에서 셀을 큐에서 제거할 수 있습니다.With the MyCell class registered, the cell can be dequeued in the GetCell method of the UITableViewSource without the need for the extra null check, as shown below:

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를 사용 하는 생성자를 구현 해야 합니다. 그렇지 않은 경우에는 셀 클래스의 인스턴스를 생성할 수 없습니다.Be aware, when using the new reuse pattern with a custom cell class, you need to implement the constructor that takes an IntPtr, as shown in the snippet below, otherwise Objective-C won't be able to construct an instance of the cell class:

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

이 문서에 연결 된 Basictable 샘플에서 위에 설명 된 항목의 예를 볼 수 있습니다.You can see examples of the topics explained above in the BasicTable sample linked to this article.

인덱스 추가Adding an Index

인덱스를 사용 하면 사용자가 원하는 조건에 따라 인덱싱할 수 있지만 일반적으로 사전순으로 정렬 된 긴 목록을 스크롤할 수 있습니다.An index helps the user scroll through long lists, typically ordered alphabetically although you can index by whatever criteria you wish. Basictableindex 예제는 인덱스를 보여 주기 위해 파일에서 훨씬 긴 항목 목록을 로드 합니다.The BasicTableIndex sample loads a much longer list of items from a file to demonstrate the index. 인덱스의 각 항목은 테이블의 ' section '에 해당 합니다.Each item in the index corresponds to a ‘section’ of the table.

' 섹션 '을 지원 하려면 테이블 뒤의 데이터를 그룹화 해야 하므로 BasicTableIndex 샘플은 각 항목의 첫 문자를 사전 키로 사용 하 여 문자열 배열에서 Dictionary<>를 만듭니다.To support ‘sections’ the data behind the table needs to be grouped, so the BasicTableIndex sample creates a Dictionary<> from the array of strings using the first letter of each item as the dictionary key:

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<>을 사용 하기 위해 다음 메서드를 추가 하거나 수정 해야 합니다.The UITableViewSource subclass then needs the following methods added or modified to use the Dictionary<> :

  • Numberofsections –이 메서드는 선택 사항이 며 기본적으로 테이블은 하나의 섹션을 가정 합니다.NumberOfSections – this method is optional, by default the table assumes one section. 인덱스를 표시 하는 경우이 메서드는 인덱스의 항목 수를 반환 해야 합니다. 예를 들어 인덱스에 영어 알파벳의 모든 문자가 포함 된 경우에는 26입니다.When displaying an index this method should return the number of items in the index (for example, 26 if the index contains all the letters of the English alphabet).
  • Rowsinsection – 지정 된 섹션의 행 수를 반환 합니다.RowsInSection – returns the number of rows in a given section.
  • 섹션 Indextitles – 인덱스를 표시 하는 데 사용 되는 문자열의 배열을 반환 합니다.SectionIndexTitles – returns the array of strings that will be used to display the index. 샘플 코드는 문자 배열을 반환 합니다.The sample code returns an array of letters.

샘플 파일 Basictableindex/Tableource. cs 의 업데이트 된 메서드는 다음과 같습니다.The updated methods in the sample file BasicTableIndex/TableSource.cs look like this:

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

인덱스는 일반적으로 일반 테이블 스타일 에서만 사용 됩니다.Indexes are generally only used with the Plain table style.

머리글 및 바닥글 추가Adding Headers and Footers

머리글 및 바닥글을 사용 하 여 테이블의 행을 시각적으로 그룹화 할 수 있습니다.Headers and footers can be used to visually group rows in a table. 필요한 데이터 구조는 인덱스를 추가 하는 것과 매우 유사 합니다. Dictionary<>은 매우 잘 작동 합니다.The data structure required is very similar to adding an index – a Dictionary<> works really well. 이 예에서는 알파벳을 사용 하 여 셀을 그룹화 하는 대신 야채 by 섬의 형식을 그룹화 합니다.Instead of using the alphabet to group the cells, this example will group the vegetables by botanical type. 출력은 다음과 같습니다.The output looks like this:

헤더 및 바닥글을 표시 하려면 UITableViewSource 하위 클래스에 다음과 같은 추가 방법이 필요 합니다.To display headers and footers the UITableViewSource subclass requires these additional methods:

  • TitleForHeader – 헤더로 사용할 텍스트를 반환 합니다.TitleForHeader – returns the text to use as the header
  • TitleForFooter – 바닥글로 사용할 텍스트를 반환 합니다.TitleForFooter – returns the text to use as the footer.

샘플 파일 Basictableheaderfooter/Code/Tableource. cs 의 업데이트 된 메서드는 다음과 같습니다.The updated methods in the sample file BasicTableHeaderFooter/Code/TableSource.cs look like this:

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

UITableViewSource에서 GetViewForHeaderGetViewForFooter 메서드 재정의를 사용 하 여 뷰 개체를 사용 하 여 머리글 및 바닥글의 모양을 사용자 지정할 수 있습니다.You can further customize the appearance of the header and footer with a View object, using the GetViewForHeader and GetViewForFooter method overrides on UITableViewSource.