{"id":2833,"url":"https://github.com/maxsokolov/TableKit","last_synced_at":"2025-08-03T12:31:13.124Z","repository":{"id":44777315,"uuid":"45779432","full_name":"maxsokolov/TableKit","owner":"maxsokolov","description":"Type-safe declarative table views.","archived":false,"fork":false,"pushed_at":"2023-04-19T09:59:15.000Z","size":1250,"stargazers_count":702,"open_issues_count":16,"forks_count":74,"subscribers_count":15,"default_branch":"master","last_synced_at":"2024-12-01T10:23:00.706Z","etag":null,"topics":["autolayout","generic","swift","uitableview","uitableviewcell"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maxsokolov.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2015-11-08T12:26:18.000Z","updated_at":"2024-11-18T09:57:07.000Z","dependencies_parsed_at":"2022-07-20T17:18:32.178Z","dependency_job_id":"ff4ba407-6654-4a61-9e94-2bb7aae5dba3","html_url":"https://github.com/maxsokolov/TableKit","commit_stats":{"total_commits":352,"total_committers":18,"mean_commits":"19.555555555555557","dds":0.07670454545454541,"last_synced_commit":"8bf4840d9d0475a92352f02f368f88b74eced447"},"previous_names":["maxsokolov/tablet.swift"],"tags_count":43,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxsokolov%2FTableKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxsokolov%2FTableKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxsokolov%2FTableKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxsokolov%2FTableKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maxsokolov","download_url":"https://codeload.github.com/maxsokolov/TableKit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228543145,"owners_count":17934432,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["autolayout","generic","swift","uitableview","uitableviewcell"],"created_at":"2024-01-05T20:16:24.033Z","updated_at":"2024-12-07T00:30:58.636Z","avatar_url":"https://github.com/maxsokolov.png","language":"Swift","funding_links":[],"categories":["UI"],"sub_categories":["Table View / Collection View","Layout","Other free courses"],"readme":"# TableKit\n\n\u003cp align=\"left\"\u003e\n\t\u003ca href=\"https://travis-ci.org/maxsokolov/TableKit\"\u003e\u003cimg src=\"https://api.travis-ci.org/maxsokolov/TableKit.svg\" alt=\"Build Status\" /\u003e\u003c/a\u003e\n\t\u003ca href=\"https://developer.apple.com/swift\"\u003e\u003cimg src=\"https://img.shields.io/badge/Swift_5.1-compatible-4BC51D.svg?style=flat\" alt=\"Swift 5.1 compatible\" /\u003e\u003c/a\u003e\n\t\u003ca href=\"https://github.com/Carthage/Carthage\"\u003e\u003cimg src=\"https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat\" alt=\"Carthage compatible\" /\u003e\u003c/a\u003e\n\t\u003ca href=\"https://cocoapods.org/pods/tablekit\"\u003e\u003cimg src=\"https://img.shields.io/badge/pod-2.11.0-blue.svg\" alt=\"CocoaPods compatible\" /\u003e\u003c/a\u003e\n\t\u003cimg src=\"https://img.shields.io/badge/platform-iOS-blue.svg?style=flat\" alt=\"Platform iOS\" /\u003e\n\t\u003ca href=\"https://raw.githubusercontent.com/maxsokolov/tablekit/master/LICENSE\"\u003e\u003cimg src=\"http://img.shields.io/badge/license-MIT-blue.svg?style=flat\" alt=\"License: MIT\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nTableKit is a super lightweight yet powerful generic library that allows you to build complex table views in a declarative type-safe manner.\nIt hides a complexity of `UITableViewDataSource` and `UITableViewDelegate` methods behind the scene, so your code will be look clean, easy to read and nice to maintain.\n\n# Features\n\n- [x] Type-safe generic cells\n- [x] Functional programming style friendly\n- [x] The easiest way to map your models or view models to cells\n- [x] Automatic cell registration*\n- [x] Correctly handles autolayout cells with multiline labels\n- [x] Chainable cell actions (select/deselect etc.)\n- [x] Support cells created from code, xib, or storyboard\n- [x] Support different cells height calculation strategies\n- [x] Support portrait and landscape orientations\n- [x] No need to subclass\n- [x] Extensibility\n\n# Getting Started\n\nAn [example app](Demo) is included demonstrating TableKit's functionality.\n\n## Basic usage\n\nCreate your rows:\n```swift\nimport TableKit\n\nlet row1 = TableRow\u003cStringTableViewCell\u003e(item: \"1\")\nlet row2 = TableRow\u003cIntTableViewCell\u003e(item: 2)\nlet row3 = TableRow\u003cUserTableViewCell\u003e(item: User(name: \"John Doe\", rating: 5))\n```\nPut rows into section:\n```swift\nlet section = TableSection(rows: [row1, row2, row3])\n```\nAnd setup your table:\n```swift\nlet tableDirector = TableDirector(tableView: tableView)\ntableDirector += section\n```\nDone. Your table is ready. Your cells have to conform to `ConfigurableCell` protocol:\n```swift\nclass StringTableViewCell: UITableViewCell, ConfigurableCell {\n\n    func configure(with string: String) {\n\t\t\n        textLabel?.text = string\n    }\n}\n\nclass UserTableViewCell: UITableViewCell, ConfigurableCell {\n\n    static var estimatedHeight: CGFloat? {\n        return 100\n    }\n\n    // is not required to be implemented\n    // by default reuse id is equal to cell's class name\n    static var reuseIdentifier: String {\n        return \"my id\"\n    }\n\n    func configure(with user: User) {\n\t\t\n        textLabel?.text = user.name\n        detailTextLabel?.text = \"Rating: \\(user.rating)\"\n    }\n}\n```\nYou could have as many rows and sections as you need.\n\n## Row actions\n\nIt nice to have some actions that related to your cells:\n```swift\nlet action = TableRowAction\u003cStringTableViewCell\u003e(.click) { (options) in\n\n    // you could access any useful information that relates to the action\n\n    // options.cell - StringTableViewCell?\n    // options.item - String\n    // options.indexPath - IndexPath\n    // options.userInfo - [AnyHashable: Any]?\n}\n\nlet row = TableRow\u003cStringTableViewCell\u003e(item: \"some\", actions: [action])\n```\nOr, using nice chaining approach:\n```swift\nlet row = TableRow\u003cStringTableViewCell\u003e(item: \"some\")\n    .on(.click) { (options) in\n\t\n    }\n    .on(.shouldHighlight) { (options) -\u003e Bool in\n        return false\n    }\n```\nYou could find all available actions [here](Sources/TableRowAction.swift).\n\n## Custom row actions\n\nYou are able to define your own actions:\n```swift\nstruct MyActions {\n    \n    static let ButtonClicked = \"ButtonClicked\"\n}\n\nclass MyTableViewCell: UITableViewCell, ConfigurableCell {\n\n    @IBAction func myButtonClicked(sender: UIButton) {\n\t\n        TableCellAction(key: MyActions.ButtonClicked, sender: self).invoke()\n    }\n}\n```\nAnd handle them accordingly:\n```swift\nlet myAction = TableRowAction\u003cMyTableViewCell\u003e(.custom(MyActions.ButtonClicked)) { (options) in\n\n}\n```\n## Multiple actions with same type\n\nIt's also possible to use multiple actions with same type:\n```swift\nlet click1 = TableRowAction\u003cStringTableViewCell\u003e(.click) { (options) in }\nclick1.id = \"click1\" // optional\n\nlet click2 = TableRowAction\u003cStringTableViewCell\u003e(.click) { (options) in }\nclick2.id = \"click2\" // optional\n\nlet row = TableRow\u003cStringTableViewCell\u003e(item: \"some\", actions: [click1, click2])\n```\nCould be useful in case if you want to separate your logic somehow. Actions will be invoked in order which they were attached.\n\u003e If you define multiple actions with same type which also return a value, only last return value will be used for table view.\n\nYou could also remove any action by id:\n```swift\nrow.removeAction(forActionId: \"action_id\")\n```\n\n# Advanced\n\n## Cell height calculating strategy\nBy default TableKit relies on \u003ca href=\"https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithSelf-SizingTableViewCells.html\" target=\"_blank\"\u003eself-sizing cells\u003c/a\u003e. In that case you have to provide an estimated height for your cells:\n```swift\nclass StringTableViewCell: UITableViewCell, ConfigurableCell {\n\n    // ...\n\n    static var estimatedHeight: CGFloat? {\n        return 255\n    }\n}\n```\nIt's enough for most cases. But you may be not happy with this. So you could use a prototype cell to calculate cells heights. To enable this feature simply use this property:\n```swift\nlet tableDirector = TableDirector(tableView: tableView, shouldUsePrototypeCellHeightCalculation: true)\n```\nIt does all dirty work with prototypes for you [behind the scene](Sources/TablePrototypeCellHeightCalculator.swift), so you don't have to worry about anything except of your cell configuration:\n```swift\nclass ImageTableViewCell: UITableViewCell, ConfigurableCell {\n\n    func configure(with url: NSURL) {\n\t\t\n        loadImageAsync(url: url, imageView: imageView)\n    }\n\n    override func layoutSubviews() {\n        super.layoutSubviews()\n        \n        contentView.layoutIfNeeded()\n        multilineLabel.preferredMaxLayoutWidth = multilineLabel.bounds.size.width\n    }\n}\n```\nYou have to additionally set `preferredMaxLayoutWidth` for all your multiline labels.\n\n## Functional programming\nIt's never been so easy to deal with table views.\n```swift\nlet users = /* some users array */\n\nlet click = TableRowAction\u003cUserTableViewCell\u003e(.click) {\n\n}\n\nlet rows = users.filter({ $0.state == .active }).map({ TableRow\u003cUserTableViewCell\u003e(item: $0.name, actions: [click]) })\n\ntableDirector += rows\n```\nDone, your table is ready.\n## Automatic cell registration\n\nTableKit can register your cells in a table view automatically. In case if your reusable cell id matches cell's xib name:\n\n```ruby\nMyTableViewCell.swift\nMyTableViewCell.xib\n\n```\nYou can also turn off this behaviour:\n```swift\nlet tableDirector = TableDirector(tableView: tableView, shouldUseAutomaticCellRegistration: false)\n```\nand register your cell manually.\n\n# Installation\n\n## CocoaPods\nTo integrate TableKit into your Xcode project using CocoaPods, specify it in your `Podfile`:\n\n```ruby\npod 'TableKit'\n```\n## Carthage\nAdd the line `github \"maxsokolov/tablekit\"` to your `Cartfile`.\n## Manual\nClone the repo and drag files from `Sources` folder into your Xcode project.\n\n# Requirements\n\n- iOS 8.0\n- Xcode 9.0\n\n# Changelog\n\nKeep an eye on [changes](CHANGELOG.md).\n\n# License\n\nTableKit is available under the MIT license. See LICENSE for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxsokolov%2FTableKit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaxsokolov%2FTableKit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxsokolov%2FTableKit/lists"}