UserGuide

iOS Table

From Xojo Documentation

Revision as of 15:12, 8 February 2019 by PLefebvre (talk | contribs) (Using a Data Source)

A Table is used to display lists of data. Tables can display information in sections, can have "accessories" to indicate that more information is available. Each row of a Table can display images and up to 2 lines of text. In addition you can customize the rows of a table to show pretty much whatever you want.

Below is a list of commonly used events, properties and methods. Refer to iOSTable in the Language Reference for the complete list.

Events

AccessoryAction

Called when the Detail accessory for a row is tapped.

Action

Called when a row is selected. You are provided the section and row that was tapped.

ActionsForRow

Use this event to set up any row actions that are available for the row.

Refreshed

Called when the user initiates a "pull-to-refresh" action.

RowAction

Called when a row action has been selected.

RowEditingStyle

Indicates the editing style for the row when the table is put into edit mode.

Properties

AllowRefresh

Enable usage of the "pull-to-refresh" action for the table.

DataSource

Use this configure a Table to gets its data from a data source class rather than populating it using the methods.

EditingEnabled

Indicates the table is currently in edit mode.

Format

Indicates how the table is displayed. There are two choices: Plain and Grouped.

SectionCount

The number of sections in the Table. Use this in conjunction with the various methods to get row counts and other information about the table.

Visible

A boolean that indicates if the Table is visible when your app runs.

Methods

AddRow, InsertRow

Adds new rows to the end or inserts rows at a specific position of the table.

AddSection, InsertSection

Add new sections to the end or inserts sections at a specific position of the table.

CreateCell

Creates new cells (of type iOSTableCellData) to display in the table.

CreateCustomCell

Creates new custom cells that are made using iOSCustomTableCell.

ReloadData, ReloadDataInSection, ReloadRow

Reloads all the data in the table, just the data for a specific section or a single row.

RemoveAll, RemoveRow, RemoveSection

Removes all rows in the table, a single row in a section or an entire section.

RowCount

The count of rows in the specified section.

RowData

Returns an instance of iOSTableCellData that contains all the information about a row in a section.

SectionTitle

Gets or sets the title of a section.

Cell Data

When working with a Table, you will need to manage its rows. The class iOSTableCellData contains information about a row in a table. To populate a table manually, you can create instances of iOSTableCellData (using iOSTable.CreateCell), set its properties and then add it to the Table. Or you can add rows using just a subset of values manually.

Use the RowData method to get the iOSTableCellData for a specific row, which you can then use or modify to change what is displayed.

Below are commonly used properties. Refer to iOSTableCellData in the Language Reference for the complete list.

Properties

AccessoryType

The type of (optional) accessory to display for the row. This uses the AccessoryTypes enumeration to choose the type of accessory: None, Disclosure, Detail, Checkmark.

DetailText

The Detail Text is smaller text that displays below the main text for the row.

Image

When an image is specified, it appears in front of the row Text.

Tag

The Tag is an Auto that can be used to store any useful, related information about the cell for retrieval later (such as a primary key to a database or an instance of a class containing additional information).

Text

The main text that is displayed for the cell row.

Data Source

Although you can directly add rows to a Table using the AddRow methods, this is only practical for when there are a small number of rows. When you have 50 or more rows in the table you should consider using a Data Source to provide the data for the table to display. This makes much better use of the resources available on iOS.

iOSTableDataSource is an Interface that you implement on a class that will provide the data to the Table. The table is then populated by the class so you do not have to use the Add/Insert methods.

These are the methods of the interface that have to be implemented in a class:

RowCount

Returns the number of the rows in the specified section.

RowData

This method is used to create the iOSTableCellData for the specified section and row.

SectionCount

Returns the total number of sections.

SectionTitle

Returns the title for the specified section.

Usage

Starting simply, you can manually add rows to a table. A table always has to have at least one section, even if you don't display it. So at a minimum, you would have code like this to add a row to the first section:

Table1.AddSection("")
Table1.AddRow(0, "First Row")

Using this version of the AddRow method only lets you provide the text for the row. If you need to set other row values, such as the DetailText or an Image, you will need to first create an iOSTableCellData, set its properties and then add it to the Table:

Dim cell As iOSTableCellData
cell = Table1.CreateCell
cell.Text = "Product Name"
cell.DetailText = "Product Details"
cell.Image = ProductImage
Table1.AddRow(0, cell)

Insert works the same as Add but has an additional paramter to specify the row position (0-based) within the section for the newly inserted row.

Using these methods, you can populate a table by looping through the data. For example, if you have an array of customer names, you can loop through them and populate the Table like this:

Table1.RemoveAll

Table1.AddSection("") // add heading for first letter of name
For i As Integer = 0 To CustomerNames.UBound
Table1.AddRow(0, CustomerNames(i))
Next

To add rows with accessories, you have to use iOSTableCellData because that is where the AccessoryType property is. This code adds rows to a table and sets the accessory to a checkmark:

Dim cellData As iOSTableCellData

Table1.AddSection("")
For i As Integer = 0 To 50
cellData = Table1.CreateCell
cellData.Text = "Line " + i.ToText
cellData.AccessoryType = iOSTableCellData.AccessoryTypes.Checkmark

Table1.AddRow(0, cellData)
Next

To toggle the checkmark on and off when the cell is tapped, you can put this code in the Table's Action event handler:

Dim cell As iOSTableCellData
cell = Me.RowData(section, row)

