Skip to content

List Floorplan (Tools Example)

The list report floorplan is one flat list that contains objects of the same object type. It may contain one or multiple groups. The user can view each object and take actions from the list report—for instance, grouping them. The user may filter to create a separate list.

Here is a sample of how to implement the example in the Tools example:

image

In this sample, we will:

  • Bind the model to views in the controller
  • Set up Search functionality
  • Utilize the Barcode Scanner, integrated in the SearchBar (requires a physical device, with camera)

Bind the Model to Views in the Controller

The most common UITableViewCell utilized in List Reports is the FUIObjectTableViewCell. Set up an array of Tool objects, and bind that data to a dequeued FUIObjectTableViewCell.

Be sure to set the tableView.rowHeight = UITableViewAutomaticDimension, so that the AutoLayout system will correctly calculate the height of the table view cells from their content.

class ToolsListReportFloorplanExample: UITableViewController {

    var tools: [ToolsListReportFPData.Tool] = ToolsListReportFPData.tools     // see sample model data below

    override func viewDidLoad() {
        super.viewDidLoad()

        self.title = "Tools"

        self.tableView.register(FUIObjectTableViewCell.self, forCellReuseIdentifier: FUIObjectTableViewCell.reuseIdentifier)

        self.tableView.estimatedRowHeight = 98
        self.tableView.rowHeight = UITableViewAutomaticDimension
    }

    // MARK: - Table view data source

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tools.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let task = tools[indexPath.row]

        let cell = tableView.dequeueReusableCell(withIdentifier: FUIObjectTableViewCell.reuseIdentifier,
                                                            for: indexPath) as! FUIObjectTableViewCell
        cell.headlineText = tool.title
        cell.subheadlineText = tool.code
        cell.detailImage = tool.image
        cell.descriptionText = tool.description
        cell.statusText = tool.status
        cell.accessoryType = .disclosureIndicator

        return cell
    }

Depending on how your navigation hierarchy is configured, you might notice that your Navigation Bar does not display. If this is the case, ensure that a UINavigationController is active, and controlling the presentation of your view controller. If you have set up a Single-Page Application, you should select your view controller in your storyboard, and select Editor > Embed In > Navigation Controller. For more details, see Apple Documentation.

Set up Search Functionality

Use the SAPFiori framework subclasses UISearchController and UISearchBar, to natively integrate bar code scanning into the search bar. You can use the FUISearchBar without barcode scanning, also, as shown below:

  1. Configure the FUISearchController, and set FUISearchBar to UITableView tableHeaderView subview property

    class ToolsListReportFloorplanExample: UITableViewController, UISearchResultsUpdating {
    
        var searchController: FUISearchController!
    
        var tools: [ToolsListReportFPData.Tool] = ToolsListReportFPData.tools
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.title = "Tools"
    
            self.tableView.register(FUIObjectTableViewCell.self, forCellReuseIdentifier: FUIObjectTableViewCell.reuseIdentifier)
    
            searchController = FUISearchController(searchResultsController: nil)
            searchController.searchResultsUpdater = self
            searchController.searchBar.placeholderText = "Search for tool"
    
            self.tableView.tableHeaderView = searchController.searchBar
    
            self.tableView.estimatedRowHeight = 98
            self.tableView.rowHeight = UITableViewAutomaticDimension
        }
    
  2. Create an isFiltered flag, and filteredTools data source to use while filtering on search bar input

    class ToolsListReportFloorplanExample: UITableViewController, UISearchResultsUpdating {
    
        var searchController: FUISearchController!
    
        var tools: [ToolsListReportFPData.Tool] = ToolsListReportFPData.tools
        var filteredTools: [ToolsListReportFPData.Tool] = []
        var isFiltered: Bool = false
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.title = "Tools"
    
            self.tableView.register(FUIObjectTableViewCell.self, forCellReuseIdentifier: FUIObjectTableViewCell.reuseIdentifier)
    
            searchController = FUISearchController(searchResultsController: nil)
            searchController.searchResultsUpdater = self
            searchController.searchBar.placeholderText = "Search for tool"
    
            self.tableView.tableHeaderView = searchController.searchBar
    
            self.tableView.estimatedRowHeight = 98
            self.tableView.rowHeight = UITableViewAutomaticDimension
        }
    
        // MARK: - Table view data source
    
        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return isFiltered ? filteredTools.count : tools.count
        }
    
        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
            let tool = isFiltered ? filteredTools[indexPath.row] : tools[indexPath.row]
    
            let cell = tableView.dequeueReusableCell(withIdentifier: FUIObjectTableViewCell.reuseIdentifier, for: indexPath) as! FUIObjectTableViewCell
            cell.headlineText = tool.title
            cell.subheadlineText = tool.code
            cell.detailImage = tool.image
            cell.descriptionText = tool.description
            cell.statusText = tool.status
            cell.accessoryType = .disclosureIndicator
    
            return cell
        }
    
  3. Implement UIKit UISearchResultsUpdating protocol, to respond to changes to the UISearchBar input

    // MARK:  UISearchResultsUpdating
    func updateSearchResults(for searchController: UISearchController) {
    
        guard let searchString = searchController.searchBar.text, !searchString.isEmpty else {
            self.isFiltered = false
            self.filteredTools.removeAll()
            self.tableView.reloadData()
            return
        }
    
        self.isFiltered = true
        self.filteredTools = self.tools.filter( {
            return $0.title.contains(searchString) ||
                $0.code.contains(searchString) ||
                $0.description.contains(searchString)
        })
        self.tableView.reloadData()
    }
    

