Collection views

UICollectionView controls

The UICollectionView is a key view type in UIKit and Apple’s Human Interface Guidelines. The Fiori Design Language utilizes collection views in a number of floorplans, especially Object Details, Overview, as well as in the Gallery View, Object CollectionView and Attachments section of the Create View.

The SAPFiori utilizes UICollectionView instances in a number of controls, and when the content for those controls should be managed by the developer, it typically exposes the collection view as a public property in the API. A developer should use the regular UIKit API’s to configure and populate the item views of the collection, and handle things like taps and transitions.

The SAPFiori controls exposing a collection view property include:

  • FUITableViewCollectionSection with embedded FUICollectionViewTableViewCell
  • FUIAttachmentsController

These controls implement some context-specific behavior for the collection view–usually around layout and sizing–but when starting to implement a custom collection case, the starting point for a developer should be to work directly with *UICollectionView***.

Then, the developer can use one or more of the UICollectionViewLayout types from the SAPFiori framework to govern the item layout, and/or choose from the available UICollectionViewCell subclasses in the framework to match the design specification.

UICollectionViewLayout subclasses

FUICollectionViewLayout.horizontalScroll

The .horizontalScroll layout extends UICollectionViewFlowLayout. This layout should be used when the user should pan horizontally in the collection view, to view items off-screen to the left or right. Items in a section extend in a single row to infinity, so items will not wrap to new lines.

A developer should set the itemSize property of the layout, to specify the standard dimensions of the cell items. Or, the developer may implement the UICollectionViewDelegateFlowLayout, to specify unique sizes for each cell item.

A developer may optionally return views to the UICollectionViewDataSource collectionView(_:viewForSupplementaryElementOfKind:at:) method, to set ‘supplementary’ views to the collection view’s section header or footer. Multiple sections are supported, though cells in all sections will scroll simultaneously, so single section collections are most common.

Important: this layout ignores the estimatedItemSize property, even if assigned.

FUICollectionViewLayout.horizontalFlow

The .horizontalFlow layout extends UICollectionViewFlowLayout, by adding a new optional property: minimumScaledItemSize, which enables the collection view cell items’ dimensions to be scaled upwards, to fill the width of the collection view’s contentSize.

The developer may allow the layout to scale any number of cell items to fit the contentSize width, or, may set a pre-determined number of items which ought to fit the contentSize width, by setting the numberOfColumns property. This is useful, when the number of items rendered in the collection view vary on different screens, but a common size is desired.

The .horizontalFlow layout also controls the inter-item spacing, and line spacing, so that the minimumInteritemSpacing and minimumLineSpacing values provided by the developer are used precisely, rather than being adjusted by the AutoLayout engine.

With the introduction of this new size property, the UICollectionViewFlowLayout item size is managed by the following priority:

  1. Autolayout system, if estimatedItemSize is set not equal to CGSize.zero
  2. FUICollectionViewHorizontalFlowLayout, with numberOfColumns property, if minimumScaledItemSize is set not equal to CGSize.zero
  3. FUICollectionViewHorizontalFlowLayout, if minimumScaledItemSize is set not equal to CGSize.zero
  4. itemSize property (Note: collectionView(_:layout:sizeForItemAt:) value is ignored)

Default flow layout behavior

Flow layout behavior, using minimumScaledItemSize

FUICollectionViewLayout.autosizingColumnFlow

The autosizingColumnFlow resizes collection view cell items, to lay them out according to a specified number of columns. All items per row are top-aligned, though the cell item height may vary, based upon the AutoLayout system’s height calculation for the cell. The leading/trailing edges of the first and last columns abut the respective margins of the content view.

The developer may specify the number of columns, by setting the numberOfColumns property.

Collection view cell items supplied to the UICollectionViewDataSource.collectionView(_:cellForItemAt:) method for collection views utilizing this flow layout, should be well-prepared for the AutoLayout engine to calculate content sizes–especially heights.

### FUICollectionViewLayout.keyValueColumnFlow

