See Also: UITableView Members
UIKit.UITableView is a subclass of UIKit.UIScrollView that allows users to scroll the table vertically (the closely-related UIKit.UICollectionView class allows for horizontal scrolling and complex two-dimensional layouts). The table consists of UIKit.UITableViewCell objects that are used to render the rows of the table. These cells have content -- labels, images, etc. -- and can also show accessories such as disclosure arrows or inputs controls. UIKit.UITableViews can enter an edit-mode in which rows can be inserted, deleted, and reordered.
The Xamarin article Working with Tables provides guidance on all aspects of UIKit.UITableView use.
For most use-cases, it is not necessary for application developers to subclass UIKit.UITableView or UIKit.UITableViewController, which provide the generic table behavior. Instead, application developers will generally subclass UIKit.UITableViewSource to populate a table and, often, UIKit.UITableViewCell to customize appearance and row behavior.
The primary classes used to display table views are:
Class | Responsibility |
---|---|
UIKit.UITableView | A view that contains a collection of cells inside a scrolling container. The table view typically uses the entire screen in an iPhone app but may exist as part of a larger view on the iPad (or appear in a popover). |
UIKit.UITableViewCell | A view that represents a single cell (or row) in a table view. There are four built-in cell types and it is possible to create custom cells both in C# or with Interface Builder. |
UIKit.UITableViewSource | Xamarin.iOS-exclusive abstract class that provides all the methods required to display a table, including row count, returning a cell view for each row, handling row selection and many other optional features. You must subclass this to get a UIKit.UITableView working. (UIKit.UITableViewSource combines UIKit.UITableViewDataSource and UIKit.UITableViewDelegate. These classes are still available if the application developer chooses not to use UIKit.UITableViewSource.) |
Foundation.NSIndexPath | Contains Row and Section properties that uniquely identify the position of a cell in a table. |
UIKit.UITableViewController | A ready-to-use UIKit.UIViewController that has a UIKit.UITableView hardcoded as its view and made accessible via the UITableViewController.TableView property. |
UIKit.UIViewController | If the table does not occupy the entire screen you can add a UIKit.UITableView to any UIKit.UIViewController with its UIView.Frame property set appropriately. |
There are two UIKit.UITableViewStyle styles: Plain and Grouped. The Plain style allows the section headers and footers to remain visible as the section is scrolled through, and can optionally support an index that appears along the right edge to quickly scroll to a specific section. The Grouped style displays sections in rounded-rectangles that visually group the rows, and provides a default background image behind the scrolling list. The style of the UIKit.UITableView is specified as an argument to the UITableView(System.Drawing.RectangleF, UITableViewStyle) constructor and cannot be changed. Grouped tables should not provide an index.
Tables consist of the following parts:
Element | Accessed via: | Type |
---|---|---|
Table Header | UITableView.TableHeaderView | UIKit.UIView |
Section Header | UITableViewSource.GetViewForHeader | UIKit.UITableViewHeaderFooterView |
Cells (also called Rows) | UITableViewSource.GetCell | UIKit.UITableViewCell |
Section Footer | UITableViewSource.GetViewForFooter | UIKit.UITableViewHeaderFooterView |
Index | UITableViewSource.SectionIndexTitles | string[] |
Edit mode (includes ‘swipe to delete’ and drag handles to change row order) | ||
Table Footer | UITableView.TableFooterView | UIKit.UIView |
Section rows, headers, footers, edit controls and the index are displayed as follows:
UIKit.UITableViews are designed to work efficiently with tables with thousands of rows. In order to achieve this, each UIKit.UITableView maintains a reusable cache of UIKit.UITableViewCells only a few items larger than can be shown on the screen at any given time.
A UIKit.UITableViewSource object is responsible for managing the relationship between the relatively few UIKit.UITableViewCells and the data is to be displayed. The UIKit.UITableViewSource's UITableViewSource.NumberOfSections and UITableViewSource.RowsInSection methods allow the UIKit.UITableView to request only the data necessary for the cells on the screen. A specific cell is identified by an Foundation.NSIndexPath, whose Foundation.NSIndexPath.Section and Foundation.NSIndexPath.Rowproperties will specify a unique cell.
As cells are about to be scrolled onto the screen, the UIKit.UITableView automatically calls the UITableViewSource.GetCell method of the UIKit.UITableViewSource object assigned to the UITableView.Source property of the UIKit.UITableView (or, if the application developer prefers, the UITableViewDataSource.GetRow method of the UIKit.UITableViewDataSource object referred to by the UITableView.DataSource property).
The application developer's responsibilities when overriding UITableViewSource.GetCell changed with the introduction of iOS 6. Application developers targeting iOS 6 and later should register a UIKit.UITableViewCell for reuse with the UIKit.UITableView by calling either the UITableView.RegisterClassForCellReuse or UITableView.RegisterNibForCellReuse method. Once that is done, application developers do not need to check for null in their override of the UITableViewSource.GetCell method.
If application developers are using the UITableView.RegisterClassForCellReuse with their own subclass of UIKit.UITableViewCell, that implementation must override the UITableViewCell(IntPtr) constructor and call the base constructor (i.e., MyTableViewCell(IntPtr handle) : base(handle){}).
The application developer overrides the UITableViewSource.GetCell method so that it:
Since the UITableViewSource.GetCell method will be called whenever a cell comes into view, application developers should avoid unnecessary computation.
The UIKit.UITableView's reuse queue is accessed via the UITableView.DequeueReusableCell method, which takes a string identifying the type of UIKit.UITableViewCell to retrieve. In iOS 5 and earlier, that method may return null, in which case the application developer should instantiate a new UIKit.UITableViewCell. In iOS 6 and later, while initializing the UIKit.UITableView, the application developer must use either UITableView.RegisterClassForCellReuse or UITableView.RegisterNibForCellReuse to associate a UIKit.UITableViewCell type and it's reuse identifier so that the method UITableViewSource.GetCell can instantiate instances as necessary.
The following shows a simple example of the UITableViewSource.GetCell method:
C# Example
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath) { //Attempt to retrieve previously-allocated cell var cell = tableView.DequeueReusableCell (this.cellTypeIdentifier); //The following check and code-block only necessary in applications that do not use RegisterClassforCellReuse or RegisterNibForCellReuse if (cell == null) { //No reusable cell, so initialize a new one cell = new UITableViewCell (UITableViewCellStyle.Default, this.cellTypeIdentifier); cell.Tag = Environment.TickCount; } // Change the state of the cell cell.TextLabel.Text = //...etc... // return the cell return cell; }
Other than the UITableView.Style property that specifies whether a UIKit.UITableView is grouped or continuous, the appearance of the table is primarily determined by the UIKit.UITableViewCells, the UIKit.UITableViewHeaderFooterViews used for section headers and footers, and the UIKit.UIViews used for the UITableView.Header and UITableView.Footer properties. The API documentation for UIKit.UITableViewCell describes customization in detail.
Selecting and highlighting in a UIKit.UITableView follows this sequence:
User Action | UITableViewDelegate (UITableViewSource) Methods | UITableViewCell Properties |
---|---|---|
Nothing touched | Highlighted == false; Selected == false | |
Finger down in cell | UITableViewDelegate.ShouldHighlightRow is called. If it returns false, processing stops. | |
UITableViewSource.RowHighlighted is called. | Highlighted == true; Selected == false | |
Finger up | UITableViewDelegate.WillSelectRow is called. If it returns null, processing stops. Otherwise, whatever Foundation.NSIndexPath it returns will be highlighted. | |
UITableViewDelegate.RowSelected is called. UITableViewDelegate.RowUnhighlighted is called. | Highlighted == false; Selected == true |
Deselecting a UIKit.UITableViewCell follows a similar sequence:
User Action | UITableViewDelegate (UITableViewSource) Methods | UITableViewCell Properties |
---|---|---|
Nothing touched while some UIKit.UITableViewCell is highlighted. | Highlighted == false; Selected == true | |
Finger taps cell (Deselect gesture) | UITableViewDelegate.WillDeselectRow is called. If it returns null, processing stops. Otherwise, whatever Foundation.NSIndexPath is returned will be deselected. | |
UITableViewDelegate.RowDeselected is called. | Highlighted == false; Selected == false |
UITableView caches UIKit.UITableViewCell objects only for visible rows, but caches the heights of rows, headers and footers for the entire table. It is possible to create custom UIKit.UITableViewCell objects with varying heights and custom layouts.
UITableView overrides UIView.LayoutSubviews() so that it calls UITableView.ReloadData only when you create a new instance or when you assign a new UITableView.Source (or UITableView.DataSource).Reloading the table view clears current state (including the current selection). However if you explicitly call UITableView.ReloadData() it clears this state and any subsequent direct or indirect call to UIView.LayoutSubviews() does not trigger a reload.