Overview
FormUI provides an easy way to build native forms for iOS. It is inspired by SwiftUI and takes advantage of new technologies like Combine and result builders. However, it is entirely implemented in UIKit which gives it more options for customization.
FormUI aims to be lightweight and unopinionated. It solves the troublesome parts of making forms—like counting sections and hiding rows—but leaves you to fill in the details for your specific use case.
Examples
Requirements
- iOS 13.0+
- Swift 5.3+
Installation
This is a pre-release version of FormUI. The API is subject to change without warning.
Swift Package Manager
To install FormUI using the Swift Package Manager, add the following value to your Package.swift
:
dependencies: [
.package(url: "https://github.com/james01/FormUI.git", .upToNextMajor(from: "0.1.0"))
]
Usage
Creating a Form
Create a form by subclassing FormViewController
.
import FormUI
class MyFormViewController: FormViewController {
convenience init() {
self.init(style: .grouped)
}
override func viewDidLoad() {
super.viewDidLoad()
form = Form {
Section {
Row(style: .default) { (cell) in
cell.textLabel?.text = "Hello World"
}
}
}
}
}
The
Form
andSection
initializers take advantage of the result builder feature of Swift that was unofficially introduced in Swift 5.1, and officially introduced in Swift 5.4.
Handling Row Selection
Handle row selection by passing a handler to the onSelect(_:)
method of a row. This handler will be called every time the row is selected.
Row(style: .default) { (cell) in
cell.textLabel?.text = "Tap Me"
}.onSelect { (tableView, indexPath) in
tableView.deselectRow(at: indexPath, animated: true)
print("Hello World")
}
Dynamically Hiding and Showing Rows
FormUI makes it easy to hide and show rows. This is an otherwise complicated task when using the default UITableView
.
First, define a published variable to keep track of whether the row is hidden.
@Published var isRowHidden = true
Then, pass the projected value of that variable (i.e., $isRowHidden
) to the hidden(_:)
method on the row you want to hide. Every time isRowHidden
changes its value, the row will automatically show or hide itself.
For more information on the
Published
property wrapper, see its documentation.
Section {
Row(style: .default) { (cell) in
cell.textLabel?.text = "Tap to Toggle Row"
}.onSelect { (tableView, indexPath) in
tableView.deselectRow(at: indexPath, animated: true)
self.isRowHidden.toggle()
}
Row(style: .default) { (cell: UITableViewCell) in
cell.textLabel?.text = "Hidden"
}.hidden($isRowHidden)
Row(style: .default) { (cell) in
cell.textLabel?.text = "Not Hidden"
}
}
You can hide and show sections in a similar way.
ForEach
Using Oftentimes you'll want to generate rows or sections from a static data source such as an enum. Use ForEach
in these situations.
enum Theme: String, CaseIterable {
case light
case dark
case system
}
...
Section(header: "Theme") {
ForEach(Theme.self) { (theme) -> Row in
Row(style: .default) { (cell) in
cell.textLabel?.text = theme.rawValue.capitalized
}
}
}
ForEach
can also be used with an array of data.
let desserts = [
"🍪 Cookies",
"🍫 Chocolate",
"🍦 Ice Cream",
"🍭 Candy",
"🍩 Doughnuts",
"🍰 Cake"
]
...
Section(header: "Desserts") {
ForEach(0..<desserts.count) { (n) -> Row in
Row(style: .default) { (cell) in
cell.textLabel?.text = desserts[n]
}
}
}
Author
James Randolph (@jamesrandolph01)
License
FormUI is released under the MIT license. See LICENSE for details.