If cell.AccessoryType = iOSTableCellData.AccessoryTypes.Checkmark Then
cell.AccessoryType = iOSTableCellData.AccessoryTypes.None
Me.ReloadRow(section, row)
Else
cell.AccessoryType = iOSTableCellData.AccessoryTypes.Checkmark
Me.ReloadRow(section, row)
End If

This code gets the selected cell and tests if the accessory is a checkmark. If it is, then it sets the accessory to None. If there is no accessory, then it sets it to a checkmark. It then reloads the changed row to show the change to the accessory.

The AccessoryTypes enumeration has other accessories you can use instead: Disclosure, Detail and None. The default for cells is None.

If you use an AccessoryType of Detail then tapping the detail indicator calls the Table's AccessoryAction event. In this event you can put the code that performs an accessory-specific action, which is typically to display a new View with additional details. One technique is to have the additional details stored in the Tag of the cell so that you can get it to send to the new View like this:

Dim details As New DetailView
details.ApplyData(Me.RowData(section, row).Tag)
PushTo(details)

The RowData method is used to get the details of a cell for a specific row. You can then use the data or you can modify it to change what is displayed. After modifying cell data, you'll need to reload the row (or rows) that were modified. This Action event code changes the text of a row that was tapped:

Dim cell As iOSTableCellData
cell = Me.RowData(section, row)
cell.DetailText = "This row was tapped."
Me.ReloadRow(section, row)

To display an image you also have to use iOSTableCellData. This adds a row using an image from the project:

Dim cell As iOSTableCellData
cell = Table1.CreateCell
cell.Image = Product1Image
cell.Text = "Product 1"
Table1.AddRow(0, cell)

Sections can be used to provide ways to group the displayed data. One example might be to group a list of names by the first character of their name. So all names that start with "D" would be in their own group. Assuming you have an array of names, you can sort the array and then populate the Table, creating a new group when the first letter of the name changes:

Dim names() As Text = Array("Anna", "Andy", "Bob", "Chris", "Chuck", "Dave", "Ed", _
"Fred", "Greg", "Harry", "Henry")

Dim lastSectionTitle As Text
Dim sectionNum As Integer
For i As Integer = 0 To names.Ubound
If names(i).Left(1) <> lastSectionTitle Then
lastSectionTitle = names(i).Left(1)
sectionNum = Table1.AddSection(lastSectionTitle)
End If
Table1.AddRow(sectionNum, names(i))
Next

Using a Data Source

In each of the above examples, the Table was populated manually using the various Add methods. Another way you can populate a Table is by using a class that implements the iOSTableDataSource interface as the DataSource. The class is then responsible for getting the data and returning it using the methods provided by the iOSTableDataSource interface. This is a bit more work to set up, but does provide a noticable performance boost for large numbers of rows and it's a nice separation of the Table UI and its data. The class you create can get the data from anywhere. It could have its data built-in, it could fetch data from a file, the Internet or a database.

To use a DataSource, you need to create a class that implements the iOSTableDataSource interface (refer to the UserGuide:Interfaces section if you need to re-familiarize yourself with this). In your class, you have to implement the four interface methods: RowCount, RowData, SectionCount and SectionTitle.

As an exercise, this is how you would create a Data Source class to populate the names in a section as shown previously.

First, create a new class called "NamesData" and set add the iOSTableDataSource interface to it. In this new class, add two properties:

Names() As Text
SectionNames() As Text

Add a Constructor to the class and add the code to initialize these properties:

Names = Array("Anna", "Andy", "Bob", "Chris", "Chuck", "Dave", "Ed", _
"Fred", "Greg", "Harry", "Henry")

Dim lastSectionTitle As Text
Dim sectionNum As Integer
For i As Integer = 0 To names.Ubound
If Names(i).Left(1) <> lastSectionTitle Then
lastSectionTitle = Names(i).Left(1)
SectionNames.Append(Names(i).Left(1))
End If
Next

Now you can add the code to the four methods to return the correct information.

This is the code for the SectionCount method:

Return SectionNames.Ubound + 1

This is the code for the SectionTitle method:

Return SectionNames(section)

This is the code for the RowCount method:

// Count the items in the array that start with the character
// of the specified section.
Dim count As Integer
For i As Integer = 0 To Names.Ubound
If Names(i).Left(1) = SectionNames(section) Then
count = count + 1
End If
Next

Return count

This is the code for the RowData method:

// Find the appropriate item in the array
Dim lookupRow As Integer
For i As Integer = 0 To Names.Ubound
If Names(i).Left(1) = SectionNames(section) Then
// Found the start of this section, which now
// serves as an offset into the array.
lookupRow = i
Exit For
End If
Next

Dim cell As New iOSTableCellData
cell.Text = Names(lookupRow + row)

Return cell

This sets up the Data Source. Yes, it is a bit more complicated, but it eliminates the need for any code on the View to populate the Table and it will be much faster when there are a lot of rows. To set up the Table, go to View1 and add a Table (Table1). Also add a property:

Names As NamesData

In the Open event handler for the View, create a new instance of NamesData and assign it to the DataSource for the Table:

Names = New NamesData
Table1.DataSource = Names

You may be wondering why it is necessary to have the Names property to store the NamesData instance. This is so that the instance does not go out of scope, preventing its data from being loaded into the table.

Now when the table is displayed, it will request only the rows that need to be shown from the data source.

See Also

iOSTable, iOSTableCellData, iOSCustomTableCell, iOSTableRowAction classes; iOSTableDataSource, iOSTableDataSourceEditing, iOSTableDataSourceReordering interfaces; UserGuide:iOS UI topic