{"id":1299,"url":"https://github.com/wordlessj/Bamboo","last_synced_at":"2025-08-06T13:32:50.458Z","repository":{"id":56903438,"uuid":"70036531","full_name":"wordlessj/Bamboo","owner":"wordlessj","description":"Auto Layout (and manual layout) in one line.","archived":false,"fork":false,"pushed_at":"2018-10-05T09:01:40.000Z","size":131,"stargazers_count":74,"open_issues_count":1,"forks_count":9,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-11-10T04:49:44.288Z","etag":null,"topics":["auto","autolayout","ios","layout","manual","swift"],"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/wordlessj.png","metadata":{"files":{"readme":"README.md","changelog":null,"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-10-05T06:50:42.000Z","updated_at":"2022-10-19T23:58:59.000Z","dependencies_parsed_at":"2022-08-21T02:50:09.524Z","dependency_job_id":null,"html_url":"https://github.com/wordlessj/Bamboo","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wordlessj%2FBamboo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wordlessj%2FBamboo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wordlessj%2FBamboo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wordlessj%2FBamboo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wordlessj","download_url":"https://codeload.github.com/wordlessj/Bamboo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228905506,"owners_count":17989778,"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":["auto","autolayout","ios","layout","manual","swift"],"created_at":"2024-01-05T20:15:43.258Z","updated_at":"2024-12-09T14:31:03.328Z","avatar_url":"https://github.com/wordlessj.png","language":"Swift","funding_links":[],"categories":["Layout","Libs","Layout [🔝](#readme)"],"sub_categories":["Other Hardware","Layout","Other free courses"],"readme":"![Bamboo](https://raw.githubusercontent.com/wordlessj/Bamboo/master/Assets/Logo.png)\n\n\u003cbr\u003e\n\n[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](#carthage)\n[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/Bamboo.svg)](#cocoapods)\n![Swift 4.2](https://img.shields.io/badge/Swift-4.2-orange.svg)\n![Platform](https://img.shields.io/badge/platform-iOS%209.0%2B%20%7C%20macOS%2010.11%2B%20%7C%20tvOS%209.0%2B-lightgrey.svg)\n[![Build Status](https://travis-ci.org/wordlessj/Bamboo.svg?branch=master)](https://travis-ci.org/wordlessj/Bamboo)\n\nAuto Layout (and manual layout) in one line.\n\n## Quick Look\n\n```swift\nview.bb.centerX().below(view2).size(100)\n```\n\nIt’s equivalent to iOS 9 API:\n\n```swift\nview.centerXAnchor.constraint(equalTo: view.superview!.centerXAnchor).isActive = true\nview.topAnchor.constraint(equalTo: view2.bottomAnchor).isActive = true\nview.widthAnchor.constraint(equalToConstant: 100).isActive = true\nview.heightAnchor.constraint(equalToConstant: 100).isActive = true\n```\n\nAs you can see, Bamboo eliminated a lot of redundant code.\n\n- Using chaining style, you can write view’s name just once.\n- All methods are grouped in `bb` extension, so their names can be simple and short.\n- Superview and anchor are usually implied.\n- More higher level methods like `below()` and `size()` make things easier.\n\n## Installation\n\n### Carthage\n\n```\ngithub \"wordlessj/Bamboo\" ~\u003e 1.0\n```\n\n### CocoaPods\n\n```\npod 'Bamboo', '~\u003e 1.0'\n```\n\n## Usage\n\n### Basics\n\nAll basic anchors on `UIView` and `UILayoutGuide` are provided with suffix `Anchor` stripped, e.g., `left` instead of `leftAnchor`.\n\n```swift\n// view.left == superview.left\nview.bb.left()\n\n// Or use it on UILayoutGuide.\nlayoutGuide.bb.left()\n```\n\nTo specify another view’s corresponding anchor, simply pass the view to the method.\n\n```swift\n// view1.left == view2.left\nview1.bb.left(view2)\n```\n\nOf course, you can use a specific anchor.\n\n```swift\n// view1.left == view2.right\nview1.bb.left(view2.rightAnchor)\n```\n\nIncluding a constant is straightforward using operator `+` or `-`.\n\n```swift\n// view1.left == view2.right + 10\nview1.bb.left(view2.rightAnchor + 10)\n\n// Specific view or anchor can be omitted.\n// view.left == superview.left + 10\nview.bb.left(10)\n```\n\nFor dimension anchors, when only a constant is specified, it sets the dimension to the constant, instead of matching to superview.\n\n```swift\n// view.width == 10\nview.bb.width(10)\n```\n\n\u003e `width()` and `width(0)` are different, the former match to superview and the latter set to 0.\n\nIn iOS 11, you can use `SystemSpacing` in place of constant, pass multiplier to the initializer, only `+` operator is supported.\n\n```swift\n// view1.left == view2.right + 2 * SystemSpacing\nview1.bb.left(view2.rightAnchor + SystemSpacing(2))\n```\n\nSimilarly, use `\u003e=` or `\u003c=` to specify equality.\n\n```swift\n// view1.left \u003e= view2.right + 10\nview1.bb.left(\u003e=view2.rightAnchor + 10)\n```\n\nTo specify priority, use operator `~`.\n\n```swift\n// view1.left == view2.right + 10 (priority 500)\nview1.bb.left(view2.rightAnchor + 10 ~ 500)\n```\n\nFor dimension anchors, multiplier can be specified with `*` or `/`.\n\n```swift\n// view1.width == 2 * view2.width\nview1.bb.width(2 * view2)\n```\n\n### Expression\n\nExpressions are passed to basic anchor methods. Full form:\n\n```\n( \u003e= or \u003c= ) item + constant ~ priority\n```\n\nFor dimension anchors:\n\n```\n( \u003e= or \u003c= ) item * multiplier + constant ~ priority\n```\n\n`item` can be `UIView`, `UILayoutGuide` or `NSLayoutAnchor`. You can use `/` and `-` instead of `*` and `+`. If equality is not specified, `multiplier` can be put before `item` to be more like linear functions. More complex expressions can be created, but for simplicity, it’s not recommended.\n\n### Constraints\n\nYou can get a single constraint created from the method for later use.\n\n```swift\nlet c: NSLayoutConstraint = view.bb.left().constraint\n```\n\nOr get all constraints accumulated from the chain.\n\n```swift\nlet c: [NSLayoutConstraint] = view.bb.left().top().constraints\n```\n\n### Activate and Deactivate\n\nConstraints can be activated and deactivated easily so you can better control the layout change.\n\n```swift\n// Deactivate after creation.\nlet c: [NSLayoutConstraint] = view.bb.left().top().constraints.deactivate()\n\n// Activate later when appropriate.\nc.activate()\n```\n\n### Higher Level Methods\n\n#### Aspect Ratio\n\n```swift\n// view.width == 2 * view.height\nview.bb.aspectRatio(2)\n```\n\n#### Center and Size\n\nBoth methods are similar to basic anchor methods.\n\n- `center()`, consists of `centerX` and `centerY`.\n- `size()`, consists of `width` and `height`.\n\nThere are two more methods to set size.\n\n```swift\nlet cgSize: CGSize\nview.bb.size(cgSize)\n\nview.bb.size(width: 10, height: 20)\n```\n\n#### Fill\n\n```swift\n// Pin all edges.\nfill()\n\n// Pin corresponding edge and adjacent edges.\n// e.g., fillLeft() pin left, top and bottom.\nfill[Left|Right|Top|Bottom|Leading|Trailing]()\n\n// Pin edges on corresponding axis.\n// e.g., fillWidth() pin leading and trailing.\nfill[Width|Height]()\n```\n\nAll fill methods take two optional arguments, first is either `UIView` or `UILayoutGuide` to be filled, `nil` for its superview, second is a `UIEdgeInsets`.\n\n```swift\n// view1 fills view2 with insets.\nlet insets: UIEdgeInsets\nview1.bb.fill(view2, insets: insets)\n\n// If all edge insets are the same, you can pass a single value.\n// view1 fills view2 with insets 10.\nview1.bb.fill(view2, insets: 10)\n```\n\n#### Around\n\n- `before()`\n- `after()`\n- `above()`\n- `below()`\n\nThese methods take two optional arguments like fill methods, except the second one is spacing.\n\n```swift\n// view1.trailing == view2.leading - 10\nview1.bb.before(view2, spacing: 10)\n```\n\n#### Offset\n\nIn iOS 10, use `-` operator to create an offset anchor between two axis anchors, then use `offset()` to create a constraint. It does not matter which view is used before `bb`.\n\n```swift\n// view2.left - view1.right == view3.left - view2.right\nview1.bb.offset(view2.leftAnchor - view1.rightAnchor, view3.leftAnchor - view2.rightAnchor)\n```\n\n### Multiple Items\n\nYou can constrain on multiple items at once. There are two fundamental methods on which other methods are built.\n\n```swift\n// Constrain on each item.\n// e.g., Set each item's width to 10.\n[view1, view2, view3].bb.each {\n    $0.bb.width(10)\n}\n\n// Constrain between every two items.\n// e.g., view1.left == view2.left, view2.left == view3.left\n[view1, view2, view3].bb.between {\n    $0.bb.left($1)\n}\n```\n\nMost basic methods on single item are available on multiple items.\n\n```swift\n// Anchor methods take no arguments and align all items' corresponding anchor.\n// e.g., Align all views' left.\n[view1, view2, view3].bb.left()\n\n// For dimension anchors, you can set values for all items.\n// e.g., Set all views' width to 10.\n[view1, view2, view3].bb.width(10)\n```\n\nYou can distribute items along an axis with fixed spacing or equal spacing.\n\n- `distributeX()`\n- `distributeY()`\n- `distributeXEqualSpacing()`\n- `distributeYEqualSpacing()`\n\n```swift\n// [view1]-10-[view2]-10-[view3]\n[view1, view2, view3].bb.distributeX(spacing: 10)\n```\n\nAll `distribute` methods come with an optional `inset` parameter, you can specify no insets, fixed insets or equal insets.\n\n```swift\n// |-[view1]-[view2]-[view3]-|, spacings are all equal.\n[view1, view2, view3].bb.distributeXEqualSpacing(inset: .equal)\n```\n\n### Group\n\nIf you want to activate/deactivate a set of constraints in response to some events, you can use `group()` to collect constraints into an array.\n\n```swift\nlet constraints: [NSLayoutConstraint] = group {\n    view1.bb.fill()\n    view2.bb.left().top().size(100)\n    view3.bb.fillBottom().height(100)\n}\n```\n\n## Manual Layout\n\nWhy manual layout when there is Auto Layout? Well, Auto Layout is good, but it has some performance issues, that’s when you may want to switch to manual layout.\n\n[Manual Layout Guide](https://github.com/wordlessj/Bamboo/blob/master/Documentation/Manual%20Layout%20Guide.md)\n\n## Panda\n\n[Panda](https://github.com/wordlessj/Panda) is a framework which creates view hierarchies declaratively, together with Bamboo, they make creating views in code incredibly simple and easy.\n\n## License\n\nBamboo is released under the MIT license. See LICENSE for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwordlessj%2FBamboo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwordlessj%2FBamboo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwordlessj%2FBamboo/lists"}