A simple way to create a UITableView for settings in Swift.

Overview

QuickTableViewController

GitHub Actions Codecov Carthage compatible CocoaPods Compatible Platform Swift 5

A simple way to create a table view for settings, including:

  • Table view cells with UISwitch
  • Table view cells with center aligned text for tap actions
  • A section that provides mutually exclusive options
  • Actions performed when the row reacts to the user interaction
  • Easy to specify table view cell image, cell style and accessory type

Usage

Set up tableContents in viewDidLoad:

import QuickTableViewController

final class ViewController: QuickTableViewController {

  override func viewDidLoad() {
    super.viewDidLoad()

    tableContents = [
      Section(title: "Switch", rows: [
        SwitchRow(text: "Setting 1", switchValue: true, action: { _ in }),
        SwitchRow(text: "Setting 2", switchValue: false, action: { _ in })
      ]),

      Section(title: "Tap Action", rows: [
        TapActionRow(text: "Tap action", action: { [weak self] in self?.showAlert($0) })
      ]),

      Section(title: "Navigation", rows: [
        NavigationRow(text: "CellStyle.default", detailText: .none, icon: .named("gear")),
        NavigationRow(text: "CellStyle", detailText: .subtitle(".subtitle"), icon: .named("globe")),
        NavigationRow(text: "CellStyle", detailText: .value1(".value1"), icon: .named("time"), action: { _ in }),
        NavigationRow(text: "CellStyle", detailText: .value2(".value2"))
      ], footer: "UITableViewCellStyle.Value2 hides the image view."),

      RadioSection(title: "Radio Buttons", options: [
        OptionRow(text: "Option 1", isSelected: true, action: didToggleSelection()),
        OptionRow(text: "Option 2", isSelected: false, action: didToggleSelection()),
        OptionRow(text: "Option 3", isSelected: false, action: didToggleSelection())
      ], footer: "See RadioSection for more details.")
    ]
  }

  // MARK: - Actions

  private func showAlert(_ sender: Row) {
    // ...
  }

  private func didToggleSelection() -> (Row) -> Void {
    return { [weak self] row in
      // ...
    }
  }

}

NavigationRow

Detail Text Styles

