Skip to Content
Technical Articles

Styling Fiori iOS Components Using NUI and SwiftUI

Table of Contents

Introduction
Prerequisites
Let’s Start
Integrate FUIFilterFormCell with SwiftUI
Integrate NUI
Result

Introduction

SAP has provided multiple components called SAP Fiori for iOS. We can easily customize these compnents using the API’s provided by the SAPFiori SDK.

But in a few scenarios, there are no default API’s available to customize these controls.

In this blog post, I will explain how to use FUIFilterFormCell with SwiftUI and customize it using a CSS-like stylesheet with .nss.

Prerequisites

Let’s Start

 

Integrate FUIFilterFormCell with SwiftUI

 

Create a new SwiftUI project called NSSStyleDemo. (You can give any project name as you wish.🙂)

For this demo, we will require the following SAP frameworks.

  • SAPFoundation.xcframework
  • SAPFiori.xcframework
  • SAPCommon.xcframework

Create a new SwiftUI file FilterTableView.swift.

Once the file has been created, copy-paste the below code.

import SwiftUI
import SAPFiori

struct FilterTableView {
    
    // MARK: - Properties
    
    typealias UIViewType = UITableView
    let tableView = UITableView(frame: .zero, style: .plain)
    
}

// MARK: - UIViewRepresentable

extension FilterTableView: UIViewRepresentable {
    
    func makeUIView(context: Context) -> UITableView {
        setupDatasourceDelegate(context)
        setupTable()
        
        return tableView
    }
    
    func updateUIView(_ uiView: UITableView, context: Context) { }
    
    func makeCoordinator() -> FilterTableViewCoordinator {
        FilterTableViewCoordinator(self)
    }
    
}

// MARK: - Private

private extension FilterTableView {
    
    func setupTable() {
        tableView.estimatedRowHeight = 80
        tableView.rowHeight = UITableView.automaticDimension
        tableView.register(FUIFilterFormCell.self, forCellReuseIdentifier: FUIFilterFormCell.reuseIdentifier)
        tableView.separatorStyle = .none
    }
    
    func setupDatasourceDelegate(_ context: Context) {
        tableView.dataSource = context.coordinator
        tableView.delegate = context.coordinator
    }
    
}

// MARK: - Coordinator

class FilterTableViewCoordinator: NSObject {
    
    // MARK: - Properties
    
    var parent: FilterTableView
    var selectedValues = [1]
    
    // MARK: - Initialization
    
    init(_ parent: FilterTableView) {
        self.parent = parent
    }
    
}

// MARK: - UITableViewDataSource, UITableViewDelegate

extension FilterTableViewCoordinator: UITableViewDataSource, UITableViewDelegate {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1 // return number of rows of data source
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let filterFormCell = tableView.dequeueReusableCell(withIdentifier: FUIFilterFormCell.reuseIdentifier, for: indexPath) as! FUIFilterFormCell
        filterFormCell.valueOptions = ["Option 1", "Option 2", "Option 3", "Option 4"]
        filterFormCell.keyName = "Filter Options"
        filterFormCell.allowsMultipleSelection = true
        filterFormCell.value = selectedValues
        filterFormCell.allowsEmptySelection = true
    
        filterFormCell.onChangeHandler = { newValue in
            self.selectedValues = newValue
            filterFormCell.setSelected(true, animated: true)
        }
        return filterFormCell
    }
    
}

In the above, we have used UIViewRepresentable which is a wrapper for a UIKit view — allowing you to integrate that UIView into your SwiftUI view hierarchy. Also, we have used Coordinator to coordinate with the view.

Now it’s time to render the component to the UI. Just copy-paste the below code and you are done!

import SwiftUI

struct ContentView: View {
    
    // MARK: - Body
    
    var body: some View {
        NavigationView {
            FilterTableView()
                .navigationBarTitle("NSS Stylesheet Demo", displayMode: .inline)
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
    
}

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

 

Now if you run the app it will use the default blue theme and it will look like below.

Integrate NUI

 

We can change the FUIFilterFormCell tint color by using SAPFiori SDK API as below.

filterFormCell.setTintColor(UIColor.orange, for: .normal)

But this API is no longer supported and XCode will prompt the below warning.

‘setTintColor(_:for:)’ is deprecated: No longer supported. 

SAPFiori provides an embedded NUI library for the styling of UI controls, using a CSS-like stylesheet with .nss file and using Theming Supported style classes

Let’s add the new empty file with a .nss extension. E.g. Theme.nss

Once the file has been created, copy-paste the below code.

fdlFUIFilterFormCell_item_titleLabel {
    font-color: #BB0000;
}

fdlFUIFilterFormCell_item_titleLabel_selected {
    font-color: #2B7D2B;
}

 

Copy-paste the below code in didFinishLaunchingWithOptions in AppDelegate.swift file.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    NUISettings.initWithStylesheet(name: "Theme")
    return true
}

We are done.

Result

With this blog post, you have learned,

  • Integration of FUIFilterFormCell with SwiftUI
  • Customize the component with .nss stylesheet.

 

Hope this helps!

Your thoughts matter! 😊

GD

1 Comment
You must be Logged on to comment or reply to a post.