{"id":15037514,"url":"https://github.com/neoneye/swiftyform","last_synced_at":"2025-05-16T11:06:39.861Z","repository":{"id":34015804,"uuid":"37772696","full_name":"neoneye/SwiftyFORM","owner":"neoneye","description":"iOS framework for creating forms","archived":false,"fork":false,"pushed_at":"2021-02-05T16:57:23.000Z","size":1602,"stargazers_count":1078,"open_issues_count":18,"forks_count":87,"subscribers_count":29,"default_branch":"master","last_synced_at":"2025-05-13T08:06:28.924Z","etag":null,"topics":["binding","form","ios","swift","uidatepicker","uipickerview","uislider","uitableview","validation"],"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/neoneye.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-06-20T14:31:03.000Z","updated_at":"2025-03-27T12:39:19.000Z","dependencies_parsed_at":"2022-07-13T21:53:36.594Z","dependency_job_id":null,"html_url":"https://github.com/neoneye/SwiftyFORM","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neoneye%2FSwiftyFORM","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neoneye%2FSwiftyFORM/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neoneye%2FSwiftyFORM/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neoneye%2FSwiftyFORM/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neoneye","download_url":"https://codeload.github.com/neoneye/SwiftyFORM/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254518383,"owners_count":22084374,"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":["binding","form","ios","swift","uidatepicker","uipickerview","uislider","uitableview","validation"],"created_at":"2024-09-24T20:34:52.978Z","updated_at":"2025-05-16T11:06:34.844Z","avatar_url":"https://github.com/neoneye.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch3 align=\"center\"\u003e\n\u003ca href=\"https://github.com/neoneye/SwiftyFORM\"\u003e\n\u003cimg src=\"Documentation/swiftyform_logo.png\" alt=\"SwiftyFORM by Simon Strandgaard\"/\u003e\n\u003cbr /\u003e\nSwiftyFORM\n\u003c/a\u003e\n\u003c/h3\u003e\n\n---\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://travis-ci.org/neoneye/SwiftyFORM\"\u003e\n        \u003cimg src=\"https://travis-ci.org/neoneye/SwiftyFORM.svg?branch=master\" alt=\"Build Status\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"http://cocoapods.org/pods/SwiftyFORM\"\u003e\n        \u003cimg src=\"https://img.shields.io/cocoapods/v/SwiftyFORM.svg?style=flat\" alt=\"Version\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"http://cocoapods.org/pods/SwiftyFORM\"\u003e\n        \u003cimg src=\"https://img.shields.io/cocoapods/p/SwiftyFORM.svg?style=flat\" alt=\"Platform\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://swift.org/package-manager\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/spm-compatible-brightgreen.svg?style=flat\" alt=\"Swift Package Manager\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/Carthage/Carthage\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/carthage-compatible-4BC51D.svg?style=flat\" alt=\"Carthage\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"http://cocoapods.org/pods/SwiftyFORM\"\u003e\n        \u003cimg src=\"https://img.shields.io/cocoapods/l/SwiftyFORM.svg?style=flat\" alt=\"MIT License\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cb\u003eSwiftyFORM is a lightweight iOS framework for creating forms\u003c/b\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://github.com/neoneye/SwiftyFORM/raw/master/Documentation/light_and_dark1.png\" alt=\"Dark Mode supported\" /\u003e \n\u003c/p\u003e\n\n\nBecause form code is hard to write, hard to read, hard to reason about. Has a slow turn around time. Is painful to maintain.\n\n[SwiftyFORM demo on YouTube](https://youtu.be/PKbVJ91uQdA)\n\n\n\u003ca href=\"mailto:neoneye@gmail.com?subject=Hire Simon Strandgaard\"\u003e\n\u003cimg src=\"Documentation/hire_simon_strandgaard@2x.png\" width=\"211\" height=\"34\"\u003e\u003c/a\u003e\n\n\n## Requirements\n\n- iOS 12+\n- Xcode 12+\n- Swift 5.1+\n\n\n## Features\n\n- [x] Several form items, such as textfield, buttons, sliders\n- [x] Some form items can expand/collapse, such as datepicker, pickerview\n- [x] You can create your own custom form items\n- [x] Align textfields across multiple rows\n- [x] Form validation rule engine\n- [x] Shows with red text where there are problems with validation\n- [x] Strongly Typed\n- [x] Pure Swift\n- [x] No 3rd party dependencies\n\n\n# USAGE\n\n### Tutorial 0 - Static text\n\n```swift\nimport SwiftyFORM\nclass MyViewController: FormViewController {\n    override func populate(_ builder: FormBuilder) {\n        builder += StaticTextFormItem().title(\"Hello\").value(\"World\")\n    }\n}\n```\n\n### Tutorial 1 - TextField\n\n```swift\nimport SwiftyFORM\nclass MyViewController: FormViewController {\n    override func populate(_ builder: FormBuilder) {\n        builder += TextFieldFormItem().title(\"Email\").placeholder(\"Please specify\").keyboardType(.emailAddress)\n    }\n}\n```\n\n### Tutorial 2 - Open child view controller\n\n```swift\nimport SwiftyFORM\nclass MyViewController: FormViewController {\n    override func populate(_ builder: FormBuilder) {\n        builder += ViewControllerFormItem().title(\"Go to view controller\").viewController(FirstViewController.self)\n    }\n}\n```\n\n### Advanced - date picker\n\n```swift\nclass DatePickerBindingViewController: FormViewController {\n    override func populate(_ builder: FormBuilder) {\n        builder += datePicker\n        builder += incrementButton\n        builder += decrementButton\n        builder += SectionFormItem()\n        builder += summary\n        updateSummary()\n    }\n    \n    lazy var datePicker: DatePickerFormItem = {\n        let instance = DatePickerFormItem()\n        instance.title = \"Date\"\n        instance.datePickerMode = .date\n        instance.behavior = .expandedAlways\n        instance.valueDidChangeBlock = { [weak self] _ in\n            self?.updateSummary()\n        }\n        return instance\n    }()\n    \n    lazy var incrementButton: ButtonFormItem = {\n        let instance = ButtonFormItem()\n        instance.title = \"Next Day\"\n        instance.action = { [weak self] in\n            self?.increment()\n        }\n        return instance\n    }()\n    \n    lazy var decrementButton: ButtonFormItem = {\n        let instance = ButtonFormItem()\n        instance.title = \"Previous Day\"\n        instance.action = { [weak self] in\n            self?.decrement()\n        }\n        return instance\n    }()\n    \n    lazy var summary: StaticTextFormItem = {\n        return StaticTextFormItem().title(\"Date\").value(\"-\")\n    }()\n    \n    func updateSummary() {\n        summary.value = \"\\(datePicker.value)\"\n    }\n    \n    func offsetDate(_ date: Date, days: Int) -\u003e Date {\n        var dateComponents = DateComponents()\n        dateComponents.day = days\n        let calendar = Calendar.current\n        guard let resultDate = calendar.date(byAdding: dateComponents, to: date) else {\n            return date\n        }\n        return resultDate\n    }\n    \n    func increment() {\n        datePicker.setValue(offsetDate(datePicker.value, days: 1), animated: true)\n        updateSummary()\n    }\n    \n    func decrement() {\n        datePicker.setValue(offsetDate(datePicker.value, days: -1), animated: true)\n        updateSummary()\n    }\n}\n```\n\n\n### Advanced - Validation\n\n![Change password form](https://github.com/neoneye/SwiftyFORM/raw/master/Documentation/change_password_form.gif \"Change password form\")\n\n```swift\nclass ChangePasswordViewController: FormViewController {\n    override func populate(_ builder: FormBuilder) {\n        builder.navigationTitle = \"Password\"\n        builder += SectionHeaderTitleFormItem().title(\"Your Old Password\")\n        builder += passwordOld\n        builder += SectionHeaderTitleFormItem().title(\"Your New Password\")\n        builder += passwordNew\n        builder += passwordNewRepeated\n        builder.alignLeft([passwordOld, passwordNew, passwordNewRepeated])\n    }\n    \n    lazy var passwordOld: TextFieldFormItem = {\n        let instance = TextFieldFormItem()\n        instance.title(\"Old password\").password().placeholder(\"required\")\n        instance.keyboardType = .numberPad\n        instance.autocorrectionType = .no\n        instance.validate(CharacterSetSpecification.decimalDigitCharacterSet(), message: \"Must be digits\")\n        instance.submitValidate(CountSpecification.min(4), message: \"Length must be minimum 4 digits\")\n        instance.validate(CountSpecification.max(6), message: \"Length must be maximum 6 digits\")\n        return instance\n        }()\n    \n    lazy var passwordNew: TextFieldFormItem = {\n        let instance = TextFieldFormItem()\n        instance.title(\"New password\").password().placeholder(\"required\")\n        instance.keyboardType = .numberPad\n        instance.autocorrectionType = .no\n        instance.validate(CharacterSetSpecification.decimalDigitCharacterSet(), message: \"Must be digits\")\n        instance.submitValidate(CountSpecification.min(4), message: \"Length must be minimum 4 digits\")\n        instance.validate(CountSpecification.max(6), message: \"Length must be maximum 6 digits\")\n        return instance\n        }()\n    \n    lazy var passwordNewRepeated: TextFieldFormItem = {\n        let instance = TextFieldFormItem()\n        instance.title(\"Repeat password\").password().placeholder(\"required\")\n        instance.keyboardType = .numberPad\n        instance.autocorrectionType = .no\n        instance.validate(CharacterSetSpecification.decimalDigitCharacterSet(), message: \"Must be digits\")\n        instance.submitValidate(CountSpecification.min(4), message: \"Length must be minimum 4 digits\")\n        instance.validate(CountSpecification.max(6), message: \"Length must be maximum 6 digits\")\n        return instance\n        }()\n}\n```\n\n\n# INSTALLATION\n\n## Swift Package Manager\n\nWith Swift Package Manager support in the latest Xcode, installation has never been easier.\n\nOpen your Xcode project -\u003e `File` -\u003e `Swift Packages` -\u003e `Add Package Dependency...`\n\nSearch for `SwiftyFORM` and specify the version you want. The latest tagged release is usually a good idea.\n\n## CocoaPods\n\nTo integrate SwiftyFORM into your Xcode project using CocoaPods, specify the following in your `Podfile`:\n\n```ruby\nsource 'https://github.com/CocoaPods/Specs.git'\nswift_version = '5.0'\nplatform :ios, '12.0'\nuse_frameworks!\n\ntarget 'MyApp' do\n    pod 'SwiftyFORM', '~\u003e 1.8'\nend\n```\n\nThen, run the following command:\n\n```bash\n$ pod install\n```\n\n## Carthage\n\n[Link to demo project that shows a minimal SwiftyFORM app using Carthage](https://github.com/neoneye/SwiftyFORM-Carthage-Example).\n\nTo integrate SwiftyFORM into your Xcode project using Carthage, specify it in your `Cartfile`:\n```\ngithub \"neoneye/SwiftyFORM\" ~\u003e 1.8\n```\n\nThen, run the following command:\n```bash\n$ carthage update\n```\n\nFinally, add `SwiftyFORM.framework` (will be built by Carthage under `Carthage/Build/iOS/`) to your project's _Linked Frameworks and Libraries_ in the _General_ tab, and add a new _Run Script_ Build Phase:\n- Set `/bin/bash` as the shell\n- write `/usr/local/bin/carthage copy-frameworks` in the script body\n- add `$(SRCROOT)/Carthage/Build/iOS/SwiftyFORM.framework` to the input files \n\n## Manual\n\n1. Open up Terminal application and cd into your iOS project directory\n\n2. ONLY IF your project is not already initialized as a git repository, run\n```\n$ git init\n```\n\n3. Add `SwiftyFORM` as a submodule by running\n```\n$ git submodule add https://github.com/neoneye/SwiftyFORM.git\n```\n\n4. In the Project Navigator, select your application project and go to \"Targets\" -\u003e \"General\"\n\n5. Open the project folder and drag the `SwiftyFORM.xcodeproj` file into the \"Frameworks, Libraries, and Embedded Content\" tab of your application. \n\n6. Click the `+` button under the \"Frameworks, Libraries, and Embedded Content\" section and `Add` the `SwiftyFORM.framework`\n\n# Communication\n\n- If you want to contribute, submit a pull request.\n- If you found a bug, have suggestions or need help, please, open an issue.\n- If you need help, write me: neoneye@gmail.com\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneoneye%2Fswiftyform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneoneye%2Fswiftyform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneoneye%2Fswiftyform/lists"}