NavigationRow(text: "UITableViewCellStyle.default", detailText: .none)
NavigationRow(text: "UITableViewCellStyle", detailText: .subtitle(".subtitle")
NavigationRow(text: "UITableViewCellStyle", detailText: .value1(".value1")
NavigationRow(text: "UITableViewCellStyle", detailText: .value2(".value2"))

Subtitle and the initializers with title/subtitle are deprecated and will be removed in v2.0.0.

Accessory Type

  • The NavigationRow shows with different accessory types based on the action and accessoryButtonAction closures:
var accessoryType: UITableViewCell.AccessoryType {
  switch (action, accessoryButtonAction) {
  case (nil, nil):      return .none
  case (.some, nil):    return .disclosureIndicator
  case (nil, .some):    return .detailButton
  case (.some, .some):  return .detailDisclosureButton
  }
}
  • The action will be invoked when the table view cell is selected.
  • The accessoryButtonAction will be invoked when the accessory button is selected.

Images

enum Icon {
  case named(String)
  case image(UIImage)
  case images(normal: UIImage, highlighted: UIImage)
}
  • Images in table view cells can be set by specifying the icon of each row.
  • Table view cells in UITableViewCellStyle.value2 will not show the image view.

SwitchRow

  • A SwitchRow is representing a table view cell with a UISwitch as its accessoryView.
  • The action will be invoked when the switch value changes.

TapActionRow

  • A TapActionRow is representing a button-like table view cell.
  • The action will be invoked when the table view cell is selected.
  • The icon, detail text, and accessory type are disabled in TapActionRow.

OptionRow

  • An OptionRow is representing a table view cell with .checkmark.
  • The action will be invoked when the selected state is toggled.
let didToggleSelection: (Row) -> Void = { [weak self] in
  if let option = $0 as? OptionRowCompatible, option.isSelected {
    // to exclude the event where the option is toggled off
  }
}

RadioSection

  • RadioSection allows only one selected option at a time.
  • Setting alwaysSelectsOneOption to true will keep one of the options selected.
  • OptionRow can also be used with Section for multiple selections.

Customization

Rows

All rows must conform to Row and RowStyle. Additional interface to work with specific types of rows are represented as different protocols:

  • NavigationRowCompatible
  • OptionRowCompatible
  • SwitchRowCompatible
  • TapActionRowCompatible

Cell Classes

A customized table view cell type can be specified to rows during initialization.

// Default is UITableViewCell.
NavigationRow<CustomCell>(text: "Navigation", detailText: .none)

// Default is SwitchCell.
SwitchRow<CustomSwitchCell>(text: "Switch", switchValue: true, action: { _ in })

// Default is TapActionCell.
TapActionRow<CustomTapActionCell>(text: "Tap", action: { _ in })

// Default is UITableViewCell.
OptionRow<CustomOptionCell>(text: "Option", isSelected: true, action: { _ in })

Since the rows carry different cell types, they can be matched using either the concrete types or the related protocol:

let action: (Row) -> Void = {
  switch $0 {
  case let option as OptionRow<CustomOptionCell>:
    // only matches the option rows with a specific cell type
  case let option as OptionRowCompatible:
    // matches all option rows
  default:
    break
  }
}

Overwrite Default Configuration

You can use register(_:forCellReuseIdentifier:) to specify custom cell types for the table view to use. See CustomizationViewController for the cell reuse identifiers of different rows.

Table view cell classes that conform to Configurable can take the customization during tableView(_:cellForRowAt:):

protocol Configurable {
  func configure(with row: Row & RowStyle)
}

Additional setups can also be added to each row using the customize closure:

protocol RowStyle {
  var customize: ((UITableViewCell, Row & RowStyle) -> Void)? { get }
}

The customize closure overwrites the Configurable setup.

UIAppearance

As discussed in issue #12, UIAppearance customization works when the cell is dequeued from the storyboard. One way to work around this is to register nib objects to the table view. Check out AppearanceViewController for the setup.

tvOS Differences

  • UISwitch is replaced by a checkmark in SwitchCell.
  • TapActionCell does not use center aligned text.
  • NavigationRow.accessoryButtonAction is not available.
  • Cell image view's left margin is 0.

Limitation

When to use QuickTableViewController?

QuickTableViewController is good for presenting static table contents, where the sections and rows don't change dynamically after viewDidLoad.

It's possible to update the table contents by replacing a specific section or row. Using different styles on each row requires additional configuration as described in the Customization section.

When not to use it?

QuickTableViewController is not designed for inserting and deleting rows. It doesn't handle table view reload animation either. If your table view needs to update dynamically, you might want to consider other solutions such as IGListKit.

Documentation

Requirements

Pre 1.0 versions
QuickTableViewController iOS tvOS Xcode Swift
~> 0.1.0 8.0+ - 6.4 1.2
~> 0.2.0 8.0+ - 7.0 2.0
~> 0.3.0 8.0+ - 7.3 2.2
~> 0.4.0 8.0+ - 8.0 2.3
~> 0.5.0 8.0+ - 8.0 3.0
~> 0.6.0 8.0+ - 8.3 3.1
~> 0.7.0 8.0+ - 9.0 3.2
~> 0.8.0 8.0+ - 9.1 4.0
~> 0.9.0 8.0+ - 9.3 4.1

QuickTableViewController iOS tvOS Xcode Swift
~> 1.0.0 8.0+ 9.0+ 9.4 4.1
~> 1.1.0 8.0+ 9.0+ 10.1 4.2
~> 1.2.0 8.0+ 9.0+ 10.2 5.0
~> 1.3.0 9.0+ 9.0+ 11.7 5.2

Installation

Use Swift Package Manager

Follow the instructions at Adding Package Dependencies to Your App and use version v1.2.1 or later. (requires Xcode 11)

Use CocoaPods

Create a Podfile with the following specification and run pod install.

platform :ios, '9.0'
use_frameworks!

pod 'QuickTableViewController'

Use Carthage

Create a Cartfile with the following specification and run carthage update QuickTableViewController. Follow the instructions to add the framework to your project.

github "bcylin/QuickTableViewController"

Xcode 12 workaround Guide: https://github.com/Carthage/Carthage/blob/master/Documentation/Xcode12Workaround.mdx

Use Git Submodule

git submodule add -b master [email protected]:bcylin/QuickTableViewController.git Dependencies/QuickTableViewController
  • Drag QuickTableViewController.xcodeproj to your app project as a subproject.
  • On your application target's Build Phases settings tab, add QuickTableViewController-iOS to Target Dependencies.

License

QuickTableViewController is released under the MIT license. See LICENSE for more details. Image source: iconmonstr.

Comments
  • How can I change selected and deselect accessoryView image?

    How can I change selected and deselect accessoryView image?

    As title, I was hoping to change the select and deselect image for my menu. However if I use original table view delegate "didSelect" and "deSelect" method, multi-selection section stop working. Is there a proper way to change it. Thx

    opened by davidhsu1115 11
  • 3D Touch

    3D Touch

    This is a feature request for being able to peek/pop on a TapActionCell cell that presents something modally to be able to "preview" the view controller

    stale 
    opened by getaaron 9
  • Update to Swift 4.2

    Update to Swift 4.2

    • Ran the Swift 4.2 Migrator in Xcode 10
    • Tests still pass
    • No SwiftLint issues
    • Updated ruby-macho to the latest version supported by CocoaPods 1.5.3

    Closes https://github.com/bcylin/QuickTableViewController/issues/19.

    opened by getaaron 8
  • How to pass NavigationRow data and display in custom cell

    How to pass NavigationRow data and display in custom cell

    Hi, I am doing some customization with NavigationRow. I wanna use the title, detailText, icon, parameters in my custom cell. However, when I set it in configure(), it always crash due to unwrap my cell properties.

    Here's my code below. Thanks!

    class GlobalInviteTVCell: UITableViewCell {
    
        @IBOutlet weak var mainTitle: UILabel!
        @IBOutlet weak var subTitle: UILabel!
        @IBOutlet weak var showImage: UIImageView!
        override func awakeFromNib() {
            super.awakeFromNib()
            // Initialization code
        }
    
        override func setSelected(_ selected: Bool, animated: Bool) {
            super.setSelected(selected, animated: animated)
    
            // Configure the view for the selected state
        }
        
    }
    
    extension GlobalInviteTVCell: Configurable {
        
        func configure(with row: Row & RowStyle) {
            self.mainTitle.text = row.text
            self.subTitle.text = row.detailText?.text
            self.showImage.image = row.icon?.image
        }
        
        
    }
    
    
    stale 
    opened by davidhsu1115 7
  • How to disable a setting option

    How to disable a setting option

    Hi, I have just started using QuickTableViewController to create a settings tab for my iOS app. One of my settings (a toggle switch) is only applicable to users that have the premium version. How do I disable the switch, grey it out or hide it until the user has upgraded to Premium? Thanks.

    stale 
    opened by alamodey 7
  • Swift 5 migration

    Swift 5 migration

    All tests pass.

    • Migrated sample project and QuickTableViewController source code to Swift 5
    • Migrated English localization to en
    • Removed access modifiers considered redundant in Swift 5
    • Use .default for potential future unknown UITableViewCellStyles using Swift 5's new @unknown default for enums imported from C-based languages
    • Updated SwiftLint to 0.32.0 (version which supports Swift 5)

    Out of scope:

    • Updating Quick and Nimble to a newer version
    opened by getaaron 7
  • Any option to mount the tableview to a UIView?

    Any option to mount the tableview to a UIView?

    If I want to place the table view at a specific spot, how can I do that?

    I currently kinda just hack it by adding a parentView open var in QuickTableViewController. Then I have the option to set the parentView.

    // viewDidLoad
    parentView = parentView ?? view
    parentView?.addSubview(tableView)
    

    Does this library already provide a way to do it that I just didn't know?

    opened by EdmundLeex 7
  • How to reload the settings menu

    How to reload the settings menu

    Hi, I need to be able to programatically reload the settings view for two reasons:

    • some users are confused after they upgrade to premium that the menu still has options disabled as though they are not premium users
    • I have using this NavigationRow(text: "CellStyle", detailText: .value2(".value2")) and after a user selects a new option for .value2 I want my settings menu to display the new value instead of the initial one loaded at app launch

    Is it possible to reload the menu? Thanks.

    stale 
    opened by alamodey 5
  • Add option to configure TableView style for storyboard usage

    Add option to configure TableView style for storyboard usage

    This pull requests add the option to configure the TableView style in the initializer used by storyboards.

    I used the new initializer in my ViewController the following way:

        public required init?(coder: NSCoder) {
            super.init(coder: coder, style: .insetGrouped)
        }
    
    hacktoberfest-accepted 
    opened by Tobisaninfo 5
  • Feature/Added tvOS-UITests

    Feature/Added tvOS-UITests

    Purpose

    This is a feature to add UITests for tvOS.

    A brief description of what has changed and why it has changed

    Added:

    • Example_tvOSUITests.swift

    Ways to test feature or scenarios to try

    Run the tests for tvOS example app.

    opened by FraDeliro 5
  • Update the icon property of a NavigationRow

    Update the icon property of a NavigationRow

    Hi,

    Is it possible to update the icon property of a NavigationRow with the option that was chosen in the view I navigated to?

    This is my starting view, which has the action to push another view controller onto the stack. getCurrentAppIcon() in this view checks UIApplication.shared.alternateIconName and returns a named icon. The detail view just sets a new AlternateIcon. But I want the first view to show the newly chosen icon when I tap "< Back" in the nav bar.

    Section(title: "App Icon", rows: [
        NavigationRow(
            text: "App Icon",
            detailText: .none,
            icon: getCurrentAppIcon(),
            action: { [weak self] _ in
            self?.navigationController?.pushViewController(SettingsAppIconViewController(), animated: true)
        })
    ]),
    

    Thanks Ben

    opened by benhaldenby 4
Releases(v1.3.0)
  • v1.3.0(Oct 5, 2020)

  • v1.2.4(Jul 2, 2020)

  • v1.2.3(Jun 23, 2020)

  • v1.2.2(Jun 7, 2020)

  • v1.2.1(Dec 2, 2019)

  • v1.2.0(Jun 14, 2019)

  • v1.1.1(May 6, 2019)

    • Fix the animated OptionRow deselection
    • Invoke accessoryButtonAction asynchronously to match the behaviour of row action
    • Remove ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES from build settings
    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Jan 6, 2019)

  • v1.0.0(Sep 19, 2018)

  • v0.9.1(Apr 17, 2018)

  • v0.9.0(Apr 5, 2018)

    Breaking

    • Change the Icon type (since v0.2.0) from struct to enum:

      enum Icon {
        case named(String)
        case image(UIImage)
        case images(normal: UIImage, highlighted: UIImage)
      }
      
    • Rename the protocols (introduced in v0.8.1) that define specific rows regardless of their associated cell types:

      • NavigationRowCompatible
      • OptionSelectableOptionRowCompatible
      • SwitchableSwitchRowCompatible
      • TappableTapActionRowCompatible
    Source code(tar.gz)
    Source code(zip)
  • v0.8.4(Mar 21, 2018)

  • v0.8.3(Feb 17, 2018)

  • v0.8.2(Jan 1, 2018)

  • v0.8.1(Dec 11, 2017)

    Fixes

    • Unhighlight the selected row in the radio section when it's tapped with alwaysSelectsOneOption set to true
    • Fix the empty image name that causes CUICatalog: Invalid asset name supplied: ''
    • Allow OptionRow to be used with custom table view cells
    • Fix the actions that are not invoked in rows with custom table view cells
    Source code(tar.gz)
    Source code(zip)
  • v0.8.0(Dec 2, 2017)

  • v0.7.1(Oct 19, 2017)

  • v0.7.0(Aug 23, 2017)

    Breaking

    • Remove the accessory view from the AccessoryEnabled protocol
    • Merge IconEnabled and AccessoryEnabled properties into the RowStyle protocol

    Enhancements

    • Add OptionRow and RadioSection to support mutually exclusive options

    Fixes

    • Use both cell type and cell style as the reuse identifiers for navigation rows to distinguish customized cell classes
    Source code(tar.gz)
    Source code(zip)
  • v0.6.2(Aug 18, 2017)

  • v0.6.1(Aug 16, 2017)

    Enhancements

    • UI testing
    • Change sections and rows from structs to classes
    • Allow customized cell classes to implement the Configurable method in addition to the default setup

    Fixes

    • UISwitch animation #9
    Source code(tar.gz)
    Source code(zip)
  • v0.6.0(Aug 8, 2017)

    Breaking

    • Deprecate the customization using table view register(_:forCellReuseIdentifier:)
    • Move the tableView configuration from loadView() to viewDidLoad()

    Enhancements

    • Specify table view cell types to rows during initialization
    • Separate RowStyle from the original Row protocol
    • Add an additional cell customization ((UITableViewCell, Row & RowStyle) -> Void)? for each row

    Project Updates

    • CocoaPods 1.3.0
    Source code(tar.gz)
    Source code(zip)
  • v0.5.3(Apr 24, 2017)

    Fixes

    • Fix the cell reuse identifier of SwitchRow and TapActionRow to be compatible with 0.5.x
    • https://github.com/bcylin/QuickTableViewController/blob/develop/CHANGELOG.md#v053
    Source code(tar.gz)
    Source code(zip)
  • v0.5.2(Apr 14, 2017)

  • v0.5.1(Oct 8, 2016)

  • v0.5.0(Oct 5, 2016)

  • v0.4.0(Sep 20, 2016)

  • v0.3.0(Jun 10, 2016)

    Enhancements

    • Swift 2.2
    • SwitchRow now conforms to IconEnabled (#2, #4). Thanks to @drinkius.

    Project Updates

    • CocoaPods 1.0.1
    • Calculate code coverage
    • SwiftLint with Hound CI
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Jan 6, 2016)

    Breaking

    • Swift 2

    Enhancements

    • Row and Subtitle now conform to Equatable
    • Specify table view cell images with Icon, which includes highlighted image
    • Separate self.view from self.tableView in QuickTableViewController

    Fixes

    • Fix the access control on the overridden initializer

    Project Updates

    • Run tests on Travis CI
    • Clean up syntax with SwiftLint
    Source code(tar.gz)
    Source code(zip)
  • v0.1.1(Oct 19, 2015)

  • v0.1.0(Sep 8, 2015)

Owner
Cheng-Yao Lin
iOS app developer. Beer lover.
Cheng-Yao Lin
HoverConversion realized vertical paging with UITableView. UIViewController will be paged when reaching top or bottom of UITableView contentOffset.

HoverConversion ManiacDev.com referred. https://maniacdev.com/2016/09/hoverconversion-a-swift-ui-component-for-navigating-between-multiple-table-views

Taiki Suzuki 166 Feb 1, 2022
A simpler way to do cool UITableView animations! (╯°□°)╯︵ ┻━┻

TableFlip (╯°□°)╯︵ ┻━┻ ┬──┬ ノ( ゜-゜ノ) Animations are cool. UITableView isn't. So why not make animating UITableView cool? The entire API for TableFlip

Joe Fabisevich 555 Dec 9, 2022
Settings screen composing framework

THIS PROJECT IS NO LONGER MAINTAINED. HERE ARE SOME SUITABLE ALTERNATIVES: SwiftUI Form https://github.com/xmartlabs/Eureka https://github.com/neoneye

David Roman 1.3k Dec 25, 2022
Simple and beautiful stacked UIView to use as a replacement for an UITableView, UIImageView or as a menu

VBPiledView simple but highly effective animation and interactivity! By v-braun - viktor-braun.de. Preview Description Very simple and beautiful stack

Viktor Braun 168 Jan 3, 2023
Simple single-selection or multiple-selection checklist, based on UITableView

SelectionList Simple single-selection or multiple-selection checklist, based on UITableView. Usage let selectionList = SelectionList() selectionList.i

Yonat Sharon 111 Oct 6, 2022
A pixel perfect replacement for UITableView section index, written in Swift

MYTableViewIndex MYTableViewIndex is a re-implementation of UITableView section index. This control is usually seen in apps displaying contacts, track

Yury 520 Oct 27, 2022
INTUZ is presenting an interesting a Multilevel Expand/Collapse UITableView App Control to integrate inside your native iOS-based application

INTUZ is presenting an interesting a Multilevel Expand/Collapse UITableView App Control to integrate inside your native iOS-based application. MultilevelTableView is a simple component, which lets you use the tableview with multilevel tree view in your project.

INTUZ 3 Oct 3, 2022
A PageView, which supporting scrolling to transition between a UIView and a UITableView

YXTPageView ##A Page View, which support scrolling to transition between a UIView and a UITableView UIView (at the top) UITableView (at the bottom) In

Hanton Yang 68 May 25, 2022
A declarative api for working with UITableView.

⚡️ Lightning Table Lightning Table provides a powerful declarative API for working with UITableView's. Table views are the foundation of almost every

Electric Kangaroo 28 Aug 25, 2021
Easy UITableView drag-and-drop cell reordering

SwiftReorder NOTE: Some users have encountered compatibility issues when using this library with recent versions of iOS. For apps targeting iOS 11 and

Adam Shin 378 Dec 13, 2022
A cells of UITableView can be rearranged by drag and drop.

TableViewDragger This is a demo that uses a TableViewDragger. Appetize's Demo Requirements Swift 4.2 iOS 8.0 or later How to Install TableViewDragger

Kyohei Ito 515 Dec 28, 2022
Protocol-oriented UITableView management, powered by generics and associated types.

DTTableViewManager Features Powerful mapping system between data models and cells, headers and footers Automatic datasource and interface synchronizat

Denys Telezhkin 454 Nov 9, 2022
A UITableView extension that enables cell insertion from the bottom of a table view.

ReverseExtension UITableView extension that enabled to insert cell from bottom of tableView. Concept It is difficult to fill a tableview content from

Taiki Suzuki 1.7k Dec 15, 2022
A declarative wrapper approach to UITableView

Thunder Table Thunder Table is a useful framework which enables quick and easy creation of table views in iOS, making the process of creating complex

3 SIDED CUBE 20 Aug 25, 2022
APDynamicGrid is a SwiftUI package that helps you create consistent and animatable grids.

APDynamicGrid Overview APDynamicGrid is a SwiftUI package that helps you create consistent and animatable grids. The DynamicGrid View preserves the sa

Antonio Pantaleo 29 Jul 4, 2022
A no-nonsense way to write cleaner UITableViewDelegate and UITableViewDataSource in Swift.

CascadingTableDelegate A no-nonsense way to write cleaner UITableViewDelegate and UITableViewDataSource. Why is this library made? In common iOS devel

Ricardo Pramana Suranta 920 Dec 14, 2022
Elegant and easy way to integrate pagination with dummy views

AZTableView Controller Features Automatic pagination handling No more awkward empty TableView screen AZ TableView controller give you advantage to con

Afroz Zaheer 73 Oct 17, 2022
Simple static table views for iOS in Swift.

Simple static table views for iOS in Swift. Static's goal is to separate model data from presentation. Rows and Sections are your “view models” for yo

Venmo 1.3k Nov 19, 2022
PreviewTransition is a simple preview gallery UI controller with animated tranisitions.

PreviewTransition is a simple preview gallery UI controller with animated tranisitions. Swift UI library made by @Ramotion

Ramotion 2.1k Dec 19, 2022