UITableView (iOS; ObjC and Swift 3, Xcode 8), ListView (Windows Store apps) and ListView (Android)


One of the most important elements for organising and listing data (especially on modern mobile devices) is the table (or list) view. Each OS handles the task in a similar but different way, using a data source and a series of table cells.

iOS (Xcode)

A UITableView in iOS draws from its data source on a cell by cell basis and we are responsible for making this work. This means there are a few steps to get a simple UITableView example up and running in iOS. I go through them here:

  1. drag out a UITableViewController object in the storyboard
  2. drag the arrow pointing at your current initial view controller and point it at the new UITableViewController (in the storyboard; note that you can delete the original View Controller at this point)
  3. click on the table cell inside the table, and in the Attributes Inspector fill out the box labelled Identifier with the word Cell

  1. create a new UITableViewController subclass file called TableViewController (using File > New... or Cmd + N, or the plus symbol beneath the directory of files and folders)
  2. with the UITableViewController selected in storyboard, use the Identity Inspector and make sure the Custom Class box has the same name as your new subclass of UITableViewController



You are now ready to replace the TableViewController.h code with the following

#import <UIKit/UIKit.h>
@interface TableViewController : UITableViewController <UITableViewDelegate>
@end

All that has changed here is that I've added <UITableViewDelegate> which means that the class accepts UITableViewDelegate calls. This is important, because it enables access to the information about which table cell has been tapped.

Next replace the code in the TableViewController.m with the following.

#import "TableViewController.h"
@interface TableViewController ()
@end

@implementation TableViewController
NSArray *tableItems;

- (void)viewDidLoad
{
[super viewDidLoad];

// sketchyTech: Build a data source
tableItems = @[@"1",@"2",@"3",@"4",@"5",@"6"];

// sketchyTech: this class must be the delegate of the table view it contains in order to receive selection messages

self.tableView.delegate=self;

}
// sketchyTech: UITableViewDelegate method

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

// sketchyTech: Tell the console which row was selected base on the string on that row
NSLog(@"Selected row no.%@",[tableItems objectAtIndex:indexPath.row]);
}
#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

// Return the number of sections.

// sketchyTech: table must have at least one section
return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

// Return the number of rows in the section.

// sketchyTech: rows are equal to number of objects in array
return [tableItems count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Configure the cell and return it
static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

cell.textLabel.text=[tableItems objectAtIndex:indexPath.row];

return cell;
}

@end

Swift 3

import UIKit

class TableViewController: UITableViewController {
    var tableItems:[String]!
    override func viewDidLoad() {
    
        super.viewDidLoad()
        
        // sketchyTech: Build a data source
        tableItems = ["1","2","3","4","5","6"]
        
        // sketchyTech: this class must be the delegate of the table view it contains in order to receive selection messages
        self.tableView.delegate=self;
    }
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let a = tableItems[indexPath.row]
                print("Selected row no. \(a)")
        
    }
    
    //MARK: Table view data source
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        // sketchyTech: table must have at least one section
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // sketchyTech: rows are equal to number of objects in array
        return tableItems.count
    }
    
  
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // sketchyTech: Configure the cell and return it
        let CellIdentifier = "Cell";
        let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier, for: indexPath)
        cell.textLabel?.text = tableItems[indexPath.row]
        return cell
    }
    
}

The code that I've added always follows a comment beginning // sketchyTech: the rest is generated by Xcode.

Windows (Visual Studio)

In Windows there is the ListView. To get the below example working, you simply need to drag out a StackPanel in the XAML interface file and provide it with the name stackPanel1. The code below is a commented and slightly adapted version of what can be found on the Windows Developer site.

Everything happens in one place and the comments explain all, just add the code to your MainPage.xaml.cs file.

namespace ListViewApp
{

  public sealed partial class MainPage : Page
    {
      public MainPage()
       {
          this.InitializeComponent();
       }

      protected override void OnNavigatedTo(NavigationEventArgs e)
       {

      // Create a data source array
      List<String> itemsList = new List<string>(){ "1", "2", "3", "4", "5" };

      // Create a new list view, add content,
      ListView listView1 = new ListView();
      listView1.ItemsSource = itemsList;

      // and add a SelectionChanged event handler
      listView1.SelectionChanged += ListView_SelectionChanged;

      // Add the list view to a parent container in the visual tree.
      stackPanel1.Children.Add(listView1);
       }

      private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
       {
       // When an item is selected we see which one it was
       ListView listView1 = (ListView)sender;
       var item = listView1.SelectedItems[0];
       // Remember to add using System.Diagnostics; and switch messages to Immediate Window if necessary
       Debug.WriteLine(item);
       }
   }
}

Make sure you've imported all the namespaces you need to make this work!

Notes: As you'll see from the code we begin with a List and add this as the ItemsSource to a ListView. A SelectionChanged listener is then added to the ListView and the view is then added to a StackPanel. The additional method is called when the listener is triggered.

Android (Eclipse)

In Android the ListView is paired with an Adapter as its data source. This can be an ArrayAdapter, which is used for object arrays, or the more sophisticated SimpleCursorAdapter, used for database queries.

Building a basic ListView in Android consists of a few steps, which I outline now.

First drag out a ListView in the main_activity.xml file. Doing so it might well assign its own id, but if it doesn't set it to @+id/listView1. Having done this move to the MainActivity.java file, where it is now time to build an array, add this array to an ArrayAdapter, assign the Adapter to the ListView and set up a listener for the ListView.


@Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      // Create the data array
      String[] myStringArray = {"Cola","Chips","Beer","Bread","Butter","Water"};

      // Build the adapter
      ArrayAdapter&lt;String&gt; adapter = new ArrayAdapter&lt;String&gt;(this, android.R.layout.simple_list_item_1, myStringArray);

      // Connect the ListView

      ListView listView = (ListView) findViewById(R.id.listView1);
      // Set the adapter for the ListView
      listView.setAdapter(adapter);
      // Set a listener to respond to taps
      listView.setOnItemClickListener(mMessageClickedHandler);
 
      // Create a message handling object as an anonymous class.
      private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() {
      public void onItemClick(AdapterView parent, View v, int position, long id) {

      // When item is clicked retrieve the text on the label
      Log.i("Position",parent.getItemAtPosition(position).toString());
      }
    };

You'll need to import the classes we've used, but Eclipse will warn you about this and provide the correct ones. You will then be up and running with tables (and list views) in all three operating systems.

Further Reading

How to add a list view (Windows Store apps using C#/VB/C++ and XAML) (Windows, Developer)

'Making a simple UITableView-like list in Windows 8.1' (John's Blog: Apps for Windows, msdn)

List View (Android, Developer)

Adapter Views (Android, Developer)


Comments