Create and Filter patterns

The FormKit API includes a set of UITableViewCells which should be used in the Fiori Design Language for constructing table views for creating or editing business objects, or for building filter controls. Each cell implements the FUIFormCell protocol and invokes an optional onChangeHandler closure to handle value changes.

FormKit cells are used in Filter and Create Floorplans.

Image

Interface

All cells in FormKit implement the FUIFormCell protocol. FUIFormCell is generic for its value property, and has an associatedtype: ValueType, which allows the value to be accessed with type safety.

FUITitleFormCell - displays the title of the form. The cell can be marked as editable to allow user editing of the title (for example, the Work Request cell in the above image):


    let cell = tableView.dequeueReusableCell(withIdentifier: FUITitleFormCell.reuseIdentifier, for: indexPath) as! FUITitleFormCell
    cell.value = "Work Request"
    cell.isEditable = false
    return cell

FUINoteFormCell - the user can enter notes in the cell (for example, the cell between Work Request and Location in the above image):


    let cell = tableView.dequeueReusableCell(withIdentifier: FUINoteFormCell.reuseIdentifier, for: indexPath) as! FUINoteFormCell
    cell.delegate = self
    cell.placeholder = "Please type something"
    cell.responderDelegate = self
    cell.cellHeight = 80
    return cell

FUISimplePropertyFormCell - provides a key/value pair that displays the key and value of the cell. The value of the cell cannot be modified (for example, the Request ID cell in the above image):


    // An un-editable property cell
    let cell = tableView.dequeueReusableCell(withIdentifier: FUISimplePropertyFormCell.reuseIdentifier, for: indexPath) as! FUISimplePropertyFormCell
    cell.key = "Request ID"
    cell.value = "#201611-001234"
    cell.delegate = self
    return cell

FUIListPickerFormCell - provides a key/value pair that displays the key and value of the cell. For single selection, set its allowsMultipleSelection property to false:


    // A property cell with list picker
    let cell = tableView.dequeueReusableCell(withIdentifier: FUIListPickerFormCell.reuseIdentifier, for: indexPath) as! FUIListPickerFormCell
    cell.keyName = "Work Group"
    cell.value = [0]
    cell.delegate = self
    cell.valueOptions = ["Construction", "Repair", "Engineering", "Vendor"]
    cell.allowsMultipleSelection = false
    cell.valueTextField.text = descriptionForSelectedStrings(cell.valueOptions, at: propValue3)
    return cell

When this cell is selected, a table view displays the available options for the user to choose:

Image

A FUIListPickerFormCell can also be set as multiple selectable in the app by setting its allowsMultipleSelection property to true as follows in the UITableViewController:

  let valueOptions12 = ["One", "Two", "Three", "Four", "Five", "Six", "Seven"]
  var propValue12 = [1, 3, 6]

  //...

    // A property cell with list picker
    let cell = tableView.dequeueReusableCell(withIdentifier: FUIListPickerFormCell.reuseIdentifier, for: indexPath) as! FUIListPickerFormCell
    cell.keyName = "Choose Multiple"
    cell.value = propValue12
    cell.valueOptions = valueOptions12

    // Developer is responsible to set the text of the valueTextField of the FUIListPickerFormCell.
    // Here, function descriptionForSelectedStrings is just returns the
    // comma separated selected string.
    cell.valueTextField.text = descriptionForSelectedStrings(valueOptions12, at: propValue12)
    cell.allowsMultipleSelection = true
    cell.listPicker.prompt = "Please select multiple items"
    cell.delegate = self
    return cell

Image

And when the cell is tapped, a multiple select table with specified optional values is displayed: Image

Developer could customize the cells displayed in the selection table by setting the dataSource property of the listPicker property of the FUIListPickerFormCell, as described below:

  let propKey11 = "List Picker with Object Cells"
  var propValue11: [Int] = []

  // ObjectCellListPickerDataSource implements ListPickerDataSource and ListPickerSearchResultsUpdating
  let listPickerDataSource11 = ObjectCellListPickerDataSource(40)

  // ...


  // A FUIListPickerFormCell with FUIObjectTableViewCell
    let cell = tableView.dequeueReusableCell(withIdentifier: FUIListPickerFormCell.reuseIdentifier, for: indexPath) as! FUIListPickerFormCell

    cell.keyName = propKey11
    cell.value = propValue11
    cell.valueTextField.text = listPickerDataSource11.descriptionForSelectedItems(at: propValue11)

    cell.listPicker.dataSource = listPickerDataSource11
    cell.listPicker.searchResultsUpdating = listPickerDataSource11
    cell.listPicker.prompt = "Please select multiple items"
    cell.listPicker.register(FUIObjectTableViewCell.self, forCellReuseIdentifier: FUIObjectTableViewCell.reuseIdentifier)
    cell.allowsMultipleSelection = true
    cell.allowsEmptySelection = true
    cell.delegate = self

    cell.delegate = self
    return cell

