Hierarchy View

  • A view controller which specializes in managing a hierarchy view. When FUIHierarchyViewController initiates, it sets data source and delegate of hierarchy view to self.

    Components

    • hierarchyView

    Usage

    Subclass FUIHierarchyViewController when you need to show a hierarchy view. It conforms to FUIHierarchyViewDataSource and FUIHierarchyViewDelegate by default.

    class MyController: FUIHierarchyViewController {}
    

    Override viewDidLoad and do some setup here. You should register your custom cell if needed. Otherwise hierarchy view will use FUIHierarchyCollectionItem by default.

    override func viewDidLoad() {
        super.viewDidLoad()
        hierarchyView.register(YourCustomCollectionViewCell.self, forCellWithReuseIdentifier: "ReuseIdentifierForYourCustomCell")
        // do more setup here.
    }
    

    Implement dataSource and delegate methods

    
    // Define your data model.
    var model = HierarchyViewModel()
    
    override func rootUUID(in hierarchyView: FUIHierarchyView) -> String? {
        return model.rootObject?.uuid
    }
    
    override func hierarchyView(_ hierarchyView: FUIHierarchyView, numberOfChildrenForItemWith uuid: String) -> Int {
        guard let object = model.getObject(for: uuid) else {
            preconditionFailure("Object with String: \(uuid) does not exsit in model")
        }
    
        if let children = object.children {
            return children.count
        }
    
        // Get children asynchronously if they haven't been loaded yet. When loading completes, cache those children for future access and insert children into hierarchy view by calling `insertChildren(of:at:)`.
        object.asyncFetchChildren { children in
            self.model.updateCache(objects: children)
            self.hierarchyView.insertChildren(of: uuid, at: IndexSet(integersIn: 0..<children.count))
        }
    
        // Return zero children before children is loaded.
        return 0
    }
    
    override func hierarchyView(_ hierarchyView: FUIHierarchyView, uuidForChildItemAt index: Int, with parentUUID: String) -> String {
        guard let parent = model.getObject(for: parentUUID) else {
            preconditionFailure("Parent object with String: \(parentUUID) does not exsit")
        }
    
        guard let children = parent.children else {
            preconditionFailure("Children of parent: \(parent) is not loaded yet")
        }
    
        return children[index].uuid
    }
    
    override func hierarchyView(_ hierarchyView: FUIHierarchyView, parentForItemWith uuid: String) -> String? {
        guard let object = model.getObject(for: uuid) else {
            preconditionFailure("Object with String: \(uuid) does not exsit in model")
        }
    
        if let parent = object.parent {
            return parent.uuid
        }
    
        // Get parent asynchronously if they haven't been loaded yet. When loading completes, cache the parent for future access and insert it into hierarchy view by calling `invalidateParent(of:)`.
        object.asyncFetchParent { parent in
            guard let parent = parent else {
                return
            }
    
            self.model.updateCache(objects: [parent])
            self.model.updateRootObject(newRootObject: parent)
            self.hierarchyView.invalidateParent(of: uuid)
        }
    
        // Return nil before parent is loaded.
        return nil
    }
    
    override func hierarchyView(_ hierarchyView: FUIHierarchyView, cellForItemWith uuid: String) -> FUIHierarchyCollectionItem {
        let cell = hierarchyView.dequeueReusableCell(withReuseIdentifier: ReuseIdentifierForYourCustomCell, with: uuid) as! YourCustomCollectionViewCell
        guard let object = model.getObject(for: uuid) else {
        return cell
        }
    
        cell.title.text = object.name
        cell.subtitle.text = object.type
        cell.body.text = object.location
        cell.accessoryType = .disclosureIndicator
        if object.numberOfChildren > 0 {
            cell.isHierarchyButtonHidden = false
            cell.hierarchyAttributeText = String(object.numberOfChildren)
        }
        else {
            cell.isHierarchyButtonHidden = true
        }
    
        return cell
    }
    
    override func hierarchyView(_ hierarchyView: FUIHierarchyView, titleForItemWith uuid: String) -> String? {
        return model.getObject(for: uuid)?.name
    }
    
    

    Theming

    Supported class paths:

    fdlHierarchyViewController_hierarchyView {}
    
    See more

    Declaration

    Swift

    open class FUIHierarchyViewController : UIViewController, FUIHierarchyViewDataSource, FUIHierarchyViewDelegate
  • A view that manages a collection of items in a multi-column layout.

    Initial Loading Process:

    1. Hierarchy view asks data source for a root item and put it in the first column. Hierarchy view will be empty if nil is returned for root. If so, hierarchy view finishes loading.
    2. Hierarchy view asks data source for number of children of the root and get each child item iteratively.
    3. Hierarchy view asks data source for the parent of root item. If that parent exists, insert it into preview column before the root.

    HierarchyView

    Interaction Behavior:

    Expand Children

    Tap on the hierarchy accessory view will drill down one level in the hierarchy view to show the children of tapped item.

    HierarchyView

    HierarchyView

    Swipe

    Quick swipe left/right to view the previous or next level in the hierarchy.

    HierarchyView

    HierarchyView

    Pan

    Pan left/right to navigate further in hierarchy view.

    HierarchyView

    Usage

    Have your data source object conform to FUIHierarchyViewDataSource protocol and set it to hierarchy view’s dataSource property.

    class YourHierarchyViewDataSource: FUIHierarchyViewDataSource {}
    
    hierarchyView.dataSource = YourHierarchyViewDataSource()
    

    Register your custom cell if needed. Otherwise hierarchy view will use FUIHierarchyCollectionItem by default.

    hierarchyView.register(YourCustomCollectionViewCell.self, forCellWithReuseIdentifier: "ReuseIdentifierForYourCustomCell")
    

    Implement dataSource methods.

    // Define your data model.
    var model = HierarchyViewModel()
    
    func rootUUID(in hierarchyView: FUIHierarchyView) -> String? {
        return model.rootObject?.uuid
    }
    
    func hierarchyView(_ hierarchyView: FUIHierarchyView, numberOfChildrenForItemWith uuid: String) -> Int {
        guard let object = model.getObject(for: uuid) else {
            preconditionFailure("Object with String: \(uuid) does not exsit in model")
        }
    
        if let children = object.children {
            return children.count
        }
    
        // Get children asynchroniously if they haven't been loaded yet. When loading completes, cache those children for future access and insert children into hierarchy view by calling `insertChildren(of:at:)`.
        object.asyncFetchChildren { children in
            self.model.updateCache(objects: children)
            self.hierarchyView.insertChildren(of: uuid, at: IndexSet(integersIn: 0..<children.count))
        }
    
        // Return zero children before children is loaded.
        return 0
    }
    
    func hierarchyView(_ hierarchyView: FUIHierarchyView, uuidForChildItemAt index: Int, with parentUUID: String) -> String {
        guard let parent = model.getObject(for: parentUUID) else {
            preconditionFailure("Parent object with String: \(parentUUID) does not exsit")
        }
    
        guard let children = parent.children else {
            preconditionFailure("Children of parent: \(parent) is not loaded yet")
        }
    
        return children[index].uuid
    }
    
    func hierarchyView(_ hierarchyView: FUIHierarchyView, parentForItemWith uuid: String) -> String? {
        guard let object = model.getObject(for: uuid) else {
            preconditionFailure("Object with String: \(uuid) does not exsit in model")
        }
    
        if let parent = object.parent {
            return parent.uuid
        }
    
        // Get parent asynchronously if they haven't been loaded yet. When loading completes, cache the parent for future access and insert it into hierarchy view by calling `invalidateParent(of:)`.
        object.asyncFetchParent { parent in
            guard let parent = parent else {
                return
            }
    
            self.model.updateCache(objects: [parent])
            self.model.updateRootObject(newRootObject: parent)
            self.hierarchyView.invalidateParent(of: uuid)
        }
    
        // Return nil before parent is loaded.
        return nil
    }
    
    func hierarchyView(_ hierarchyView: FUIHierarchyView, cellForItemWith uuid: String) -> FUIHierarchyCollectionItem {
        let cell = hierarchyView.dequeueReusableCell(withReuseIdentifier: ReuseIdentifierForYourCustomCell, with: uuid) as! YourCustomCollectionViewCell
        guard let object = model.getObject(for: uuid) else {
            return cell
        }
    
        cell.title.text = object.name
        cell.subtitle.text = object.type
        cell.body.text = object.location
        cell.accessoryType = .disclosureIndicator
        if object.numberOfChildren > 0 {
            cell.isHierarchyButtonHidden = false
            cell.hierarchyAttributeText = String(object.numberOfChildren)
        }
        else {
            cell.isHierarchyButtonHidden = true
        }
    
        return cell
    }
    
    func hierarchyView(_ hierarchyView: FUIHierarchyView, titleForItemWith uuid: String) -> String? {
        return model.getObject(for: uuid)?.name
    }
    

    Make your delegate object conform to FUIHierarchyViewDelegate protocol and assign it to hierarchy view’s delegate property if needed.

    class YourHierarchyViewDelegate: FUIHierarchyViewDelegate {}
    
    hierarchyView.delegate = YourHierarchyViewDelegate()
    

    Theming

    Supported class paths:

    fdlFUIHierarchyView {}
    fdlFUIHierarchyView_header {}
    
    See more

    Declaration

    Swift

    open class FUIHierarchyView : UIView, FUIContentCopyable
  • A concrete layout class that manages the layout of hierarchy view.

    This layout organizes items into different columns from left to right (right to left if in opposite layout direction) where items in one column happens to be the children of expanded item in the previous column. This layout is specially designed for hierarchy view so it is supposed to be used along with hierarchy view.

    See more

    Declaration

    Swift

    open class FUIHierarchyCollectionViewLayout : UICollectionViewLayout, UIScrollViewDelegate
  • The FUIHierarchyViewDelegate protocol defines methods that allow you to manage the selection of items or tapping on hierarchy accessory view of collection item cell in a hierarchy view. The methods of this protocol are all optional.

    See more

    Declaration

    Swift

    @objc
    public protocol FUIHierarchyViewDelegate
  • An object that adopts the UICollectionViewDataSource protocol is responsible for providing the data required by a hierarchy view. It also handles the creation and configuration of cells used by the hierarchy view to display your data.

    See more

    Declaration

    Swift

    public protocol FUIHierarchyViewDataSource : AnyObject
  • FUIHierarchyItemTableViewCell is a table view UI component which extends FUIObjectBaseTableViewCell for showing a collection item’s business object content and hierarchy information (e.g. number of children in its next level). It is identical to FUIHierarchyCollectionItem in terms of the configuration of inner view and hierarchy indicator.

    Initialization and Configuration:

    To use FUIHierarchyItemTableViewCell, it should be dequeued from hierarchyView and returned in the data source method in FUIHierarchyViewDataSource.

    Example of setting an FUIHierarchyCollectionItem in a table view:

       cell.title.text = "Business Object Title"
       cell.subtitle.text = "Business Object Subtitle"
       cell.footnote.text = "Business Object Footnote"
       cell.hierarchyIndicator.title.text = "128"
       cell.status.text = "Business Object Status"
       cell.accessoryType = .disclosureIndicator
    

    Settings of Hierarchy Indicator:

    Similar to FUIHierarchyCollectionItem, hierarchy indicator is used to display related hierarchy information. To customize a different text in hierarchy indicator, set the text for title property of the cell’s FUIHierarchyIndicator.

       cell.hierarchyIndicator.title.text = "My Title"
    

    Likewise, hierarchy indicator by default is displayed in a vertical aligned multi-line mode in FUIHierarchyCollectionItem. To display in single-line mode, configure the isMultiline property of the cell’s FUIHierarchyIndicator.

       cell.hierarchyIndicator.isMultiline = false
    

    Layout of Hierarchy Indicator in Table View:

    The default width of the space showing hierarchy indicator is 38px in multi-line mode and 74px in multi-line mode. So the table view controller consuming the FUIHierarchyItemTableViewCell should enforce this minimum layout margin based on its display mode. The recommended technique for managing this is to set the table view controller’s additionalSafeAreaInsets property accordingly.

    override func viewDidLoad() {
       self.tableView.showsVerticalScrollIndicator = false
       self.tableView.insetsContentViewsToSafeArea = false
       if UIView.userInterfaceLayoutDirection(for: self.view.semanticContentAttribute) == .leftToRight {
           self.additionalSafeAreaInsets.right = 38
       } else {
           self.additionalSafeAreaInsets.left = 38
       }
    }
    

    Default Styling:

    Depending on the selection state, the tint color and button style of hierarchy icon, the font size of the title text, and the cell’s background color will be updated automatically.

    Customize Selection Behavior:

    Similar to FUIHierarchyCollectionItem, selection behavior can be customized by conforming to FUIHierarchyViewDelegate and then implementing the hierarchyButtonTappedForItemWith method.

    AccessoryView, AccessoryType, and EditingAccessoryView

    Standard UITableViewCell properties like accessoryView, accessoryType, and editingAccessoryView are supported.

    Theming

    Supported class paths:

       fdlFUIBaseCollectionViewCell {}
       fdlFUIBaseCollectionViewCell_title {}
       fdlFUIBaseCollectionViewCell_subtitle {}
       fdlFUIBaseCollectionViewCell_footnote {}
       fdlFUIBaseCollectionViewCell_detailImageView {}
    

    Please refer to FUIHierarchyItemView and FUIHierarchyIndicator documentation for all supported attributes.

    See more

    Declaration

    Swift

    open class FUIHierarchyItemTableViewCell : FUIObjectBaseTableViewCell<FUIHierarchyItemView>
  • A header view sits at top of hierarchy view. Header label displays the title of the selected parent item in previous section. You can use left/right button to navigate back or forth in the hierarchy.

    Theming

    Supported class paths:

    fdlFUIHierarchyViewHeader {}
    fdlFUIHierarchyViewHeader_title {}
    fdlFUIHierarchyViewHeader_leftButton {}
    fdlFUIHierarchyViewHeader_rightButton {}
    

    Please refer to FUIButton documentation for all supported attributes.

    See more

    Declaration

    Swift

    open class FUIHierarchyViewHeader : UIView, FUIViewBorderDrawing
  • Base inner view showing business object information for FUIHierarchyItemTableViewCell and FUIHierarchyCollectionItem.

    Example Initialization and Configuration:

       let view = FUIHierarchyItemView()
       view.title.text = "Business Object Title"
       view.subtitle.text = "Business Object Subtitle"
       view.footnote.text = "Business Object Footnote"
       view.status.text = "Business Object Status"
       view.statusImageView.image = UIImage(named: <#image#>)
       view.iconImages = ["1", FUIIconLibrary.indicator.veryHighPriority.withRenderingMode(.alwaysTemplate)]
    

    Theming

    Supported TEXT class paths:

       fdlFUIHierarchyItemView_title {}
       fdlFUIHierarchyItemView_subtitle {}
       fdlFUIHierarchyItemView_footnote {}
       fdlFUIHierarchyItemView_status {}
    

    Supported TEXT properties:

       font-color: Color;
       font-style: UIFontTextStyle;
       text-align: NSTextAlignment;
    

    Supported IMAGE class paths:

       fdlFUIHierarchyItemView_detailImageView {}
    

    Supported IMAGE properties:

       tint-color: Color;
    
    See more

    Declaration

    Swift

    open class FUIHierarchyItemView : FUIObjectViewBase, FUIHierarchyItemComponent
  • FUIHierarchyCollectionItem is a collection view UI component which extends FUITableViewAccessoryDrawingCollectionViewCell for showing a collection item’s business object content and hierarchy information (e.g. number of children in its next level). It is the default cell for displaying hierarchy items in an FUIHierarchyView.

    Initialization and Configuration:

    To use FUIHierarchyCollectionItem, it should be dequeued from hierarchyView and returned in the data source method in FUIHierarchyViewDataSource.

    Example of setting an FUIHierarchyCollectionItem by implementing cellForItemWith in the hierarchy view:

       cell.title.text = "Business Object Title"
       cell.subtitle.text = "Business Object Subtitle"
       cell.footnote.text = "Business Object Footnote"
       cell.accessoryType = .disclosureIndicator
       cell.statusImage = FUIIconLibrary.indicator.veryHighPriority
       cell.hierarchyIndicator.title.text = "999,999"
    

    Hierarchy Indicator:

    Hierarchy indicator provides a stacked view which includes two components: a text view, and a hierarchy icon. In hierarchy view, the text view is used to show the number of children belongs to the specific hierarchy item. Once the hierarchy indicator is tapped, the hierarchy view will be expanded to display a list of its children in a new column. The icon indicates that if the hierarchy item has been expanded or not. To customize a different text in hierarchy indicator, set the text for title property of the cell’s FUIHierarchyIndicator.

       cell.hierarchyIndicator.title.text = "My Title"
    

    Hierarchy indicator has two ways to layout its components: multi-line mode and single-line mode. By default, it is displayed in a vertical aligned multi-line mode. To horizontally align its components in a single-line mode, configure the isMultiline property of the cell’s FUIHierarchyIndicator.

       cell.hierarchyIndicator.isMultiline = false
    

    Default Styling:

    Depending on the selection state, the tint color and button style of hierarchy icon, the font size of the title text, and the cell’s background color will be updated automatically.

    Customize Selection Behavior:

    By default after selection the hierarchy item cell will be expanded. Selection behavior can be customized by conforming to FUIHierarchyViewDelegate and then implementing the hierarchyButtonTappedForItemWith method. To support additional gesture handling, a developer would usually add a gesture recognizer. This can be added directly to the cell when it is being dequeued, or added to collection view containing the cell.

    In the following example, a long press gesture recognizer is added to each hierarchy collection cell:

       let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(didLongPress(_:)))
       longPressGestureRecognizer.minimumPressDuration = 0.5
       cell.addGestureRecognizer(longPressGestureRecognizer)
    

    Theming:

    Supported class paths:

       fdlFUIHierarchyCollectionItem {}
    

    Please refer to FUIHierarchyItemView and FUIHierarchyIndicator documentation for all supported attributes.

    See more

    Declaration

    Swift

    open class FUIHierarchyCollectionItem : FUITableViewAccessoryDrawingCollectionViewCell<FUIHierarchyItemView>, InnerViewContainerEventHandling, FUIContentCopyable
  • FUIHierarchyState is an hierarchy object that defines its selection state: normal or selected.

    See more

    Declaration

    Swift

    public struct FUIHierarchyState : Hashable
    extension FUIHierarchyState: Enableable
    extension FUIHierarchyState: Defaultable