SwiftUI – Table on iOS 16

By | 28/06/2023

In this post, we will see how to use the new Table introduced in iOS 16.
It is import to highlight that in macOS and iPadOS it works very well instead, in iOS, it doesn’t work fine. In fact, in iOS, and in situations with a compact horizontal size class, the Table doesn’t show the headers and collapses all columns after the first. 
It means that, if we want to use the Table on iOS, we have to customize its appearance by implementing compact-specific logic in the first column.
For all information, we can look up the Apple website.

Let’s see some examples:

We open Xcode, we create an iOS application and, following the pattern MVVM, we define a list of Users:

[USER.SWIFT]

import Foundation

struct User: Identifiable {
    let id = UUID()
    let userName: String
    let password: String
}


[USERVIEWMODEL.SWIFT]

import Foundation

class UserViewModel {
    func GetAllUsers() -> [User] {
        // Create a list of 12 sample users
        let users = [
            User(userName: "user1", password: "password1"),
            User(userName: "user2", password: "password2"),
            User(userName: "user3", password: "password3"),
            User(userName: "user4", password: "password4"),
            User(userName: "user5", password: "password5"),
            User(userName: "user6", password: "password6"),
            User(userName: "user7", password: "password7"),
            User(userName: "user8", password: "password8"),
            User(userName: "user9", password: "password9"),
            User(userName: "user10", password: "password10"),
            User(userName: "user11", password: "password11"),
            User(userName: "user12", password: "password12")
        ]
        return users
    }
}


[CONTENTVIEW.SWIFT]

import SwiftUI

struct ContentView: View {
    @State private var lstUsers = UserViewModel().GetAllUsers()
    
    var body: some View {
        Table(lstUsers) {
            TableColumn("ID", value: \.id.uuidString)
            TableColumn("UserName", value: \.userName)
            TableColumn("Password", value: \.password)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


If we run the application, using the iPad simulator, the following will be the result:


Instead, if we run the application in the iPhone simulator, the following will be the result:


In order to show a custom information, instead of the first column, we have just to modify the code in the first column:


[CONTENTVIEW.SWIFT]

import SwiftUI

struct ContentView: View {
    @State private var lstUsers = UserViewModel().GetAllUsers()
    // with this parameter we can know if we are "using" iOS
    @Environment(\.horizontalSizeClass) var horizontalSizeClass

    var body: some View {
        Table(lstUsers) {
            TableColumn("ID") { user in
                            if horizontalSizeClass == .compact {
                                // different output for iOS
                                Text("\(user.userName) - \(user.password)")
                            } else {
                                Text(user.id.uuidString)
                            }
                        }
            TableColumn("UserName", value: \.userName)
            TableColumn("Password", value: \.password)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


If we run the application, using both iPhone and iPad simulators, the following will be the results:



The last thing that I want to show is how to make the columns of the table sortable, following the instructions in Apple’s website:
To make the columns of a table sortable, provide a binding to an array of SortComparator instances. The table reflects the sorted state through its column headers, allowing sorting for any columns with key paths. When the table sort descriptors update, re-sort the data collection that underlies the table; the table itself doesn’t perform a sort operation. You can watch for changes in the sort descriptors by using a onChange(of:perform:) modifier, and then sort the data in the modifier’s perform closure.

[CONTENTVIEW.SWIFT]

import SwiftUI

struct ContentView: View {
    @State private var lstUsers = UserViewModel().GetAllUsers()
    @State private var sortOrder = [KeyPathComparator(\User.userName)]
    
    var body: some View {
        Table(lstUsers, sortOrder: $sortOrder){
            TableColumn("Id", value: \.id.uuidString)
            TableColumn("UserName", value: \.userName)
            TableColumn("Password", value: \.password)
        }
        .onChange(of: sortOrder) {
                    lstUsers.sort(using: $0)
                }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


If we run the application, the following will be the result:








Leave a Reply

Your email address will not be published. Required fields are marked *