Image

And when the cell is tapped, a multiple select table with FUIObjectTableViewCell is displayed: Image

A search bar could be added to the FUIListPickerFormCell in the selection table view by setting the isSearchEnabled, dataSource and listPickerResultsUpdating. Optionally, a barcode scanner could be added to the search bar by setting the isBarcodeScannerEnabled property of the searchBar property, as follows:


  let propKey7 = "Choose Multiple"
  var propValue7: [Int] = []
  let listPickerDataSource7 = StringListPickerDataSource(options: ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"])

  // ...

    let cell = tableView.dequeueReusableCell(withIdentifier: FUIListPickerFormCell.reuseIdentifier, for: indexPath) as! FUIListPickerFormCell

    cell.keyName = propKey7
    cell.value = propValue7

    cell.allowsMultipleSelection = true
    cell.allowsEmptySelection = false
    cell.valueTextField.text = descriptionForSelectedStrings(cell.valueOptions, at: propValue7)

    cell.listPicker.dataSource = listPickerDataSource7
    cell.listPicker.searchResultsUpdating = listPickerDataSource7
    cell.listPicker.prompt = "Please select multiple items"
    cell.listPicker.isSearchEnabled = true
    cell.delegate = self

    cell.listPicker.searchBar?.isBarcodeScannerEnabled = true
    cell.listPicker.searchBar?.barcodeScanner?.scanMode = .ean_upc
    cell.listPicker.searchBar?.barcodeScanner?.scanResultTransformer = { (scanString) -> String in
      return self.transformStringToSearchBar(scanResultString: scanString)
    }

    return cell

Image

When the cell is tapped, the multiple selection table is shown with a search bar under the navigation bar.

Image

When user starts typing in the search bar, the displayed list will be filtered.

Image

When the barcode scanner icon is tapped, the barcode scan view is displayed. Note that the barcode scanner icon will not be displayed when the device does not support camera, such as running on simulator. The icon will not be displayed when the search bar is active, also.

Image

FUIDatePickerFormCell - provides a key/value pair that displays a key and a Date as the property value. When this cell is selected, a UIDatePicker displays to allow the user to select a date. The app can provide a DateFormatter to customize how the date displays (for example, the Appointment Date cell in the above image):

Image


    let cell = tableView.dequeueReusableCell(withIdentifier: FUIDatePickerFormCell.reuseIdentifier, for: indexPath) as! FUIDatePickerFormCell
    cell.key = "Appointment Date"
    cell.date = Date()
    // if the date property is not provided, the default value is now.
    cell.delegate = self
    return cell

FUIDurationPickerFormCell - provides a key/value pair that displays a key and a TimeInterval as the property value. When this cell is selected, a UIDatePicker displays to allow the user to select a duration. The app can provide a text formatter to customize how the duration displays (for example, the formatter by default is %d Hrs %d Min):


    let cell = tableView.dequeueReusableCell(withIdentifier: FUIDurationPickerFormCell.reuseIdentifier, for: indexPath) as! FUIDurationPickerFormCell
    cell.keyName = "Duration"
    cell.value = 3600  //In seconds
    cell.delegate = self
    return cell

FUISwitchFormCell - the property for this cell is a boolean value that uses a standard UISwitch to display the value. The user can change the value by tapping the switch (for example, the Confirmed cell in the above image):


    // A FUISwitchFormCell
    let cell = tableView.dequeueReusableCell(withIdentifier: FUISwitchFormCell.reuseIdentifier, for: indexPath) as! FUISwitchFormCell
    cell.key = "Confirmed"
    cell.value = true
    cell.delegate = self
    return cell

AttachmentFormCell - a cell to which photos or selected files from the photo library can be added as attachments:


    let cell = tableView.dequeueReusableCell(withIdentifier: AttachmentFormCell.reuseIdentifier, for: indexPath) as! AttachmentFormCell
    cell.attachmentDelegate = attachmentDelegate
    return cell

The application needs to add the following to its info.plist in order to access camera and photo library:


    <key>NSCameraUsageDescription</key>
    <string>Please permit access to camera</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>Please permit access to photo library</string>

Each UITableViewController is allowed to have only one AttachmentFormCell.

FUISegmentedControlFormCell - A type of FUIPropertyFormCell, representing a key/value pair of the cell. The user can select a value by clicking the button. The cell is editable by default and can be set to isEditable to disable user interaction.

Usage

Implement a UITableViewController that hosts the cells and constructs a Create Window view similar to the one in the example above:

The UITableViewController must subclass FUIFormTableViewController.


    class MyFormTableViewController: FormTableViewController {
    ...
    }

Register the reuse identifiers of all needed FUIFormCells, and enable auto-dimension row height calculation.


    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.register(FUITitleFormCell.self, forCellReuseIdentifier: FUITitleFormCell.reuseIdentifier)
        ...
        self.tableView.estimatedRowHeight = 200
        self.tableView.rowHeight = UITableViewAutomaticDimension
    }