The keyValueColumnFlow is a variant of the autosizingColumnFlow, with pre-configured layout characteristics for rendering collections of FUIKeyValueCollectionViewCell items.

  • minimumInteritemSpacing is set to 80.
  • minimumLineSpacing is set to 24.
  • sectionInset is set to UIEdgeInsetsMake(0, 8, 0, 8).
  • The FUITableViewCollectionSection control is designed to be used, when a section in a UITableView should be dedicated to displaying a UICollectionView, and, the height of that section should adjust to fit its contents.

    FUITableViewCollectionSection

    The collection section produces a single FUICollectionViewTableViewCell, which refreshes its height, after its subview FUICollectionView calculates the sizes of its subview UICollectionViewCell items.

    A developer uses the FUITableViewCollectionSection, by assigning a data source (/and delegate) to its collectionView: FUICollectionView property; then, he or she should supply its collectionViewTableViewCell property to a UITableViewDataSource.tableView(_:cellForRowAt:) implementation.

    Important

    A developer should retain a strong reference to a FUITableViewCollectionSection.

    ## Usage

        let workorders: [WorkOrder] = [WorkOrder]()
    
        override public func viewDidLoad() {
    
            let workOrdersLayout = FUICollectionViewLayout.horizontalFlow
            workOrdersLayout.itemSize = CGSize(width: 200, height: 200)
            self.workOrdersSection = FUITableViewCollectionSection(tableView: self.tableView, collectionViewLayout: workOrdersLayout)
            self.workOrdersSection.collectionView.dataSource = self
            self.workOrdersSection.collectionView.register(FUISimpleCollectionViewCell.self, forCellWithReuseIdentifier: FUISimpleCollectionViewCell.reuseIdentifier)
            self.workOrdersSection.collectionView.delegate = self
            self.workOrdersSection.collectionView.isScrollEnabled = false
    
            self.tableView.estimatedRowHeight = 98
            self.tableView.rowHeight = UITableViewAutomaticDimension
    
        }
    
        // MARK:  UITableViewDataSource
        override public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 1
        }
    
        public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            return self.workOrdersSection.collectionViewTableViewCell
        }
    
        // MARK:  UICollectionViewDataSource
        public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    
            switch collectionView {
            case workOrdersSection.collectionView:
                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FUISimpleCollectionViewCell.reuseIdentifier,
                                                                              for: indexPath) as! FUISimpleCollectionViewCell
                cell.contentImageView.image = UIImage(named: "WorkOrderImage")
                cell.titleLabel.text = "Work Order: \(indexPath.item)"
                return cell
            default:
                // ...
            }
        }
    
    See more

    Declaration

    Swift

    open class FUITableViewCollectionSection
  • UITableViewCell subclass, containing a full-frame collectionView: FUIResizingCollectionView. The FUICollectionViewTableViewCell should be returned by the FUITableViewCollectionSection collectionViewTableViewCell property.

    Important

    The resizing behavior of the FUIResizingCollectionView is dependent upon the internal size change handler. By default, the collectionView size will be controlled by its intrinsicContentSize. Developers should size the FUICollectionViewTableViewCell accordingly.
    See more

    Declaration

    Swift

    open class FUICollectionViewTableViewCell: NibDesignableTableViewCell
  • FUISimpleCollectionViewCell is a variant of UICollectionViewCell defined in SAPFiori. It contains a UIImageView and a UILabel.

    Code usage:

    Implement collectionView(_:cellForItemAt:) dataSource method

    
     //Implement collectionView(_:cellForItemAt:) dataSource method
     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
         let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FUISimpleCollectionViewCell.reuseIdentifier, for: indexPath) as! FUISimpleCollectionViewCell
    
         //configure cell
         cell.contentImage = UIImage()
         cell.titleText = "Title"
    
         return cell
     }
    
    

    Create and assign a layout object to collection view

    
     let layout = UICollectionViewFlowLayout()
    
     // Set any custom layout here.
     layout.itemSize = CGSize(width: 126, height: 126)
     layout.minimumInteritemSpacing = 10
     layout.minimumLineSpacing = 10
    
     // Sets the flow layout to CollectionView
     collectionView.collectionViewLayout = layout
     collectionView.dataSource = self
     collectionView.register(FUISimpleCollectionViewCell.self, forCellWithReuseIdentifier: FUISimpleCollectionViewCell.reuseIdentifier)
    
    
    See more

    Declaration

    Swift

    open class FUISimpleCollectionViewCell: NibDesignableCollectionViewCell
  • A variant of UICollectionViewCell which is very similar to SimplePropertyFormCell except that it’s not editable.

    • keyName: The key of the cell.
    • value: The value of the cell.

    Code usage:

    Register FUISimplePropertyCollectionViewCell for a collection view object. swift self.collectionView.register(FUISimplePropertyCollectionViewCell.self, forCellWithReuseIdentifier: FUISimplePropertyCollectionViewCell.reuseIdentifier)

    Dequeue a FUISimplePropertyCollectionViewCell object from a collection view’s dataSource method collectionView(_:cellForItemAt:) “`swift public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: FUISimplePropertyCollectionViewCell.reuseIdentifier, for: indexPath) as! FUISimplePropertyCollectionViewCell

    switch indexPath.item {
        case 0:
        cell.keyName = "Name"
        cell.value = "Broken Plates on Pole"
        case 1:
        cell.keyName = "Sort No."
        cell.value = "0001"
        default:
        break
    }
    
    return cell
    

    } ”`

    See more

    Declaration

    Swift

    public class FUISimplePropertyCollectionViewCell: NibDesignableCollectionViewCell
  • FUIKeyValueCollectionViewCell is a variant of UICollectionViewCell defined in SAPFiori. It contains a UILabel and a UITextField.

    Code usage:

    Register FUIKeyValueCollectionViewCell for a collection view object.

    
    self.collectionView.register(FUIKeyValueCollectionViewCell.self, forCellWithReuseIdentifier: FUIKeyValueCollectionViewCell.reuseIdentifier)
    
    

    Implement collection view’s dataSource method collectionView(_:cellForItemAt:)

    
    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: FUIKeyValueCollectionViewCell.reuseIdentifier, for: indexPath) as! FUIKeyValueCollectionViewCell
    
        switch indexPath.item {
            case 0:
            cell.keyName = "Name"
            cell.value = "Broken Plates on Pole"
            case 1:
            cell.keyName = "Sort No."
            cell.value = "0001"
            default:
            break
        }
    
        return cell
    }
    
    
    See more

    Declaration

    Swift

    public class FUIKeyValueCollectionViewCell: NibDesignableCollectionViewCell
  • Set of UICollectionViewFlowLayouts occurring in Fiori Design Language.

    See more

    Declaration

    Swift

    public enum FUICollectionViewLayout
  • This layout extends UICollectionViewFlowLayout, by adding a new optional property: minimumScaledItemSize, which enables the collection view cell items’ dimensions to be scaled upwards, to fill the width of the collection view’s contentSize.

    The developer may allow the layout to scale any number of cell items to fit the contentSize width, or, may set a pre-determined number of items which ought to fit the contentSize width, by setting the numberOfColumns property. This is useful, when the number of items rendered in the collection view vary on different screens, but a common size is desired.

    This layout also controls the inter-item spacing, and line spacing, so that the minimumInteritemSpacing and minimumLineSpacing values provided by the developer are used precisely, rather than being adjusted by the AutoLayout engine.

    Code usage

    1. Assign an instance of FUIHorizontalScrollCollectionViewLayout to your collection view. swfit self.collectionView.collectionViewLayout = FUICollectionViewLayout.horizontalScroll

    2. Implement collectionView(:cellForItemAt:) dataSource. “`swfit public func collectionView( collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FUIObjectCollectionViewCell.reuseIdentifier, for: indexPath) as! FUIObjectCollectionViewCell //You may use any type of collection view cell here. //configue cell here //… return cell } ”`

    3. Implement following methods if you need section header/footer. You can also set headerReferenceHeight/footerReferenceHeight to apply same height for all headers/footers. “`swift func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { let view = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: Header, for: indexPath) as! FUICollectionSectionHeaderFooterView //configue header/footer view here //… return view }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { switch section { case 0: return CGSize(width: 40, height: 40) default: return CGSize(width: 60, height: 60) }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { switch section { case 0: return CGSize(width: 40, height: 40) default: return CGSize(width: 60, height: 60) } ”`

    See more

    Declaration

    Swift

    open class FUIHorizontalFlowCollectionViewLayout: UICollectionViewFlowLayout
  • This layout should be used when the user should pan horizontally in the collection view, to view items off-screen to the left or right. Items in a section extend in a single row to infinity, so items will not wrap to new lines.

    A developer should set the itemSize property of the layout, to specify the standard dimensions of the cell items.

    Code usage

    1. Assign an instance of FUIHorizontalScrollCollectionViewLayout to your collection view. swfit self.collectionView.collectionViewLayout = FUICollectionViewLayout.horizontalScroll

    2. Implement collectionView(:cellForItemAt:) dataSource. “`swfit public func collectionView( collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FUIObjectCollectionViewCell.reuseIdentifier, for: indexPath) as! FUIObjectCollectionViewCell //You may use any type of collection view cell here. //configue cell here //… return cell } ”`

    3. Implement following methods if you need section header/footer. You can also set headerReferenceHeight/footerReferenceHeight to apply same height for all headers/footers. “`swift func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { let view = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: Header, for: indexPath) as! FUICollectionSectionHeaderFooterView //configue header/footer view here //… return view }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { switch section { case 0: return CGSize(width: 40, height: 40) default: return CGSize(width: 60, height: 60) }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { switch section { case 0: return CGSize(width: 40, height: 40) default: return CGSize(width: 60, height: 60) } ”`

    See more

    Declaration

    Swift

    open class FUIHorizontalScrollCollectionViewLayout: UICollectionViewFlowLayout
  • The FUIStandardAutoSizingColumnFlowLayout resizes collection view cell items, to lay them out according to a specified number of columns. All items per row are top-aligned, though the cell item height may vary, based upon the AutoLayout system’s height calculation for the cell.

    Code usage

    1. Assign an instance of FUIStandardAutoSizingColumnFlowLayout to your collection view. swfit self.collectionView.collectionViewLayout = FUICollectionViewLayout.autosizingColumnFlow

    2. Implement collectionView(:cellForItemAt:) dataSource. “`swfit public func collectionView( collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FUIObjectCollectionViewCell.reuseIdentifier, for: indexPath) as! FUIObjectCollectionViewCell //configue cell here //… return cell } ”`

    3. Implement following methods if you need section header/footer. You can also set headerReferenceHeight/footerReferenceHeight to apply same height for all headers/footers. “`swift func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { let view = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: Header, for: indexPath) as! FUICollectionSectionHeaderFooterView //configue header/footer view here //… return view } }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { switch section { case 0: return CGSize(width: 40, height: 40) default: return CGSize(width: 60, height: 60) }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { switch section { case 0: return CGSize(width: 40, height: 40) default: return CGSize(width: 60, height: 60) } ”`

    See more

    Declaration

    Swift

    open class FUIStandardAutoSizingColumnFlowLayout: UICollectionViewLayout
  • A subclass of FUIStandardAutoSizingColumnFlowLayout which resizes collection view cell items, to lay them out according to a specified number of columns. All items per row are top-aligned, though the cell item height may vary, based upon the AutoLayout system’s height calculation for the cell.

    minimumInteritemSpacing is set to 80 and minimumLineSpacing is set to 24 by default.

    sectionInset is set to ‘top: 0, left: 8, bottom: 0, right: 8’.

    Declaration

    Swift

    public class FUIKeyValueFlowLayout: FUIStandardAutoSizingColumnFlowLayout
  • UICollectionView subclass, which invokes a sizeChangeHandler: (() -> Void)? closure, when the current content size of the collection does not match the intrinsic content size. The sizeChangeHandler property is internal to the SDK.

    Developers should generally not initialize FUIResizingCollectionView directly. Instead, instances of the class are typically accessed through the FUITableViewCollectionSection API’s.

    Important

    Resizing behavior will only be executed, if the sizeChangeHandler is implemented.

    Declaration

    Swift

    public class FUIResizingCollectionView: UICollectionView