Configure the Embedded Barcode Scanner

The Barcode Scanner depends on access to the device camera. According to Apple's privacy requirements, a developer must add the following entry to the application project's Info.plist; if missing, the application will be terminated when the user attempts to launch a camera-dependent component.

1
2
3
4
```xml
<key>NSCameraUsageDescription</key>
<string>Please permit access to camera</string>
```
class ToolsListReportFloorplanExample: UITableViewController, UISearchResultsUpdating {

    var searchController: FUISearchController!

    var tools: [ToolsListReportFPData.Tool] = ToolsListReportFPData.tools

    override func viewDidLoad() {
        super.viewDidLoad()

        self.title = "Tools"

        self.tableView.register(FUIObjectTableViewCell.self, forCellReuseIdentifier: FUIObjectTableViewCell.reuseIdentifier)

        searchController = FUISearchController(searchResultsController: nil)
        searchController.searchResultsUpdater = self
        searchController.searchBar.placeholderText = "Search for tool"
        searchController.searchBar.isBarcodeScannerEnabled = true
        searchController.hidesNavigationBarDuringPresentation = true
        searchController.searchBar.barcodeScanner?.scanResultTransformer = {
            return $0.lowercased()
        }

        self.tableView.tableHeaderView = searchController.searchBar

        self.tableView.estimatedRowHeight = 98
        self.tableView.rowHeight = UITableViewAutomaticDimension
    }

Sample Data

Before running the application, add an image to your project's Asset catalog, named "BoringPic". For more information on working with Asset catalogs, see Apple documentation.

struct ToolsListReportFPData {

    struct Tool {
        let title: String
        let code: String
        let image: UIImage?
        let description: String
        let status: String

        init(title: String, code: String, image: UIImage? = UIImage(named: "BoringTool"), description: String = "Cylinder head - CYLH-Z6-R166 / Index 2", status: String = "OP50") {
            self.title = title
            self.code = code
            self.image = image
            self.description = description
            self.status = status
        }
    }

    static let tools: [Tool] = [Tool(title: "PCBN Indexable Insert Boring Tool", code: "T6179"),
                                Tool(title: "Special PCD Milling Cutter", code: "T6171"),
                                Tool(title: "Special PCD Stepped Boring Tool", code: "T5277"),
                                Tool(title: "Special PCD Stepped Boring Tool", code: "T5278"),
                                Tool(title: "Special PCD Stepped Boring Tool", code: "T4370"),
                                Tool(title: "Special PCD Stepped Boring Tool", code: "T4270"),
                                Tool(title: "Special PCD Stepped Boring Tool", code: "T4271"),
                                Tool(title: "Special PCD Stepped Boring Tool", code: "T4272"),
                                Tool(title: "Special PCD Stepped Boring Tool", code: "T4273"),
                                Tool(title: "Special PCD Stepped Boring Tool", code: "T4371")]
}

Last update: January 15, 2021