Reuse the registered cells in tableView(_:cellForRowAt:), and bind the form data to the cell views:


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // An simple key-value property cell
        let cell = tableView.dequeueReusableCell(withIdentifier: FUISimplePropertyFormCell.reuseIdentifier, for: indexPath) as! FUISimplePropertyFormCell
        cell.key = "Location"
        cell.value = "127 Higgins Drive, Palo Alto"
        // MARK:  Implement `onChangeHandler` closure to process the new value entered by the user
        cell.onChangeHandler = { newValue in
            myObject.value = newValue
        }
        return cell
    }

For AttachmentFormCell, set the cell delegate property to DefaultAttachmentFormCellDelegate, or implement the didAddAttachment(attachment:) and didDeleteAttachment(attachmentNumber:) functions of AttachmentFormCellDelegate protocol, to receive notifications when attachments are added or deleted by the user:


    public class DefaultAttachmentFormCellDelegate: AttachmentFormCellDelegate {
        /**
        The list of attachments.
        */
        public var attachmentList: [AttachmentData] = [AttachmentData]()

        public init() {}
    }

    public func didAddAttachment(attachment: AttachmentData) {
        attachmentList.append(attachment)
    }

    public func didDeleteAttachment(attachmentNumber: Int) {
        var index = -1
        for i in 0..<attachmentList.count {
            if attachmentList[i].attachmentNumber == attachmentNumber {
                index = i
                break
            }
        }
        if index != -1 {
            attachmentList.remove(at: index)
        }
    }

  • This protocol is to be implemented by all the form cells except FUIAttachmentsFormCell, including:

    • FUIDatePickerFormCell
    • FUIFilterFormCell
    • FUINoteFormCell
    • FUISegmentedControlFormCell
    • FUISimplePropertyFormCell
    • FUISwitchFormCell
    • FUITitleFormCell
    See more

    Declaration

    Swift

    public protocol FUIFormCell: class, FUIInlineValidation
  • When FUIFormCells are to be used in an application, application’s implementation of UITableViewController that hosts these FUIFormCells must be a subclass of this FUIFormTableViewController. FUIFormTableViewController hides all the complications and interactions for handling all different types of FUIFormCells.

    Application’s implementation of the UITableViewController needs to only implement the following functions:

    
     class FormCellTestTVC: FUIFormTableViewController {
        override func viewDidLoad() {
            // MUST: Call viewDidLoad function of super class.
            super.viewDidLoad()
    
            // Register FUIFormCells that will be used
            self.tableView.register(FUITitleFormCell.self, forCellReuseIdentifier: FUITitleFormCell.reuseIdentifier)
            ...
        }
    
        override func numberOfSections(in tableView: UITableView) -> Int {
            // Return how many section in the table
            return ...
        }
    
        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            // Return number of rows in each section
            ...
        }
    
        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            // Return the cell to be used at the IndexPath specified
            let cell = tableView.dequeueReusableCell(withIdentifier: FUITitleFormCell.reuseIdentifier, for: indexPath) as! FUITitleFormCell
            cell.value = "Work Request"
    
            cell.isEditable = true
            // MARK:  implement onChangeHandler
            cell.onChangeHandler = { newValue in
                myObject.title = newValue
            }
            return cell
        }
    
    

    In addition, if there are some other actions on the table view, it is required that the action functions should also call function endEditing of the table view with the force parameter to true so that all editing cells have its onChangeHandler called. For example, the function didSaveTapped below is the action when the Save button tapped:

        @IBAction func didSaveTapped(_ sender: AnyObject) {
            self.tableView.endEditing(true)
    
            // save object ...
        }
    
    

    Declaration

    Swift

    open class FUIFormTableViewController: UITableViewController, FUIFormCellResponderDelegate, FUIFormCellNavigationDelegate
  • The reusable UI component implemented as an UITableViewCell to allow user to enter a value, using a UITextField.

    FUITitleFormCell

    The developer should set the following properties on the cell, in their implementation of UITableViewDataSource cellForRow(at:) function:

    • value: The value of the property, as String

    And an onChangeHandler:

    • onChangeHandler: a handler closure, which is invoked on changes to the value

    Optionally, the developer may provide:

    • isEditable: Indicates if the cell’s value may be modified. Defaults to true.

    The following is an example of usage in an application UITableViewController:

    Important

    The app’s UITableViewController must subclass FUIFormTableViewController
    override func viewDidLoad() {
       super.viewDidLoad()
       self.tableView.register(FUITitleFormCell.self, forCellReuseIdentifier: FUITitleFormCell.reuseIdentifier)
       // ...
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
       let cell = tableView.dequeueReusableCell(withIdentifier: FUITitleFormCell.reuseIdentifier, for: indexPath) as! FUITitleFormCell
    
       cell.value = myObject.title
       cell.isEditable = true
    
       // MARK:  implement onChangeHandler
       cell.onChangeHandler = { newValue in
            myObject.title = newValue
       }
       return cell
    }
    
    
    See more

    Declaration

    Swift

    open class FUITitleFormCell: FUIInlineValidationTableViewCell, FUIFormCell, UITextFieldDelegate
  • The reusable UI component implemented as an UITableViewCell to display or edit a key-value pair property.

    FUISimplePropertyFormCell

    The developer should set the following properties on the cell, in their implementation of UITableViewDataSource cellForRow(at:) function:

    • keyName: The key name of the property.
    • value: The value of the property.

    And an onChangeHandler:

    • onChangeHandler: a handler closure, which is invoked on changes to the value

    Optionally, the developer may provide

    • isEditable: Indicates if the cell’s value may be modified. Defaults to true.

    The following is an example of usage in an application UITableViewController:

    Important

    The app’s UITableViewController must subclass FUIFormTableViewController
    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.register(FUISimplePropertyFormCell.self, forCellReuseIdentifier: FUISimplePropertyFormCell.reuseIdentifier)
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: FUISimplePropertyFormCell.reuseIdentifier, for: indexPath) as! FUISimplePropertyFormCell
    
        cell.keyName = "Editable"
        cell.value = myObject.productName
    
        // MARK:  implement onChangeHandler
        cell.onChangeHandler = { newValue in
            myObject.productName = newValue
        }
    
        return cell
    }
    
    See more

    Declaration

    Swift

    open class FUISimplePropertyFormCell: FUIInlineValidationTableViewCell, FUIPropertyFormCell
  • The reusable UI component implemented as an UITableViewCell to allow user enter notes.

    FUINoteFormCell

    Optionally, the developer may provide:

    • value: The default text in the note.
    • placeholderText: The placeholder string to be put on the text area before user typed anything.
    • isAutoFitting: If this is true, the scroll will be disabled and the height of the cell will grow and shrink as needed. There is a minimum height that the cell will maintain.
    • isEditable: Indicates if the note text could be modified or not. The default is true.
    • onChangeHandler: a handler closure, which is invoked on changes to the value

    The following is an example of usage in an application UITableViewController:

    Important

    The app’s UITableViewController must subclass FUIFormTableViewController
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.register(FUINoteFormCell.self, forCellReuseIdentifier: FUINoteFormCell.reuseIdentifier)
        // ...
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        let cell = tableView.dequeueReusableCell(withIdentifier: FUINoteFormCell.reuseIdentifier, for: indexPath) as! FUINoteFormCell
    
        // If a value already exists, set it to the `value` property
        cell.value = myObject.note
    
        // Specify an optional placeholder text
        cell.placeholderText = "Description"
    
        // MARK:  implement onChangeHandler
        cell.onChangeHandler = { newValue in
            myObject.note = newValue
        }
    
        return cell
    }
    
    
    See more

    Declaration

    Swift

    public class FUINoteFormCell: FUIInlineValidationTableViewCell, FUIFormCell, UITextViewDelegate
  • The reusable UI component implemented as an UITableViewCell to allow user to choose a boolean value using a switch for a property.

    FUISwitchFormCell

    The developer should set the following properties on the cell, in their implementation of UITableViewDataSource cellForRow(at:) function:

    • keyName: The key name of the property
    • value: The value of the property, as Bool
    • isEditable: Indicates if the cell’s value may be modified. Defaults to true.

    And, an onChangeHandler:

    • onChangeHandler: a handler closure, which is invoked on changes to the value

    The following is an example of usage in an application UITableViewController:

    Important

    The app’s UITableViewController must subclass FUIFormTableViewController
    override func viewDidLoad() {
       super.viewDidLoad()
       self.tableView.register(FUISwitchFormCell.self, forCellReuseIdentifier: FUISwitchFormCell.reuseIdentifier)
       // ...
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
       // ...
       let cell = tableView.dequeueReusableCell(withIdentifier: FUISwitchFormCell.reuseIdentifier, for: indexPath) as! FUISwitchFormCell
       cell.keyName = "Confirmed"
       cell.value = myObject.isConfirmed
    
       // MARK:  implement onChangeHandler
       cell.onChangeHandler = { newValue in
           myObject.isConfirmed = newValue
       }
    
       return cell
    }
    
    
    See more

    Declaration

    Swift

    open class FUISwitchFormCell: FUIInlineValidationTableViewCell, FUIPropertyFormCell
  • A UITableViewCell subclass, which allows a user to view or select from a list of strings, using a Fiori-styled segmented control.

    FUISegmentedControlFormCell

    The value property of the cell is equal to the selectedSegmentIndex in the segmented control.

    Code usage:

    // Optionally, create an array of value option to localized string mappings
    let buttonTitles: [[String: String]] = [[LO: Low], [MED: Medium], [HI: High]]

    // Register FUISegmentedControlFormCell in viewDidLoad() method in the controller. override func viewDidLoad() { super.viewDidLoad() self.tableView.register(FUISegmentedControlFormCell.self, forCellReuseIdentifier: FUISegmentedControlFormCell.reuseIdentifier) }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: FUISegmentedControlFormCell.reuseIdentifier, for: indexPath) as! FUISegmentedControlFormCell

    cell.valueOptions = buttonTitles.flatMap { $0.map { $0.value } } cell.keyName = Priority cell.value = myObject.priority // String value in the valid options set: [LO, MED, HI]

    // MARK: implement onChangeHandler cell.onChangeHandler = { newValue in myObject.priority = buttonTitles[newValue].first!.key // lookup valid String value, from the buttonTitles array }

    return cell }

    See more

    Declaration

    Swift

    open class FUISegmentedControlFormCell: FUIInlineValidationTableViewCell, FUIPropertyFormCell
  • A UITableViewCell subclass, which allows a user to read or enter a set of values, using a grid of buttons. Commonly used for composing filters.

    FUIFilterFormCell

    The developer should set the following properties on the cell, in their implementation of UITableViewDataSource cellForRow(at:) function:

    • keyName: The key name of the property.
    • value: An array of the selected indexes in the control. Uses the same index as the valueOptions array.
    • `valueOptions: A String array, of titles for the buttons in the control

    And an onChangeHandler:

    • onChangeHandler: a handler closure, which is invoked on changes to the value

    Optionally, the developer may provide

    • allowsMultipleSelection: Indicates if multiple buttons may be selected simultaneously (true). If false, the control behaves in radio mode. Defaults to true.
    • allowsEmptySelection: Indicates if the control allows zero items to be selected (true). If false, then once a value has been selected by the developer or user, taps by the user on the last selected item will be ignored, instead of de-selecting the item. Defaults to true.
    • isEditable: Indicates if the cell’s value may be modified. Defaults to true.

    The following is an example of usage in an application UITableViewController:

    Important

    The app’s UITableViewController must subclass FUIFormTableViewController
     // optionally, create an array of value option to localized string mappings
      let buttonTitles: [[String: String]] = [["radius": "Distance"], ["price": "Price"], ["rating": "Ratings"], ["avail": "Availability"]]
    
     // Register FUIFilterFormCell in viewDidLoad() method in the controller.
     override func viewDidLoad() {
         super.viewDidLoad()
         self.tableView.register(FUIFilterFormCell.self, forCellReuseIdentifier: FUIFilterFormCell.reuseIdentifier)
     }
    
     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         let cell = tableView.dequeueReusableCell(withIdentifier: FUIFilterFormCell.reuseIdentifier, for: indexPath) as! FUIFilterFormCell
    
         cell.valueOptions = buttonTitles.flatMap { $0.map { $0.value }}
         cell.keyName = "Sort By"
         cell.value = [1]
         cell.allowsMultipleSelection = true
         cell.allowsEmptySelection = false
    
         // MARK:  implement onChangeHandler
         cell.onChangeHandler = { newValue in
            self.applyFilter(forDimensions: newValue)      // here, the cell input is set to a filter function
         }
    
        return cell
     }
    
    
    See more

    Declaration

    Swift

    public class FUIFilterFormCell: FUIInlineValidationTableViewCell, FUIPickerFormCell, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
  • A UITableViewCell subclass, which allows a user to read or enter a value, using a date picker.

    FUIDatePickerFormCell

    The developer should set the following properties on the cell, in their implementation of UITableViewDataSource cellForRow(at:) function:

    • keyName: The key name of the property.
    • value: The value of the property, as Date

    And an onChangeHandler:

    • onChangeHandler: a handler closure, which is invoked on changes to the value

    Optionally, UITableViewController could provide

    • dateFormatter: A developer-defined UIDateFormatter, for transposing between Date type and String.
    • datePickerMode: The UIDatePickerMode for the date picker. Default is .dateAndTime. Note that .countDownTimer mode is not supported. Use the FUIDurationPickerFormCell for duration values.
    • isEditable: Indicates if the cell’s value may be modified. Defaults to true.

    The following is an example of usage in an application UITableViewController:

    Important

    The app’s UITableViewController must subclass FUIFormTableViewController
    let dateFormatter = DateFormatter()
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        dateFormatter.dateFormat = "dd-MM-yyyy"
        self.tableView.register(FUIDatePickerFormCell.self, forCellReuseIdentifier: FUIDatePickerFormCell.reuseIdentifier)
        // ...
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        let cell = tableView.dequeueReusableCell(withIdentifier: FUIDatePickerFormCell.reuseIdentifier, for: indexPath) as! FUIDatePickerFormCell
        cell.keyName = "End Date"
    
        cell.dateFormatter = dateFormatter
        cell.datePickerMode = .date
        cell.value = cell.dateFormatter.date(from: myObject.endDate)   // "02-17-2017"
    
         // MARK:  implement onChangeHandler
         cell.onChangeHandler = { newValue in
            myObject.endDate = cell.dateFormatter.string(from: newValue)
         }
    
         return cell
    }
    
    
    See more

    Declaration

    Swift

    public class FUIDatePickerFormCell: FUIInlineValidationTableViewCell, FUIPropertyFormCell
  • A UITableViewCell subclass, which allows a user to read or enter a value, using a duration picker.

    FUIDurationPickerFormCell

    The developer should set the following properties on the cell, in their implementation of UITableViewDataSource cellForRow(at:) function:

    • keyName: The key name of the property
    • value: The value of the property, as TimeInterval

    And an onChangeHandler:

    • onChangeHandler: a handler closure, which is invoked on changes to the value

    Optionally, the developer may provide

    • minInterval: The minute interval to be used in the picker.
    • isEditable: Indicates if the cell’s value may be modified. Defaults to true.

    The following is an example of usage in an application UITableViewController:

    Important

    The app’s UITableViewController must subclass FUIFormTableViewController
     override func viewDidLoad() {
         super.viewDidLoad()
         self.tableView.register(FUIDurationPickerFormCell, forCellReuseIdentifier: FUIDurationPickerFormCell.reuseIdentifier)
         // ...
     }
    
     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
         let cell = tableView.dequeueReusableCell(withIdentifier: FUIDurationPickerFormCell.reuseIdentifier, for: indexPath) as! FUIDurationPickerFormCell
         cell.keyName = "Duration"
         cell.value = myObject.eventDuration  // in seconds
    
         // MARK:  implement an onChangeHandler
         cell.onChangeHandler = { newValue in
            myObject.eventDuration = newValue
         }
    
         return cell
     }
    
    See more

    Declaration

    Swift

    public class FUIDurationPickerFormCell: FUIInlineValidationTableViewCell, FUIPropertyFormCell
  • The reusable UI component implemented as an UITableViewCell to display a key-value pair property, which is integrated with a FUIListPicker controller for displaying a list of values.

    ### Single-line version

    FUIListPickerFormCell-single

    ### Multi-line version

    FUIListPickerFormCell-multi

    The developer should set the following properties on the cell, in their implementation of UITableViewDataSource cellForRow(at:) function:

    • keyName: The key name of the property.
    • value: The default selections.
    • valueOptions: The list of optional values user may choose from.
    • allowsMultipleSelection: Indicates if user can select multiple values. Default is true, meaning by default user may select multiple values.
    • isEditable: If the selection(s) could be modified or not. The default is true.
    • listPicker: The FUIListPicker for this FUIListPickerFormCell.

    Note that the display of the selections in the valueTextField is the responsibility of the developer if the dataSource property of the listPicker is set. Developer is to set the text of the valueTextField to reflect the selections. Otherwise, if developer sets valueOptions and leaves dataSource of listPicker to nil, then the text in valueTextField will be set internally.

    Here are the code snippets in app’s UITableViewController implementation: (The app’s UITableViewController needs to be a subclass of FUIFormTableViewController.)

    
            var propValue7: [Int] = [1, 3, 6]
            var valueOptions7 = ["One", "Two", "Three", "Four", "Five", "Six", "Seven"]
            var listPickerDataSource7 = StringListPickerDataSource(options: valueOptions7)
    
            override func viewDidLoad() {
                super.viewDidLoad()
                self.tableView.register(FUIListPickerFormCell.self, forCellReuseIdentifier: FUIListPickerFormCell.reuseIdentifier)
                // ...
            }
    
            override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                // ...
                let cell = tableView.dequeueReusableCell(withIdentifier: FUIListPickerFormCell.reuseIdentifier, for: indexPath) as! FUIListPickerFormCell
                cell.keyName = "Choose Multiple"
                cell.value = propValue7
                cell.allowsMultipleSelection = true
                cell.valueTextField.text = descriptionForSelectedStrings(valueOptions7, at: propValue7) // See below
    
                cell.listPicker.dataSource = listPickerDataSource7
                cell.listPicker.searchResultsUpdating = listPickerDataSource7
                cell.listPicker.isSearchEnabled = true
                cell.listPicker.prompt = "Please select multiple items"
    
                cell.listPicker.searchBar?.isBarcodeScannerEnabled = true
                cell.listPicker.searchBar?.barcodeScanner?.scanMode = .EAN_UPC
                cell.listPicker.searchBar?.barcodeScanner?.scanResultTransformer = { (scanString) -> String in
                    return self.transformStringToSearchBar(scanResultString: scanString)
                }
                // MARK:  implement onChangeHandler
                cell.onChangeHandler = { [unowned self] newValue in
                    self.propValue3 = newValue
                }
                return cell
                // ...
            }
    
            func descriptionForSelectedStrings(_ options: [String], at indexes: [Int]) -> String {
                return options.enumerated().filter({ (index, element) -> Bool in
                    return indexes.contains(index)
                }).reduce ("") { string, element in
                    return string.isEmpty ? element.1 : "\(string), \(element.1)"
                }
            }
    
    
    See more

    Declaration

    Swift

    public class FUIListPickerFormCell: FUIInlineValidationTableViewCell, FUIPickerFormCell
  • An object that adopts the FUIListPickerDataSource protocol is responsible for providing the data and views required to display the list of options available in the FUIListPickerFormCell.

    See more

    Declaration

    Swift

    public protocol FUIListPickerDataSource: class
  • An implementation of FUIListPickerSearchResultsUpdating protocol is responsible to maintain a filtered list of options, based on the search string specified, for the corresponding FUIListPickerDataSource implementation.

    See more

    Declaration

    Swift

    public protocol FUIListPickerSearchResultsUpdating: class
  • The protocol defines the properties and functions for listing the options in an UITableView for the corresponding ListPickerFormCell.

    See more

    Declaration

    Swift

    public protocol FUIListPicker
  • The reusable UI component implemented as an UITableViewCell to manage selecting attachments. The application must provide a list of FUIAttachmentAction implementations for the desired type of attachments. The app can use the built-in types or implement additional types as desired.

  • Important

    the cell’s parent UITableViewController should subclass FUIFormTableViewController.

    There are two built-in FUIAttachmentAction: - FUIAddPhotoAttachmentAction: Choose photo from the photo library. - FUITakePhotoAttachmentAction: Take photo using the camera.

     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         let cell = tableView.dequeueReusableCell(withIdentifier: FUIAttachmentsFormCell.reuseIdentifier, for: indexPath) as! FUIAttachmentsFormCell
         cell.attachmentsController.delegate = self
         cell.attachmentsController.dataSource = self
    
         let addPhotoAction = FUIAddPhotoAttachmentAction()
         addPhotoAction.delegate = self
         cell.attachmentsController.addAttachmentAction(addPhotoAction)
    
         let takePhotoAction = FUITakePhotoAttachmentAction()
         takePhotoAction.delegate = self
         cell.attachmentsController.addAttachmentAction(takePhotoAction)
    
         let customAction = CustomAction(controller: self)
         cell.attachmentsController.addAttachmentAction(customAction)
    
         return cell
     }
    
     var attachmentURLs: [URL] = [URL]()
    
    // MARK: FUIAttachmentsViewControllerDataSource methods
    func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, iconForAttachmentAtIndex index: Int) -> (image: UIImage, contentMode: UIViewContentMode)? {
        let urlString = self.attachmentURLs[index].absoluteString
        guard let image = self.attachmentThumbnails[urlString] else {
            return nil
        }
        return (image!, .scaleAspectFill)
    }
    
    func numberOfAttachments(in attachmentsViewController: FUIAttachmentsViewController) -> Int {
        return attachmentURLs.count
    }
    
    func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, urlForAttachmentAtIndex index: Int) -> URL? {
        return attachmentURLs[index]
    }
    
    // MARK:  FUIAttachmentsViewControllerDelegateMethods
    func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, couldNotPresentAttachmentAtIndex index: Int) {
        // TODO:  present the attachment, using a compatible viewer
    }
    
    func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, didPressDeleteAtIndex index: Int) {
        self.attachmentURLs.remove(at: index)
        self.tableView.reloadSections(IndexSet(integer:attachmentSection), with: .automatic)
    }
    
    
    //MARK: FUIAddPhotoAttachmentActionDelegate
    func addPhotoAttachmentAction(_ action: FUIAddPhotoAttachmentAction, didSelectPhotoAt url: URL) {
        self.addAttachmentURL(url)
    }
    
    //MARK: FUITakePhotoAttachmentActionDelegate
    
    func takePhotoAttachmentAction(_ action: FUITakePhotoAttachmentAction, didTakePhotoAt url: URL) {
        self.addAttachmentURL(url)
    }
    
    
    func addAttachmentURL(_ url: URL) {
        self.attachmentURLs.append(url)
        DispatchQueue.main.async {
            self.tableView.reloadSections(IndexSet(integer:self.attachmentSection), with: .automatic)
            self.tableView.scrollToRow(at: IndexPath(row: 0, section: self.attachmentSection) , at: .middle, animated: true)
        }
    }
    
    
    See more

    Declaration

    Swift

    open class FUIAttachmentsFormCell: NibDesignableTableViewCell
  • FUIInlineValidationTableViewCell is a base class for FUIFormCells that need to support validation handling. The validation view will appear at the bottom of cell if validation message is set.

    Code usage:

    1. Custom class should subclass FUIInlineValidationTableViewCell to enable validation handling. Create a bottom constraint on main view and contentView and assign to validationViewHeight property.
    public class FUITitleFormCell: FUIInlineValidationTableViewCell, FUIFormCell, UITextFieldDelegate {
        public override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
           //Any setup code
    
           self.validationViewHeight = self.stackViewBottom
        }
    }
    
    1. Set validationMessage on the cell.
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: FUITitleFormCell.reuseIdentifier, for: indexPath) as! FUITitleFormCell
        //Configure your cell
    
        cell.validationMessage = "Validation msg"
    }
    
    See more

    Declaration

    Swift

    open class FUIInlineValidationTableViewCell: NibDesignableTableViewCell, FUIInlineValidation