{"id":2163,"url":"https://github.com/wangshengjia/LeeGo","last_synced_at":"2025-08-06T15:30:43.830Z","repository":{"id":56919683,"uuid":"49977774","full_name":"wangshengjia/LeeGo","owner":"wangshengjia","description":"Declarative, configurable \u0026 highly reusable UI development as making Lego bricks.","archived":false,"fork":false,"pushed_at":"2018-08-02T11:12:28.000Z","size":3066,"stargazers_count":966,"open_issues_count":20,"forks_count":45,"subscribers_count":20,"default_branch":"master","last_synced_at":"2024-12-03T23:03:52.700Z","etag":null,"topics":["autolayout","component-driven","declarative-ui","ios","swift","uiview"],"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/wangshengjia.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}},"created_at":"2016-01-19T19:35:30.000Z","updated_at":"2024-10-25T15:58:49.000Z","dependencies_parsed_at":"2022-08-20T21:50:33.677Z","dependency_job_id":null,"html_url":"https://github.com/wangshengjia/LeeGo","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wangshengjia%2FLeeGo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wangshengjia%2FLeeGo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wangshengjia%2FLeeGo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wangshengjia%2FLeeGo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wangshengjia","download_url":"https://codeload.github.com/wangshengjia/LeeGo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228915462,"owners_count":17991409,"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","component-driven","declarative-ui","ios","swift","uiview"],"created_at":"2024-01-05T20:16:06.291Z","updated_at":"2024-12-09T15:30:52.025Z","avatar_url":"https://github.com/wangshengjia.png","language":"Swift","funding_links":[],"categories":["Libs","UI","UI [🔝](#readme)"],"sub_categories":["UI","Other free courses","Font","Other Testing"],"readme":"\u003cp align=\"center\"\u003e\n\n\u003cimg src=\"Medias/leego.jpg\" alt=\"LeeGo\" title=\"LeeGo\" width=\"600\"/\u003e\n\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\n\u003ca href=\"https://travis-ci.org/wangshengjia/LeeGo\"\u003e\u003cimg src=\"https://img.shields.io/travis/wangshengjia/LeeGo.svg?branch=master\"\u003e\u003c/a\u003e\n\n\u003ca href=\"http://cocoapods.org/pods/LeeGo\"\u003e\u003cimg src=\"https://img.shields.io/cocoapods/v/LeeGo.svg?style=flat\"\u003e\u003c/a\u003e\n\n\u003ca href=\"https://github.com/Carthage/Carthage\"\u003e\u003cimg src=\"https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat\"\u003e\u003c/a\u003e\n\n\u003ca href=\"https://codecov.io/github/wangshengjia/LeeGo?branch=master\"\u003e\u003cimg src=\"https://img.shields.io/codecov/c/github/wangshengjia/LeeGo.svg\"\u003e\u003c/a\u003e\n\n\u003ca href=\"http://developer.apple.com\"\u003e\u003cimg src=\"https://img.shields.io/badge/Platform-iOS-lightgray.svg?style=flat\"\u003e\u003c/a\u003e\n\n\u003ca href=\"https://swift.org\"\u003e\u003cimg src=\"https://img.shields.io/badge/Swift-4.0-orange.svg?style=flat\"\u003e\u003c/a\u003e\n\n\u003ca href=\"https://tldrlegal.com/license/mit-license\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-blue.svg?style=flat\" /\u003e\u003c/a\u003e\n\n\u003c/p\u003e\n\nLeeGo is a lightweight Swift framework that helps you decouple \u0026 modularise your UI component into small pieces of LEGO style's bricks, to make UI development declarative, configurable and highly reusable.\n\n## Rational behind\nWe all know that MVC pattern has some serious problems when dealing with a complex iOS project. Fortunately there are also a bunch of approaches that aim to fix the problems, most of them mainly address the `Controller` part, such as MVP, MVVM, MVSM or VIPER. But there is barely a thing which addresses the `View` part. Does that mean we just run out of all the problems in the `View` part ? I think the answer is NO, especially when we need our app to be fully responsive.\n\nI’ve talked this idea on a [dotSwift’s talk](http://www.thedotpost.com/2016/01/victor-wang-build-ios-ui-in-the-way-of-lego-bricks), and also on my blog posts:\n- [Build UI without UIView](http://allblue.me/swift/2016/05/12/reuse-everything-of-your-UI-components/)\n- [Put your whole UI into struct \u0026 enum with LeeGo](http://allblue.me/swift/2016/05/25/LeeGo-UI-developpment/)\n\nPlease checkout through for more details.\n\nLeeGo, replaces the `View` part of MVC by `Brick`.\n\u003cp align=\"center\"\u003e\n\n\u003cimg src=\"Medias/leego.gif\" alt=\"LeeGo\" title=\"LeeGo\" width=\"600\"/\u003e\n\n\u003c/p\u003e\n\n## Features\n\n**What may LeeGo helps you:**\n\n- **Describe** your whole UI in small pieces of Lego style’s bricks. Let you configure your view as a `brick` whenever \u0026 wherever you want.\n- No longer need to deal with a bunch of custom UIView’s subclasses. Instead, you only need to deal with different `Brick`s which is **lightweight** and **pure value type**.\n- Designed to be **UIKit friendly** and **non-intrusive**. There is no need to inherit from other base class at all.\n- Capable to **update remotely** almost everything via your JSON payload.\n- Built-in convenience methods to make **UIStackView like layout** hassle-free.\n- Built-in **self-sizing mechanism** to calculate cell’s height automatically.\n- Method chaining syntax sugar.\n- Benefits from Swift’s enum, let you put the whole UI in a single enum file.\n\n**Compare with Facebook ComponentKit**\n\nBoth:\n- Brings declarative, configurable \u0026 reusable UI development for iOS.\n\nPros:\n- Written in Swift, built for Swift. No more Obj-C++ stuff.\n- Lightweight and UIKit friendly. No inheritance, dealing with standard UIView and Auto Layout directly.\n- Totally smooth to begin with integrating only a small part, also free to drop all without any side effect.\n- Possible to update any part of UI which powered by LeeGo remotely via JSON payload.\n- Powered by standard auto layout which you probably familiar with already.\n\nCons:\n- Lack of high level features for the moment. Such as support of built-in configurable view controller, view animation, auto layout animation or UIControl component’s action.\n- Powered by standard auto layout which may have some [potential performance issues](http://floriankugler.com/2013/04/22/auto-layout-performance-on-ios/) in some circumstances.\n- Still requires the basic knowledge of standard auto layout and [Visual Format Language](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/VisualFormatLanguage.html).\n\n## Full Documentation\n- [Full Documentation](http://cocoadocs.org/docsets/LeeGo/0.6.0/)\n- [Native UI powered by server side](Docs/Remote.md)\n- [Configurable appearance](Docs/Appearance.md)\n- [Built-in convenience methods for layout](Docs/Layout.md)\n- [Dynamic cell height](Docs/Cell.md)\n\n## Usages\n#### Basic bricks\nCreate a `Brick` instance which named \"title\" as UILabel, with default text \"Showcase\" and gray background color\n\n```swift\nimport LeeGo\n\nlet titleBrick: Brick = \"title\".build(UILabel).style([.text(\"Showcase\"), .backgroundColor(.lightGrayColor())])\n```\nConfigure an `UILabel` instance just as title brick\n\n```swift\nlet titleLabel = UILabel()\ntitleLabel.lg_configureAs(titleBrick)\n```\n\u003cp align=\"center\"\u003e\u003cimg src=\"Medias/title_sample.png\"/\u003e\u003c/p\u003e\n#### More complex bricks\nCreate the bricks inside a cell brick\n\n```swift\n\nlet titleBrick = \"title\".build(UILabel).style([.numberOfLines(0), .text(\"title\")])\nlet subtitleBrick = \"subtitle\".build(UILabel).style([.textColor(.lightGrayColor()), .numberOfLines(0), .font(.systemFontOfSize(14)), .text(\"subtitle\")])\nlet imageBrick = \"image\".build(UIImageView).style([.ratio(1.5), .backgroundColor(.blueColor())]).width(68)\n\n/// Create a brick stand for `UIView` which contains a `title`,\n/// a `subtitle` and an `image` inside, layout them with\n/// standard auto layout VFL.\nlet brickName = \"cell\"\nlet cellBrick = brickName.build().bricks(titleBrick, subtitleBrick, imageBrick) {\n\ttitle, subtitle, image in\n\treturn Layout([\n\t\t\t\"H:|-left-[\\(image)]-spaceH-[\\(title)]-right-|\",\n\t\t\t\"H:[\\(image)]-spaceH-[\\(subtitle)]-right-|\",\n\t\t\t\"V:|-top-[\\(title)]-spaceV-[\\(subtitle)]-(\u003e=bottom)-|\",\n\t\t\t\"V:|-top-[\\(image)]-(\u003e=bottom)-|\"], metrics: LayoutMetrics(20, 20, 20, 20, 10, 10))\n}\n```\n\nDequeue a standard `UICollectionViewCell` instance, then configure it as cell brick with `element` as data source\n\n```swift\nlet cell = collectionView.dequeueCell…\ncell.lg_configureAs(cellBrick, dataSource: element[indexPath.item])\n```\n\u003cp align=\"center\"\u003e\u003cimg src=\"Medias/complex_sample.png\" width=\"320\" /\u003e\u003c/p\u003e\n\n#### UIStackView inspired layout\nCreate a brick stand for `UIView` which contains the 3 bricks (red, green \u0026 blue block), then lay them out with the `UIStackView` inspired layout helper method.\n\n```swift\nlet bricks = [\"red\".build().style(Style.redBlockStyle).height(50),\n \"green\".build().style(Style.greenBlockStyle).height(80),\n \"blue\".build().style(Style.blueBlockStyle).height(30)]\n\nlet layout = Layout(bricks: bricks, axis: .Horizontal, align: .Top, distribution: .FillEqually, metrics: LayoutMetrics(10, 10, 10, 10, 10, 10))\nlet viewBrick = \"view\".build().style(Style.blocksStyle).bricks(bricks, layout: layout).height(100)\n```\n\nConfigure a `UIView` instance just as the brick\n\n```swift\nview.lg_configureAs(viewBrick)\n```\n\u003cp align=\"center\"\u003e\u003cimg src=\"Medias/blocks_sample.png\" width=\"320\" /\u003e\u003c/p\u003e\n#### Union different bricks\nUnion different bricks to a new brick with `UIStackView` style’s layout.\n\n```swift\nlet viewBrick = Brick.union(\"brickName\", bricks: [\n\t\t            title,\n\t\t            subtitle,\n\t\t            Brick.union(\"blocks\", bricks: [\n\t\t                redBlock.height(50),\n\t\t                greenBlock.height(80),\n\t\t                blueBlock.height(30)], axis: .Horizontal, align: .Top, distribution: .FillEqually, metrics: LayoutMetrics(10, 10, 10, 10, 10, 10)).style([.backgroundColor(.yellowColor())])\n\t\t            ], axis: .Vertical, align: .Fill, distribution: .Flow(3), metrics: LayoutMetrics(20, 20, 20, 20, 10, 10))\n                \n```\n\nConfigure a `UIView` instance just as the brick\n\n```swift\nview.lg_configureAs(viewBrick)\n```\n\u003cp align=\"center\"\u003e\u003cimg src=\"Medias/union_sample.png\" width=\"320\" /\u003e\u003c/p\u003e\n#### More complex brick and build with an enum\nAn enum which implements `BrickBuilderType`, used to centralize all `brick` designs in a single enum file.\n\n```swift\nimport LeeGo\n\nenum TwitterBrickSet: BrickBuilderType {\n    // leaf bricks\n    case username, account, avatar, tweetText, tweetImage, date, replyButton, retweetButton, retweetCount, likeButton, likeCount\n    \n    // complex bricks\n    case retweetView, likeView\n    case accountHeader, toolbarFooter, retweetHeader\n    \n    // root bricks\n    case standardTweet\n\n    static let brickClass: [Twitter: AnyClass] = [username: UILabel.self, account: UILabel.self, avatar: UIImageView.self, tweetText: UITextView.self]\n    \n    func brick() -\u003e Brick {\n        switch self {\n        case .username:\n            return build().style([.font(.boldSystemFontOfSize(14))])\n        case .account:\n            return build().style([.font(.systemFontOfSize(14))])\n        case .avatar:\n            return build().style([.ratio(1), .backgroundColor(.lightGrayColor()), .cornerRadius(3)]).width(50)\n        case .tweetText:\n            return build().style([.scrollEnabled(false)])\n        …\n        case .standardTweet:\n            return build().style([.backgroundColor(.whiteColor())])\n                .bricks(\n                    avatar.brick(),\n                    accountHeader.brick(),\n                    tweetText.brick(),\n                    tweetImage.brick(),\n                    toolbarFooter.brick()\n                ) { (avatar, accountHeader, tweetText, image, toolbarFooter) in\n                    Layout([\"H:|-10-[\\(avatar)]-10-[\\(tweetText)]-10-|\",\n                        \"H:[\\(avatar)]-10-[\\(accountHeader)]-10-|\",\n                        \"H:[\\(avatar)]-10-[\\(image)]-10-|\",\n                        \"H:[\\(avatar)]-10-[\\(toolbarFooter)]-10-|\",\n                        \"V:|-10-[\\(avatar)]-(\u003e=10)-|\",\n                        \"V:|-10-[\\(accountHeader)]-10-[\\(tweetText)]-10-[\\(image)]-10-[\\(toolbarFooter)]-(\u003e=10)-|\"])\n            }\n        }\n    }\n}\n\n/// Configure your cell\nlet cell = collectionView.dequeueCell…\ncell.lg_configureAs(TwitterBrickSet.standardTweet.brick(), dataSource: element[indexPath.item])\n```\n\u003cp align=\"center\"\u003e\u003cimg src=\"Medias/tweet_sample.png\" width=\"320\" /\u003e\u003c/p\u003e\n## Update UI remotely\n`Brick` is designed to be JSON convertible, which makes possible that you can control your app’s interface, from tweak some UIKit appearances to create view/cell with brand new design **remotely** via JSON payload. Please check out [\"JSON encodable \u0026 decodable\"](Docs/Remote.md) for more details.\n\n## Best practices\nFor best practices and more design details, please checkout [more design details](Docs/Design.md)\n\n## Installation\n#### CocoaPods\nLeeGo is available through [CocoaPods](http://cocoapods.org). To install it, simply add the following line to your Podfile:\n\n```ruby\nsource 'https://github.com/CocoaPods/Specs.git'\nplatform :ios, '8.0'\nuse_frameworks!\n\npod \"LeeGo\"\n```\n#### Carthage\nTo integrate LeeGo into your Xcode project using Carthage, specify it in your Cartfile:\n\n```\ngithub \"wangshengjia/LeeGo\"\n```\n\nThen, run the following command to build the LeeGo framework:\n\n```\n$ carthage update\n```\n\nAt last, you need to set up your Xcode project manually to add the LeeGo framework.\n\n## Contributing\n\nIf you like LeeGo and willing to make it better, you are more than welcomed to send pull request for:\n\n- Proposing new features.\n- Answering questions on issues.\n- Improving documentation.\n- Reviewing pull requests.\n- Finding, reporting or fixing bugs.\n\nPlease note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by [its terms](Docs/Code of Conduct.md).\n\n## Well...\nIf you have any thing want to tell me, please ping me on [Twitter](http://twitter.com/wangshengjia), on [Weibo](http://www.weibo.com/1739447693) or just fire the issue.\n\nI'd like to thank every one who helped me, inspired me and encouraged me. Also thank to my team at [Le Monde](http://lemonde.fr/), especially [Vincent](https://twitter.com/vipom) \u0026 [Blaise](https://github.com/bsarr007).\n\nEnjoy~ 🎉 🎉 🍻 🍻 \n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwangshengjia%2FLeeGo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwangshengjia%2FLeeGo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwangshengjia%2FLeeGo/lists"}