Giter Club home page Giter Club logo

ios-form's Introduction

iOS Form

Form Demo New Contact
Form demo New Contact

Implement iOS Form with UITableView

Create a base controller

Base class FormViewController with

  • A table view
  • A data source to handle data
  • Implement table view's data source and delegate
class FormViewController: UIViewController {

  let tableView = UITableView(frame: .zero, style: .grouped)
  let dataSource = FormDataSource()

  override func viewDidLoad() {
    super.viewDidLoad()
    configure()
  }
}

// MARK: - UITableViewDataSource

extension FormViewController: UITableViewDataSource {

  func numberOfSections(in tableView: UITableView) -> Int {
    dataSource.sections.count
  }

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    dataSource.sections[section].fields.count
  }

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let field = dataSource.sections[indexPath.section].fields[indexPath.row]
    return field.dequeue(for: tableView, at: indexPath)
  }
}

// MARK: - UITableViewDelegate

extension FormViewController: UITableViewDelegate {

  func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let field = dataSource.sections[indexPath.section].fields[indexPath.row]
    return field.height
  }

  func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    dataSource.sections[section].header?.dequeue(for: tableView, in: section)
  }

  func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    guard let header = dataSource.sections[section].header else { return .zero }
    return header.height
  }

  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let field = dataSource.sections[indexPath.section].fields[indexPath.row]
    field.tableView(tableView, didSelectRowAt: indexPath)
  }
}

Detail about FormDataSource

The class FormDataSource contains data that is used for the form.

final class FormDataSource {

  private(set) var sections: [FormSection] = []
}

FormSection

FormSection contains data for each section on the table view.

final class FormSection {

  var key: String
  var header: FormHeader?
  var fields: [FormField]

  init(key: String, header: FormHeader? = nil, fields: [FormField]) {
    self.key = key
    self.header = header
    self.fields = fields
  }
}

FormHeader

A object conform to FormHeader protocol, it will contains only the configuration of a header.

FormHeader makes it easy to create and maintain a header in a FormSection.

import UIKit

protocol FormHeader: AnyObject {

  var key: String { get }
  var height: CGFloat { get }

  func register(for tableView: UITableView)
  func dequeue(for tableView: UITableView, in section: Int) -> UIView?
}

How the implementation might look:

final class TitleFormHeader {

  let key: String
  let viewModel: TitleHeaderFooterViewModel

  init(key: String, viewModel: TitleHeaderFooterViewModel) {
    self.key = key
    self.viewModel = viewModel
  }
}

extension TitleFormHeader: FormHeader {

  var height: CGFloat { 60.0 }

  func register(for tableView: UITableView) {
    tableView.register(TitleHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: "TitleHeaderFooterView")
  }

  func dequeue(for tableView: UITableView, in section: Int) -> UIView? {
    let view = tableView.dequeueReusableHeaderFooterView(
      withIdentifier: "TitleHeaderFooterView"
    ) as? TitleHeaderFooterView
    view?.configure(with: viewModel)
    return view
  }
}

FormField

FormField is the most important protocol. For cells in table view, we will have field objects that carry the logic configuration of a view. We will create fields that conform FormField for all the cells we want to display in a table view.

protocol FormField: AnyObject {

  var key: String { get }
  var height: CGFloat { get }
  var delegate: FormFieldDelegate? { get set }

  func register(for tableView: UITableView)
  func dequeue(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell
  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
}

Here is an example about an implementation of FormField

final class TextInputFormField {

  let key: String
  var viewModel: TextInputViewModel

  weak var delegate: FormFieldDelegate?

  init(key: String, viewModel: TextInputViewModel) {
    self.key = key
    self.viewModel = viewModel
  }
}

// MARK: - FormField

extension TextInputFormField: FormField {

  var height: CGFloat { 44.0 }

  func register(for tableView: UITableView) {
    tableView.register(TextInputCell.self, forCellReuseIdentifier: "TextInputCell")
  }

  func dequeue(for tableView: UITableView, at indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "TextInputCell", for: indexPath) as! TextInputCell
    cell.delegate = self
    cell.configure(viewModel)
    return cell
  }
}

Form Demo

Check out the demo for more detail about different types of cell.

git clone [email protected]:nimblehq/ios-form.git

pod install

License

This project is Copyright (c) 2014 and onwards. It is free software, and may be redistributed under the terms specified in the LICENSE file.

About

Nimble

This project is maintained and funded by Nimble.

We love open source and do our part in sharing our work with the community! See our other projects or hire our team to help build your product.

ios-form's People

Contributors

suho avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.