iOS Mobile Table

From Xojo Documentation

Revision as of 19:25, 20 February 2019 by PLefebvre (talk | contribs) (More Loading Data From 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.

If you have created desktop or web projects, you can think of an iOS Table as analogous to a single-column ListBox. An iOS Table can have a single column (called a cell) that contains a main line of text and optional smaller detail text underneath it. It can also have an image that displays in front of the cell. For more sophisticated display you can also create your own custom table cells to display almost anything you want, including multiple columns and controls.

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



Called when the Detail accessory for a row is tapped.


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


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


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


Called when a row action has been selected.


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



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


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


Indicates the table is currently in edit mode.


iOS Table Sections Plain Style
iOS Table Sections Grouped Style
Indicates how the table is displayed. There are two choices: Plain and Grouped.


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.


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


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.


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


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.


The count of rows in the specified section.


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


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.



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.


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


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


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).


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:


Returns the number of the rows in the specified section.


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


Returns the total number of sections.


Returns the title for the specified section.


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.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.AddSection("") // add heading for first letter of name
For i As Integer = 0 To CustomerNames.UBound
Table1.AddRow(0, CustomerNames(i))
iOS Table Showing Checkmark Accessory

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

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

Table1.AddRow(0, cellData)

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

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

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.

iOS Table Names in Sections

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)
End If

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

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

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.

Loading Data Manually

Loading data manually means that you are creating the sections and rows yourself to supply the data for the table. Before you can add any row to an iOSTable, it must first have a section. Sections provide a way for the data to appear in groups. As an example, if you look at the Contacts app in iOS you'll see that there are sections for each letter of the alphabet and the contacts are grouped by the letter they start with.

In its simplest form, you may not want to show any sections so you can just add an empty section:


Once you have added a section, you can add the rows using the AddRow method. This method requires that you tell it the section, which is why you must have a section to start with. Sections are 0-based so the first section is 0. This adds 50 rows to the table:


For i As Integer = 1 To 50
ExampleTable.AddRow(0, "Line " + i.ToText)

Example Project: iOS/Controls/Table/SimpleTableExample

More Loading Data From a Data Source

Baseball Teams Shown in an iOS Table Using a Data Source

Although loading data manually using the AddRow method is quick and easy, performance can really start to suffer once a lot ( > 100) of rows have been added. So in most cases you are going to want to use a separate data source to provide the data for the table to display. To provide a data source, you create a class that implements the iOSTableDataSource interface and then use its methods to provide data from whatever your source of data is. This data can be in a file, a database, text or anything else you want.

The example below displays MLB teams using a data source.

The first thing to do is to create a new class (named BaseballTeams). In the Inspector, click the Choose button for the Interfaces property and select the iOSTableDataSource interface. This will add these methods to your class:

  • RowCount
  • RowData
  • SectionCount
  • SectionData

But before you add any code to those methods, you first want to set up the actual data you will display. There are 30 MLB teams, separated into six divisions. A simple way to manage this data is to use a Dictionary for the divisions and then for each division in the Dictionary, store an array of the team names. To start, create a property on the class:

Divisions As Dictionary

Now add a Constructor method with the code to populate the Dictionary:

Divisions = New Dictionary

Dim ALEast() As Text = Array("Red Sox", "Yankees", "Rays", "Orioles", "Blue Jays")
Dim ALCentral() As Text = Array("Tigers", "White Sox", "Twins", "Royals", "Indians")
Dim ALWest() As Text = Array("Angels", "Mariners", "Rangers", "Athletics", "Astros")

Dim NLEast() As Text = Array("Mets", "Braves", "Nationals", "Marlins", "Phillies")
Dim NLCentral() As Text = Array("Cardinals", "Brewers", "Reds", "Pirates", "Cubs")
Dim NLWest() As Text = Array("Dodgers", "Pardres", "Giants", "Diamondbacks", "Rockies")

Divisions.Value("AL East") = ALEast
Divisions.Value("AL Central") = ALCentral
Divisions.Value("AL West") = ALWest

Divisions.Value("NL East") = NLEast
Divisions.Value("NL Central") = NLCentral
Divisions.Value("NL West") = NLWest

Now you'll want one other helper method to get the name for a specific section number. Create a new method:

GetSectionName(section As Integer) As Text

And use this code:

Dim name As Text
Select Case section
Case 0
name = "AL East"
Case 1
name = "AL Central"
Case 2
name = "AL West"
Case 3
name = "NL East"
Case 4
name = "NL Central"
Case 5
name = "NL West"
End Select

Return name

With this all set up, you can now populate the interface methods. The RowCount method returns the number of rows in a specific section. This is the number of rows in the array that belongs to the Dictionary key for the section. You get it like this:

Dim teams() As Text
teams() = Divisions.Value(GetSectionName(section))
Return teams.Ubound + 1

The SectionCount method returns the number of sections. This is simply the count of keys in the Dictionary:

Return Divisions.Count

The SectionTitle method returns the name for a specific section. You can use the GetSectionName method get the name:

Return GetSectionName(section)

Lastly, this leaves the RowData method. Here you provide the data to display in the form of an iOSTableCellData instance. This code gets the team name for the appropriate section and row and sets it as the Text for the cell data:

Dim teams() As Text
teams() = Divisions.Value(GetSectionName(section))

Dim cell As iOSTableCellData = table.CreateCell
cell.Text = teams(row)

Return cell

And that's it to set up the data source. The last step is to add a Table to a View and tell it to use your new data source. On the View, you'll want to add a property to reference the data source:

Teams As BaseballTeams

And then in the Open event handler for the Table, you can create an instance of your data source and assign it to the table:

Teams = New BaseballTeams
Me.DataSource = Teams

Now you can run the project and you'll see the MLB team names grouped by division.

Example Project: iOS/Controls/Table/TableDataSource

Getting the Selected Row

Row Actions

Row Editing and Re-Ordering

Row Editing

Row Re-Ordering

Custom Cell Data

Example Projects

These example projects demonstrate various features of iOS Tables:

  • Examples/iOS/Controls/Table/CustomCellDynamicHeight
  • Examples/iOS/Controls/Table/CustomCellsAndScroll
  • Examples/iOS/Controls/Table/GroupTableExample
  • Examples/iOS/Controls/Table/SectionTableExample
  • Examples/iOS/Controls/Table/SelectableTable
  • Examples/iOS/Controls/Table/SimpleTableExample
  • Examples/iOS/Controls/Table/TableActions
  • Examples/iOS/Controls/Table/TableCellSizes
  • Examples/iOS/Controls/Table/TableCheckmark
  • Examples/iOS/Controls/Table/TableDataSource
  • Examples/iOS/Controls/Table/TableDetail
  • Examples/iOS/Controls/Table/TableDisclosure
  • Examples/iOS/Controls/Table/TableEditing
  • Examples/iOS/Controls/Table/TableDataSourceDatabase
  • Examples/iOS/Apps/XojoNotes
  • Examples/iOS/Database/SQLiteExample
  • Examples/Sample Applications/EddiesElectronics/iOS/EEiOS

See Also

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