{"id":22061182,"url":"https://github.com/hackware1993/flutter_constraintlayout","last_synced_at":"2026-01-11T13:34:21.718Z","repository":{"id":37725735,"uuid":"475854544","full_name":"hackware1993/Flutter_ConstraintLayout","owner":"hackware1993","description":"A super powerful Stack, build flexible layouts with constraints. Similar to ConstraintLayout for Android and AutoLayout for iOS. But the code implementation is much more efficient, it has O(n) layout time complexity and no linear equation solving is required.","archived":false,"fork":false,"pushed_at":"2024-12-07T07:46:20.000Z","size":7506,"stargazers_count":499,"open_issues_count":15,"forks_count":36,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-08T04:12:41.950Z","etag":null,"topics":["autolayout","constraint","constraintlayout","dart","flutter","hell","layout","nested","stack"],"latest_commit_sha":null,"homepage":"","language":"Dart","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/hackware1993.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":"support.webp","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-30T11:49:00.000Z","updated_at":"2025-04-07T14:27:53.000Z","dependencies_parsed_at":"2024-11-30T18:06:15.067Z","dependency_job_id":"975ef9be-a28d-4066-ae4c-4f245c821652","html_url":"https://github.com/hackware1993/Flutter_ConstraintLayout","commit_stats":null,"previous_names":[],"tags_count":89,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackware1993%2FFlutter_ConstraintLayout","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackware1993%2FFlutter_ConstraintLayout/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackware1993%2FFlutter_ConstraintLayout/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackware1993%2FFlutter_ConstraintLayout/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hackware1993","download_url":"https://codeload.github.com/hackware1993/Flutter_ConstraintLayout/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254414499,"owners_count":22067272,"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","constraint","constraintlayout","dart","flutter","hell","layout","nested","stack"],"created_at":"2024-11-30T18:05:43.819Z","updated_at":"2026-01-11T13:34:21.711Z","avatar_url":"https://github.com/hackware1993.png","language":"Dart","funding_links":["https://www.paypal.com/paypalme/hackware1993"],"categories":[],"sub_categories":[],"readme":"# Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=hackware1993/Flutter_ConstraintLayout\u0026type=Date)](https://star-history.com/#hackware1993/Flutter_ConstraintLayout)\n\n# Flutter ConstraintLayout\n\n[简体中文](https://github.com/hackware1993/flutter-constraintlayout/blob/master/README_CN.md)\n\n**I have developed the world's fastest general purpose sorting algorithm, which is on average 3\ntimes faster than Quicksort and up to 20 times faster**\n, [ChenSort](https://github.com/hackware1993/ChenSort)\n\nA super powerful Stack, build flexible layouts with constraints. Similar to ConstraintLayout for\nAndroid and AutoLayout for iOS. But the code implementation is much more efficient, it has O(n)\nlayout time complexity and no linear equation solving is required.\n\n**It surpasses traditional nested writing in terms of performance, flexibility, development speed,\nand maintainability. It pretty much negates the O(2n) layout algorithm of Intrinsic Measurement.**\n\n**It is a layout and a more modern general layout framework.**\n\n# Greatly improve Flutter development experience and efficiency. Improve application performance\n\nNo matter how complex the layout is and how deep the constraints are, it has almost the same\nperformance as a single Flex or Stack. When facing complex layouts, it provides better performance,\nflexibility, and a very flat code hierarchy than Flex and Stack. Say no to 'nested hell'.\n\nIn short, once you use it, you can't go back.\n\nImproving \"nested hell\" is one of my original intentions for developing Flutter ConstraintLayout,\nbut I don't advocate the ultimate pursuit of one level of nesting, which is unnecessary. So features\nlike chains are already well supported by Flex itself, so ConstraintLayout will not actively support\nit.\n\nView [Flutter Web Online Example](https://constraintlayout.flutterfirst.cn)\n\n**Flutter ConstraintLayout has extremely high layout performance. It does not require linear\nequations to solve.** At any time, each child element will only be laid out once. When its own width\nor height is set to wrapContent, some child elements may calculate the offset twice. The layout\nprocess of ConstraintLayout consists of the following three steps:\n\n1. Constraint calculation\n2. Layout\n3. Draw\n\nThe performance of layout and drawing is almost equivalent to a single Flex or Stack, and the\nperformance of constraint calculation is roughly 0.01 milliseconds (layout of general complexity, 20\nchild elements). Constraints are only recalculated after they have changed.\n\nConstraintLayout itself can be arbitrarily nested without performance issues, each child element in\nthe render tree is only laid out once, and the time complexity is O(n) instead of O(2n) or worse.\n\nA smaller Widget tree leads to less build time and a smaller Element tree. A very flat layout\nstructure results in a smaller RenderObject tree and less rendering time. One thing most people tend\nto overlook is that complex nesting can cause build times to sometimes exceed render times.\n\nIt is recommended to use ConstraintLayout at the top level. For extremely complex layout(one\nthousand child elements, two thousand constraints), layout and drawing total time within 5\nmilliseconds(debug mode on Windows 10，release mode take less time), the frame rate can be easily\nreached 200 fps.\n\n**If not necessary, try to be relative to the parent layout, so that you can define less id. Or use\nrelative id.**\n\n**Warning**:\nFor layout performance considerations, constraints are always one-way, and there should be no two\nchild elements directly or indirectly restrain each other(for example, the right side of A is\nconstrained to the left side of B, and the left side of B is in turn constrained to A right). Each\nconstraint should describe exactly where the child elements are located. Although constraints can\nonly be one-way, you can still better handle things that were previously (Android ConstraintLayout)\ntwo-way constraints, such as chains(not yet supported, please use with Flex).\n\n# Feature\n\n1. build flexible layouts with constraints\n    1. left\n        1. toLeft\n        2. toCenter(with bias, the default value is 0.5)\n        3. toRight\n    2. right\n        1. toLeft\n        2. toCenter(with bias, the default value is 0.5)\n        3. toRight\n    3. top\n        1. toTop\n        2. toCenter(with bias, the default value is 0.5)\n        3. toBottom\n    4. bottom\n        1. toTop\n        2. toCenter(with bias, the default value is 0.5)\n        3. toBottom\n    5. baseline\n        1. toTop\n        2. toCenter(with bias, the default value is 0.5)\n        3. toBaseline\n        4. toBottom\n2. margin and goneMargin(when the visibility of the dependent element is gone or the actual size of\n   one side is 0, the goneMargin will take effect, otherwise the margin will take effect, even if\n   its own visibility is gone)\n3. clickPadding(quickly expand the click area of child elements without changing their actual size.\n   This means that you can completely follow the layout of the UI prototype without having to think\n   about the click area of the element. This also means that the click area can be shared between\n   child elements without increasing nesting. Sometimes it may be necessary to combine with e-index)\n4. visibility control\n    1. visible\n    2. invisible\n    3. gone(sometimes it may be better to use a conditional expression to keep the element from\n       being created)\n5. constraint integrity hint\n6. bias(when there are constraints left and right or top and bottom, horizontalBias and verticalBias\n   can be used to adjust the offset. The default value is 0.5, which means centering)\n7. z-index(drawing order, default is child index)\n8. translate、rotate\n9. percentage layout(when size is set to matchConstraint, the percentage layout will take effect,\n   the default percentage is 1 (100%). The relevant properties are widthPercent, heightPercent,\n   widthPercentageAnchor, heightPercentageAnchor)\n10. guideline\n11. constraints and widgets separation\n12. barrier\n13. dimension ratio\n    1. widthHeightRatio: 1 / 3,\n    2. ratioBaseOnWidth: true, (the default value is null, which means automatic inference. The size\n       of the undetermined side will be calculated using the determined side based on the aspect\n       ratio. The undetermined side must be matchConstraint, and the determined side can be\n       matchParent, fixed size(\u003e=0), matchConstraint)\n14. relative id(if an id is defined for a child element, it cannot be referenced using a relative\n    id)\n    1. rId(3) represents the 3th child element, and so on\n    2. rId(-1) represents the last child element\n    3. rId(-2) represents the penultimate child element, and so on\n    4. sId(-1) represents the previous sibling element, and so on\n    5. sId(1) represents the next sibling element, and so on\n15. wrapper constraints\n    1. topLeftTo\n    2. topCenterTo\n    3. topRightTo\n    4. centerLeftTo\n    5. centerTo\n    6. centerRightTo\n    7. bottomLeftTo\n    8. bottomCenterTo\n    9. bottomRightTo\n    10. centerHorizontalTo\n    11. centerVerticalTo\n    12. outTopLeftTo\n    13. outTopCenterTo\n    14. outTopRightTo\n    15. outCenterLeftTo\n    16. outCenterRightTo\n    17. outBottomLeftTo\n    18. outBottomCenterTo\n    19. outBottomRightTo\n    20. centerTopLeftTo\n    21. centerTopCenterTo\n    22. centerTopRightTo\n    23. centerCenterLeftTo\n    24. centerCenterRightTo\n    25. centerBottomLeftTo\n    26. centerBottomCenterTo\n    27. centerBottomRightTo\n16. staggered grid、grid、list(list is a special staggered grid, grid is also a special staggered\n    grid)\n17. circle position\n18. pinned position\n19. arbitrary position\n20. e-index(event dispatch order, default is z-index)\n21. the size of child widgets can be set to:\n    1. fixed size(\u003e=0)\n    2. matchParent\n    3. wrapContent(default, minimum and maximum supported)\n    4. matchConstraint\n22. the size of itself can be set to:\n    1. fixed size(\u003e=0)\n    2. matchParent(default)\n    3. wrapContent(minimum and maximum are temporarily not supported)\n23. layout debugging\n    1. showHelperWidgets\n    2. showClickArea\n    3. showZIndex\n    4. showChildDepth\n    5. debugPrintConstraints\n    6. showLayoutPerformanceOverlay\n24. open grammar gives you more flexibility to organize child elements, solving the problem of using\n    only limited expressions in the children list\n\n```dart\nclass OpenGrammarExample extends StatelessWidget {\n  const OpenGrammarExample({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: ConstraintLayout().open(() {\n        if (DateTime\n            .now()\n            .millisecond % 2 == 0) {\n          Container(\n            color: Colors.red,\n          ).applyConstraint(\n            size: 200,\n            centerTo: parent,\n          );\n        } else {\n          Container(\n            color: Colors.yellow,\n          ).applyConstraint(\n            size: 200,\n            centerTo: parent,\n          );\n        }\n\n        for (int i = 0; i \u003c 5; i++) {\n          Row().open(() {\n            for (int j = 0; j \u003c 10; j++) {\n              Text(\"$i x $j\").enter();\n              const SizedBox(\n                width: 20,\n              ).enter();\n            }\n          }).applyConstraint(\n            height: 100,\n            left: parent.left.margin(100),\n            top: i == 0 ? parent.top : sId(-1).bottom,\n          );\n        }\n\n        int i = 0;\n        while (i \u003c 100) {\n          Text(\"$i\").applyConstraint(\n            left: parent.left,\n            top: i == 0 ? parent.top : sId(-1).bottom,\n          );\n          i++;\n        }\n      }),\n    );\n  }\n}\n```\n\nFollow-up development plan:\n\n1. chain\n2. constraints visualization\n3. provides a visual editor to create layouts by dragging and dropping\n4. automatically convert design drafts into code\n5. more…\n\nSubscribe to my WeChat official account to get the latest news of ConstraintLayout([Full Guide](https://mp.weixin.qq.com/s/yTpp7TtLagOeWzX2URKOIQ), Best\nPractices, Principle Analysis). Follow-up will also share some high-quality, unique, and thoughtful\nFlutter technical articles.\n![official_account.webp](https://github.com/hackware1993/flutter-constraintlayout/blob/master/official_account.webp?raw=true)\n\nCurrently, I am developing a new declarative UI framework weiV(pronounced the same as wave) for\nAndroid based on the View system. It has the following advantages:\n\n1. Declarative UI writing doubles the efficiency of native development\n2. Meets or exceeds the performance of the View system\n    1. I ported my Flutter ConstraintLayout to Android, relying on its advanced layout algorithm,\n       without introducing Intrinsic Measurement, so that the child elements in the View tree will\n       only be laid out once in any case, making arbitrary nesting does not cause performance\n       issues. Even if each level in the View tree is a mix of wrap_content and match_parent\n    2. xml will be discarded\n3. All your existing View system experience will be retained\n4. All existing UI components will be reused\n5. It is written in Kotlin but supports Java friendly\n6. At present, the initial support for real-time effective dynamization has begun. You can issue JS,\n   use JS to write page logic, and generate JSON describing the Widget tree and pass it to the\n   native, and the native uses a non-reflection method to convert it into a real Widget tree and\n   render. I might consider implementing a declarative API in JS later\n7. In the future, the same stateful hot reload as Flutter will be implemented\n\nThe sample code is as follows:\n\n```kotlin\nclass WeiVCounterKotlinActivity : WeiVActivity() {\n    private var count = 0\n    private val maxCount = 10\n    private val minCount = 0\n\n    override fun build() = WeiV {\n        Flex {\n            it.orientation = FlexDirection.VERTICAL\n\n            Button(text = \"Add count\", enable = count \u003c maxCount, onClick = {\n                setState {\n                    count++\n                }\n            })\n\n            Button(text = \"Sub count\", enable = count \u003e minCount, onClick = {\n                setState {\n                    count--\n                }\n            })\n\n            Text(text = \"count = $count\")\n        }\n    }\n}\n```\n\n**No one wants to overturn their past experience with the View system, Compose's design is too\nbad.**\n\n[weiV GitHub Home Page](https://github.com/hackware1993/weiV)\n\nSubscribe to my WeChat official account to get the latest news of weiV.\n\nSupport platform:\n\n1. Android\n2. iOS\n3. Mac\n4. Windows\n5. Linux\n6. Web\n\n# Import\n\nNull-safety\n\n```yaml\ndependencies:\n  flutter_constraintlayout:\n    git:\n      url: 'https://github.com/hackware1993/Flutter-ConstraintLayout.git'\n      ref: 'v1.7.0-stable'\n```\n\n```yaml\ndependencies:\n  flutter_constraintlayout: ^1.7.0-stable\n```\n\n```dart\nimport 'package:flutter_constraintlayout/flutter_constraintlayout.dart';\n```\n\n# Example [Flutter Web Online Example](https://constraintlayout.flutterfirst.cn)\n\n![effect.gif](https://github.com/hackware1993/flutter-constraintlayout/blob/master/effect.gif?raw=true)\n\n```dart\nclass SummaryExampleState extends State\u003cSummaryExample\u003e {\n  double x = 0;\n  double y = 0;\n\n  ConstraintId box0 = ConstraintId('box0');\n  ConstraintId box1 = ConstraintId('box1');\n  ConstraintId box2 = ConstraintId('box2');\n  ConstraintId box3 = ConstraintId('box3');\n  ConstraintId box4 = ConstraintId('box4');\n  ConstraintId box5 = ConstraintId('box5');\n  ConstraintId box6 = ConstraintId('box6');\n  ConstraintId box7 = ConstraintId('box7');\n  ConstraintId box8 = ConstraintId('box8');\n  ConstraintId box9 = ConstraintId('box9');\n  ConstraintId box10 = ConstraintId('box10');\n  ConstraintId box11 = ConstraintId('box11');\n  ConstraintId barrier = ConstraintId('barrier');\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: const CustomAppBar(\n        title: 'Summary',\n        codePath: 'example/summary.dart',\n      ),\n      backgroundColor: Colors.black,\n      body: ConstraintLayout(\n        // Constraints can be separated from widgets\n        childConstraints: [\n          Constraint(\n            id: box0,\n            size: 200,\n            bottomLeftTo: parent,\n            zIndex: 20,\n          )\n        ],\n        children: [\n          Container(\n            color: Colors.redAccent,\n            alignment: Alignment.center,\n            child: const Text('box0'),\n          ).applyConstraintId(\n            id: box0, // Constraints can be separated from widgets\n          ),\n          Container(\n            color: Colors.redAccent,\n            alignment: Alignment.center,\n            child: const Text('box1'),\n          ).apply(\n            constraint: Constraint(\n              // Constraints set with widgets\n              id: box1,\n              width: 200,\n              height: 100,\n              topRightTo: parent,\n            ),\n          ),\n          Container(\n            color: Colors.blue,\n            alignment: Alignment.center,\n            child: const Text('box2'),\n          ).applyConstraint(\n            // Constraints set with widgets easy way\n            id: box2,\n            size: matchConstraint,\n            centerHorizontalTo: box3,\n            top: box3.bottom,\n            bottom: parent.bottom,\n          ),\n          Container(\n            color: Colors.orange,\n            width: 200,\n            height: 150,\n            alignment: Alignment.center,\n            child: const Text('box3'),\n          ).applyConstraint(\n            id: box3,\n            right: box1.left,\n            top: box1.bottom,\n          ),\n          Container(\n            color: Colors.redAccent,\n            alignment: Alignment.center,\n            child: const Text('box4'),\n          ).applyConstraint(\n            id: box4,\n            size: 50,\n            bottomRightTo: parent,\n          ),\n          GestureDetector(\n            child: Container(\n              color: Colors.pink,\n              alignment: Alignment.center,\n              child: const Text('box5 draggable'),\n            ),\n            onPanUpdate: (details) {\n              setState(() {\n                x += details.delta.dx;\n                y += details.delta.dy;\n              });\n            },\n          ).applyConstraint(\n            id: box5,\n            width: 120,\n            height: 100,\n            centerTo: parent,\n            zIndex: 100,\n            translate: Offset(x, y),\n            translateConstraint: true,\n          ),\n          Container(\n            color: Colors.lightGreen,\n            alignment: Alignment.center,\n            child: const Text('box6'),\n          ).applyConstraint(\n            id: box6,\n            size: 120,\n            centerVerticalTo: box2,\n            verticalBias: 0.8,\n            left: box3.right,\n            right: parent.right,\n          ),\n          Container(\n            color: Colors.lightGreen,\n            alignment: Alignment.center,\n            child: const Text('box7'),\n          ).applyConstraint(\n            id: box7,\n            size: matchConstraint,\n            left: parent.left,\n            right: box3.left,\n            centerVerticalTo: parent,\n            margin: const EdgeInsets.all(50),\n          ),\n          Container(\n            color: Colors.cyan,\n            alignment: Alignment.center,\n            child: const Text('child[7] pinned to the top right'),\n          ).applyConstraint(\n            width: 200,\n            height: 100,\n            left: box5.right,\n            bottom: box5.top,\n          ),\n          const Text(\n            'box9 baseline to box7',\n            style: TextStyle(\n              color: Colors.white,\n            ),\n          ).applyConstraint(\n            id: box9,\n            baseline: box7.baseline,\n            left: box7.left,\n          ),\n          Container(\n            color: Colors.yellow,\n            alignment: Alignment.bottomCenter,\n            child: const Text(\n                'percentage layout\\nwidth: 50% of parent\\nheight: 30% of parent'),\n          ).applyConstraint(\n            size: matchConstraint,\n            widthPercent: 0.5,\n            heightPercent: 0.3,\n            horizontalBias: 0,\n            verticalBias: 0,\n            centerTo: parent,\n          ),\n          Barrier(\n            id: barrier,\n            direction: BarrierDirection.left,\n            referencedIds: [box6, box5],\n          ),\n          Container(\n            color: const Color(0xFFFFD500),\n            alignment: Alignment.center,\n            child: const Text('align to barrier'),\n          ).applyConstraint(\n            width: 100,\n            height: 200,\n            top: box5.top,\n            right: barrier.left,\n          )\n        ],\n      ),\n    );\n  }\n}\n```\n\n# Advanced usage\n\n1. guideline [Flutter Web Online Example](https://constraintlayout.flutterfirst.cn)\n\n![guideline.webp](https://github.com/hackware1993/flutter-constraintlayout/blob/master/guideline.webp?raw=true)\n\n```dart\nclass GuidelineExample extends StatelessWidget {\n  const GuidelineExample({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    ConstraintId guideline = ConstraintId('guideline');\n    return MaterialApp(\n      home: Scaffold(\n        body: ConstraintLayout(\n          children: [\n            Container(\n              color: const Color(0xFF005BBB),\n            ).applyConstraint(\n              width: matchParent,\n              height: matchConstraint,\n              top: parent.top,\n              bottom: guideline.top,\n            ),\n            Guideline(\n              id: guideline,\n              horizontal: true,\n              guidelinePercent: 0.5,\n            ),\n            Container(\n              color: const Color(0xFFFFD500),\n            ).applyConstraint(\n              width: matchParent,\n              height: matchConstraint,\n              top: guideline.bottom,\n              bottom: parent.bottom,\n            ),\n            const Text(\n              'Stand with the people of Ukraine',\n              style: TextStyle(\n                fontSize: 40,\n                color: Colors.white,\n              ),\n            ).applyConstraint(\n              width: wrapContent,\n              height: wrapContent,\n              centerHorizontalTo: parent,\n              bottom: guideline.bottom,\n            )\n          ],\n        ),\n      ),\n    );\n  }\n}\n```\n\n2. barrier [Flutter Web Online Example](https://constraintlayout.flutterfirst.cn)\n\n![barrier.gif](https://github.com/hackware1993/flutter-constraintlayout/blob/master/barrier.gif?raw=true)\n\n```dart\nclass BarrierExample extends StatelessWidget {\n  const BarrierExample({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    ConstraintId leftChild = ConstraintId('leftChild');\n    ConstraintId rightChild = ConstraintId('rightChild');\n    ConstraintId barrier = ConstraintId('barrier');\n    return MaterialApp(\n      home: Scaffold(\n        body: ConstraintLayout(\n          debugShowGuideline: true,\n          children: [\n            Container(\n              color: const Color(0xFF005BBB),\n            ).applyConstraint(\n              id: leftChild,\n              width: 200,\n              height: 200,\n              top: parent.top,\n              left: parent.left,\n            ),\n            Container(\n              color: const Color(0xFFFFD500),\n            ).applyConstraint(\n              id: rightChild,\n              width: 200,\n              height: matchConstraint,\n              right: parent.right,\n              top: parent.top,\n              bottom: parent.bottom,\n              heightPercent: 0.5,\n              verticalBias: 0,\n            ),\n            Barrier(\n              id: barrier,\n              direction: BarrierDirection.bottom,\n              referencedIds: [leftChild, rightChild],\n            ),\n            const Text(\n              'Align to barrier',\n              style: TextStyle(\n                fontSize: 40,\n                color: Colors.blue,\n              ),\n            ).applyConstraint(\n              width: wrapContent,\n              height: wrapContent,\n              centerHorizontalTo: parent,\n              top: barrier.bottom,\n              goneMargin: const EdgeInsets.only(top: 20),\n            )\n          ],\n        ),\n      ),\n    );\n  }\n}\n```\n\n3. badge [Flutter Web Online Example](https://constraintlayout.flutterfirst.cn)\n\n![badge.webp](https://github.com/hackware1993/flutter-constraintlayout/blob/master/badge.webp?raw=true)\n\n```dart\nclass BadgeExample extends StatelessWidget {\n  const BadgeExample({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    ConstraintId anchor = ConstraintId('anchor');\n    return Scaffold(\n      body: ConstraintLayout(\n        children: [\n          Container(\n            color: Colors.yellow,\n          ).applyConstraint(\n            width: 200,\n            height: 200,\n            centerTo: parent,\n            id: anchor,\n          ),\n          Container(\n            color: Colors.green,\n            child: const Text(\n              'Indeterminate badge size',\n              style: TextStyle(\n                color: Colors.black,\n                fontSize: 20,\n              ),\n            ),\n          ).applyConstraint(\n            left: anchor.right,\n            bottom: anchor.top,\n            translate: const Offset(-0.5, 0.5),\n            percentageTranslate: true,\n          ),\n          Container(\n            color: Colors.green,\n          ).applyConstraint(\n            width: 100,\n            height: 100,\n            left: anchor.right,\n            right: anchor.right,\n            top: anchor.bottom,\n            bottom: anchor.bottom,\n          )\n        ],\n      ),\n    );\n  }\n}\n```\n\n4. grid [Flutter Web Online Example](https://constraintlayout.flutterfirst.cn)\n\n![grid.webp](https://github.com/hackware1993/flutter-constraintlayout/blob/master/grid.webp?raw=true)\n\n```dart\nclass GridExample extends StatelessWidget {\n  const GridExample({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    List\u003cColor\u003e colors = [\n      Colors.redAccent,\n      Colors.greenAccent,\n      Colors.blueAccent,\n      Colors.orangeAccent,\n      Colors.yellow,\n      Colors.pink,\n      Colors.lightBlueAccent\n    ];\n    return Scaffold(\n      body: ConstraintLayout(\n        children: [\n          ...constraintGrid(\n              id: ConstraintId('grid'),\n              left: parent.left,\n              top: parent.top,\n              itemCount: 50,\n              columnCount: 8,\n              itemWidth: 50,\n              itemHeight: 50,\n              itemBuilder: (index) {\n                return Container(\n                  color: colors[index % colors.length],\n                );\n              },\n              itemMarginBuilder: (index) {\n                return const EdgeInsets.only(\n                  left: 10,\n                  top: 10,\n                );\n              })\n        ],\n      ),\n    );\n  }\n}\n```\n\n5. staggered grid [Flutter Web Online Example](https://constraintlayout.flutterfirst.cn)\n\n![staggered_grid.gif](https://github.com/hackware1993/flutter-constraintlayout/blob/master/staggered_grid.gif?raw=true)\n\n```dart\nclass StaggeredGridExample extends StatelessWidget {\n  const StaggeredGridExample({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    List\u003cColor\u003e colors = [\n      Colors.redAccent,\n      Colors.greenAccent,\n      Colors.blueAccent,\n      Colors.orangeAccent,\n      Colors.yellow,\n      Colors.pink,\n      Colors.lightBlueAccent\n    ];\n    const double smallestSize = 40;\n    const int columnCount = 8;\n    Random random = Random();\n    return Scaffold(\n      body: ConstraintLayout(\n        children: [\n          TextButton(\n            onPressed: () {\n              (context as Element).markNeedsBuild();\n            },\n            child: const Text(\n              'Upset',\n              style: TextStyle(\n                fontSize: 32,\n                height: 1.5,\n              ),\n            ),\n          ).applyConstraint(\n            left: ConstraintId('horizontalList').right,\n            top: ConstraintId('horizontalList').top,\n          ),\n          ...constraintGrid(\n              id: ConstraintId('horizontalList'),\n              left: parent.left,\n              top: parent.top,\n              margin: const EdgeInsets.only(\n                left: 100,\n              ),\n              itemCount: 50,\n              columnCount: columnCount,\n              itemBuilder: (index) {\n                return Container(\n                  color: colors[index % colors.length],\n                  alignment: Alignment.center,\n                  child: Text('$index'),\n                );\n              },\n              itemSizeBuilder: (index) {\n                if (index == 0) {\n                  return const Size(\n                      smallestSize * columnCount + 35, smallestSize);\n                }\n                if (index == 6) {\n                  return const Size(smallestSize * 2 + 5, smallestSize);\n                }\n                if (index == 7) {\n                  return const Size(smallestSize * 6 + 25, smallestSize);\n                }\n                if (index == 19) {\n                  return const Size(smallestSize * 2 + 5, smallestSize);\n                }\n                if (index == 29) {\n                  return const Size(smallestSize * 3 + 10, smallestSize);\n                }\n                return Size(\n                    smallestSize, (2 + random.nextInt(4)) * smallestSize);\n              },\n              itemSpanBuilder: (index) {\n                if (index == 0) {\n                  return columnCount;\n                }\n                if (index == 6) {\n                  return 2;\n                }\n                if (index == 7) {\n                  return 6;\n                }\n                if (index == 19) {\n                  return 2;\n                }\n                if (index == 29) {\n                  return 3;\n                }\n                return 1;\n              },\n              itemMarginBuilder: (index) {\n                return const EdgeInsets.only(\n                  left: 5,\n                  top: 5,\n                );\n              })\n        ],\n      ),\n    );\n  }\n}\n```\n\n6. circle position [Flutter Web Online Example](https://constraintlayout.flutterfirst.cn)\n\n![circle_position.gif](https://github.com/hackware1993/flutter-constraintlayout/blob/master/circle_position.gif?raw=true)\n\n```dart\nclass CirclePositionExampleState extends State\u003cCirclePositionExample\u003e {\n  late Timer timer;\n  late int hour;\n  late int minute;\n  late int second;\n\n  double centerTranslateX = 0;\n  double centerTranslateY = 0;\n\n  @override\n  void initState() {\n    super.initState();\n    calculateClockAngle();\n    timer = Timer.periodic(const Duration(seconds: 1), (_) {\n      calculateClockAngle();\n    });\n  }\n\n  void calculateClockAngle() {\n    setState(() {\n      DateTime now = DateTime.now();\n      hour = now.hour;\n      minute = now.minute;\n      second = now.second;\n    });\n  }\n\n  @override\n  void dispose() {\n    super.dispose();\n    timer.cancel();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: ConstraintLayout(\n        children: [\n          GestureDetector(\n            child: Container(\n              decoration: const BoxDecoration(\n                color: Colors.red,\n                borderRadius: BorderRadius.all(\n                  Radius.circular(1000),\n                ),\n              ),\n            ),\n            onPanUpdate: (details) {\n              setState(() {\n                centerTranslateX += details.delta.dx;\n                centerTranslateY += details.delta.dy;\n              });\n            },\n          ).applyConstraint(\n            width: 20,\n            height: 20,\n            centerTo: parent,\n            zIndex: 100,\n            translate: Offset(centerTranslateX, centerTranslateY),\n            translateConstraint: true,\n          ),\n          for (int i = 0; i \u003c 12; i++)\n            Text(\n              '${i + 1}',\n              style: const TextStyle(\n                fontWeight: FontWeight.bold,\n                fontSize: 25,\n              ),\n            ).applyConstraint(\n              centerTo: rId(0),\n              translate: circleTranslate(\n                radius: 205,\n                angle: (i + 1) * 30,\n              ),\n            ),\n          for (int i = 0; i \u003c 60; i++)\n            if (i % 5 != 0)\n              Transform.rotate(\n                angle: pi + pi * (i * 6 / 180),\n                child: Container(\n                  color: Colors.grey,\n                  margin: const EdgeInsets.only(\n                    top: 405,\n                  ),\n                ),\n              ).applyConstraint(\n                width: 1,\n                height: 415,\n                centerTo: rId(0),\n              ),\n          Transform.rotate(\n            angle: pi + pi * (hour * 30 / 180),\n            alignment: Alignment.topCenter,\n            child: Container(\n              color: Colors.green,\n            ),\n          ).applyConstraint(\n            width: 5,\n            height: 80,\n            centerTo: rId(0),\n            translate: const Offset(0, 0.5),\n            percentageTranslate: true,\n          ),\n          Transform.rotate(\n            angle: pi + pi * (minute * 6 / 180),\n            alignment: Alignment.topCenter,\n            child: Container(\n              color: Colors.pink,\n            ),\n          ).applyConstraint(\n            width: 5,\n            height: 120,\n            centerTo: rId(0),\n            translate: const Offset(0, 0.5),\n            percentageTranslate: true,\n          ),\n          Transform.rotate(\n            angle: pi + pi * (second * 6 / 180),\n            alignment: Alignment.topCenter,\n            child: Container(\n              color: Colors.blue,\n            ),\n          ).applyConstraint(\n            width: 5,\n            height: 180,\n            centerTo: rId(0),\n            translate: const Offset(0, 0.5),\n            percentageTranslate: true,\n          ),\n          Text(\n            '$hour:$minute:$second',\n            style: const TextStyle(\n              fontSize: 40,\n            ),\n          ).applyConstraint(\n            outTopCenterTo: rId(0),\n            margin: const EdgeInsets.only(\n              bottom: 250,\n            ),\n          )\n        ],\n      ),\n    );\n  }\n}\n```\n\n7. margin [Flutter Web Online Example](https://constraintlayout.flutterfirst.cn)\n\n![margin.webp](https://github.com/hackware1993/flutter-constraintlayout/blob/master/margin.webp?raw=true)\n\n```dart\nclass MarginExample extends StatelessWidget {\n  const MarginExample({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: ConstraintLayout(\n        children: [\n          Container(\n            color: const Color(0xFF005BBB),\n          ).applyConstraint(\n            size: 50,\n            topLeftTo: parent,\n            margin: const EdgeInsets.only(\n              left: 20,\n              top: 100,\n            ),\n          ),\n          Container(\n            color: const Color(0xFFFFD500),\n          ).applyConstraint(\n            size: 100,\n            top: sId(-1).bottom,\n            right: parent.right.margin(100),\n          ),\n          Container(\n            color: Colors.pink,\n          ).applyConstraint(\n            size: 50,\n            topRightTo: parent.rightMargin(20).topMargin(50),\n          ),\n        ],\n      ),\n    );\n  }\n}\n```\n\n8. pinned position [Flutter Web Online Example](https://constraintlayout.flutterfirst.cn)\n\n![pinned_position.gif](https://github.com/hackware1993/flutter-constraintlayout/blob/master/pinned_position.gif?raw=true)\n\n```dart\nclass PinnedPositionExampleState extends State\u003cPinnedPositionExample\u003e {\n  late Timer timer;\n  double angle = 0;\n\n  @override\n  void initState() {\n    super.initState();\n    timer = Timer.periodic(const Duration(milliseconds: 16), (_) {\n      setState(() {\n        angle++;\n      });\n    });\n  }\n\n  @override\n  void dispose() {\n    super.dispose();\n    timer.cancel();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    ConstraintId anchor = ConstraintId('anchor');\n    return Scaffold(\n      appBar: const CustomAppBar(\n        title: 'Pinned Position',\n        codePath: 'example/pinned_position.dart',\n      ),\n      body: ConstraintLayout(\n        children: [\n          Container(\n            color: Colors.yellow,\n          ).applyConstraint(\n            id: anchor,\n            size: 200,\n            centerTo: parent,\n          ),\n          Container(\n            color: Colors.cyan,\n          ).applyConstraint(\n            size: 100,\n            pinnedInfo: PinnedInfo(\n              anchor,\n              Anchor(0.2, AnchorType.percent, 0.2, AnchorType.percent),\n              Anchor(1, AnchorType.percent, 1, AnchorType.percent),\n              angle: angle,\n            ),\n          ),\n          Container(\n            color: Colors.orange,\n          ).applyConstraint(\n            size: 60,\n            pinnedInfo: PinnedInfo(\n              anchor,\n              Anchor(1, AnchorType.percent, 1, AnchorType.percent),\n              Anchor(0, AnchorType.percent, 0, AnchorType.percent),\n              angle: 360 - angle,\n            ),\n          ),\n          Container(\n            color: Colors.black,\n          ).applyConstraint(\n            size: 60,\n            pinnedInfo: PinnedInfo(\n              anchor,\n              Anchor(0.5, AnchorType.percent, 0.5, AnchorType.percent),\n              Anchor(0.5, AnchorType.percent, 0.5, AnchorType.percent),\n              angle: angle,\n            ),\n          ),\n          Container(\n            decoration: const BoxDecoration(\n              color: Colors.red,\n              borderRadius: BorderRadius.all(Radius.circular(10)),\n            ),\n          ).applyConstraint(\n            size: 10,\n            centerBottomRightTo: anchor,\n          ),\n          Container(\n            decoration: const BoxDecoration(\n              color: Colors.red,\n              borderRadius: BorderRadius.all(Radius.circular(10)),\n            ),\n          ).applyConstraint(\n            size: 10,\n            centerTopLeftTo: anchor,\n          ),\n          Container(\n            decoration: const BoxDecoration(\n              color: Colors.red,\n              borderRadius: BorderRadius.all(Radius.circular(10)),\n            ),\n          ).applyConstraint(\n            size: 10,\n            centerTo: anchor,\n          )\n        ],\n      ),\n    );\n  }\n}\n```\n\n9. translate [Flutter Web Online Example](https://constraintlayout.flutterfirst.cn)\n\n![translate.gif](https://github.com/hackware1993/flutter-constraintlayout/blob/master/translate.gif?raw=true)\n\n```dart\nclass TrackPainter extends CustomPainter {\n  Queue\u003cOffset\u003e points = Queue();\n  Paint painter = Paint();\n\n  TrackPainter(this.points);\n\n  @override\n  void paint(Canvas canvas, Size size) {\n    canvas.drawPoints(PointMode.polygon, points.toList(), painter);\n  }\n\n  @override\n  bool shouldRepaint(CustomPainter oldDelegate) =\u003e true;\n}\n\nclass TranslateExampleState extends State\u003cTranslateExample\u003e {\n  late Timer timer;\n  double angle = 0;\n  double earthRevolutionAngle = 0;\n  Queue\u003cOffset\u003e points = Queue();\n\n  @override\n  void initState() {\n    super.initState();\n    timer = Timer.periodic(const Duration(milliseconds: 16), (_) {\n      setState(() {\n        angle += 1;\n        earthRevolutionAngle += 0.1;\n      });\n    });\n  }\n\n  @override\n  void dispose() {\n    super.dispose();\n    timer.cancel();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    ConstraintId anchor = ConstraintId('anchor');\n    return Scaffold(\n      appBar: const CustomAppBar(\n        title: 'Translate',\n        codePath: 'example/translate.dart',\n      ),\n      body: ConstraintLayout(\n        children: [\n          CustomPaint(\n            painter: TrackPainter(points),\n          ).applyConstraint(\n            width: matchParent,\n            height: matchParent,\n          ),\n          Container(\n            decoration: const BoxDecoration(\n              color: Colors.redAccent,\n              borderRadius: BorderRadius.all(Radius.circular(1000)),\n            ),\n            child: const Text('----'),\n            alignment: Alignment.center,\n          ).applyConstraint(\n            id: cId('sun'),\n            size: 200,\n            pinnedInfo: PinnedInfo(\n              parent,\n              Anchor(0.5, AnchorType.percent, 0.5, AnchorType.percent),\n              Anchor(0.3, AnchorType.percent, 0.5, AnchorType.percent),\n              angle: earthRevolutionAngle * 365 / 25.4,\n            ),\n          ),\n          Container(\n            decoration: const BoxDecoration(\n              color: Colors.blue,\n              borderRadius: BorderRadius.all(Radius.circular(1000)),\n            ),\n            child: const Text('----'),\n            alignment: Alignment.center,\n          ).applyConstraint(\n            id: cId('earth'),\n            size: 100,\n            pinnedInfo: PinnedInfo(\n              cId('sun'),\n              Anchor(0.5, AnchorType.percent, 0.5, AnchorType.percent),\n              Anchor(0.5, AnchorType.percent, 0.5, AnchorType.percent),\n              angle: earthRevolutionAngle * 365,\n            ),\n            translate: circleTranslate(\n              radius: 250,\n              angle: earthRevolutionAngle,\n            ),\n            translateConstraint: true,\n          ),\n          Container(\n            decoration: const BoxDecoration(\n              color: Colors.grey,\n              borderRadius: BorderRadius.all(Radius.circular(1000)),\n            ),\n            child: const Text('----'),\n            alignment: Alignment.center,\n          ).applyConstraint(\n            id: cId('moon'),\n            size: 50,\n            pinnedInfo: PinnedInfo(\n              cId('earth'),\n              Anchor(0.5, AnchorType.percent, 0.5, AnchorType.percent),\n              Anchor(0.5, AnchorType.percent, 0.5, AnchorType.percent),\n              angle: earthRevolutionAngle * 365 / 27.32,\n            ),\n            translate: circleTranslate(\n              radius: 100,\n              angle: earthRevolutionAngle * 365 / 27.32,\n            ),\n            translateConstraint: true,\n            paintCallback: (_, __, ____, offset, ______) {\n              points.add(offset!);\n              if (points.length \u003e 2000) {\n                points.removeFirst();\n              }\n            },\n          ),\n          Text('Sun rotates ${(earthRevolutionAngle * 365 / 25.4) ~/ 360} times')\n              .applyConstraint(\n            outTopCenterTo: cId('sun'),\n          ),\n          Text('Earth rotates ${earthRevolutionAngle * 365 ~/ 360} times')\n              .applyConstraint(\n            outTopCenterTo: cId('earth'),\n          ),\n          Text('Moon rotates ${(earthRevolutionAngle * 365 / 27.32) ~/ 360} times')\n              .applyConstraint(\n            outTopCenterTo: cId('moon'),\n          ),\n          Container(\n            color: Colors.yellow,\n          ).applyConstraint(\n            id: anchor,\n            size: 250,\n            centerRightTo: parent.rightMargin(300),\n          ),\n          Container(\n            color: Colors.red,\n            child: const Text('pinned translate'),\n          ).applyConstraint(\n            centerTo: anchor,\n            translate: PinnedTranslate(\n              PinnedInfo(\n                null,\n                Anchor(0.5, AnchorType.percent, 0.5, AnchorType.percent),\n                null,\n                angle: angle,\n              ),\n            ),\n          ),\n          Container(\n            color: Colors.blue,\n            child: const Text('circle translate'),\n          ).applyConstraint(\n            size: wrapContent,\n            centerTo: anchor,\n            translate: circleTranslate(\n              radius: 100,\n              angle: angle,\n            ),\n          ),\n          Container(\n            color: Colors.cyan,\n            child: const Text('pinned \u0026 circle translate'),\n          ).applyConstraint(\n            centerTo: anchor,\n            translate: PinnedTranslate(\n              PinnedInfo(\n                null,\n                Anchor(0.5, AnchorType.percent, 0.5, AnchorType.percent),\n                null,\n                angle: angle,\n              ),\n            ) +\n                circleTranslate(\n                  radius: 150,\n                  angle: angle,\n                ),\n          ),\n          Container(\n            color: Colors.orange,\n            child: const Text('normal translate'),\n          ).applyConstraint(\n            size: wrapContent,\n            outBottomCenterTo: anchor,\n            translate: Offset(0, angle / 5),\n          )\n        ],\n      ),\n    );\n  }\n}\n```\n\n# Performance optimization\n\n1. When the layout is complex, if the child elements need to be repainted frequently, it is\n   recommended to use RepaintBoundary to improve performance.\n\n```dart\nclass OffPaintExample extends StatelessWidget {\n  const OffPaintExample({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      home: Scaffold(\n        body: ConstraintLayout(\n          children: [\n            Container(\n              color: Colors.orangeAccent,\n            ).offPaint().applyConstraint(\n              width: 200,\n              height: 200,\n              topRightTo: parent,\n            )\n          ],\n        ),\n      ),\n    );\n  }\n}\n```\n\n2. Try to use const Widget. If you can't declare a child element as const and it won't change, you\n   can use OffBuildWidget to avoid the rebuilding of the child element.\n\n```dart\nclass OffBuildExample extends StatelessWidget {\n  const OffBuildExample({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      home: Scaffold(\n        body: ConstraintLayout(\n          children: [\n\n            /// subtrees that do not change\n            Container(\n              color: Colors.orangeAccent,\n            ).offBuild(id: 'id').applyConstraint(\n              width: 200,\n              height: 200,\n              topRightTo: parent,\n            )\n          ],\n        ),\n      ),\n    );\n  }\n}\n```\n\n3. Child elements will automatically become RelayoutBoundary unless width or height is wrapContent.\n   The use of wrapContent can be reasonably reduced, because after the size of ConstraintLayout\n   changes (usually the size of the window changes), all child elements whose width or height is\n   wrapContent will be re-layout. And since the constraints passed to other child elements won't\n   change, no real re-layout will be triggered.\n\n4. If you use Guideline or Barrier in the children list, Element and RenderObject will inevitably be\n   generated for them, which will be laid out but not drawn. At this point you can use\n   GuidelineDefine or BarrierDefine to optimize it, no Element and RenderObject will be generated\n   anymore:\n\n```dart\nclass BarrierExample extends StatelessWidget {\n  const BarrierExample({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    ConstraintId leftChild = ConstraintId('leftChild');\n    ConstraintId rightChild = ConstraintId('rightChild');\n    ConstraintId barrier = ConstraintId('barrier');\n    return Scaffold(\n      body: ConstraintLayout(\n        childConstraints: [\n          BarrierDefine(\n            id: barrier,\n            direction: BarrierDirection.bottom,\n            referencedIds: [leftChild, rightChild],\n          ),\n        ],\n        children: [\n          Container(\n            color: const Color(0xFF005BBB),\n          ).applyConstraint(\n            id: leftChild,\n            width: 200,\n            height: 200,\n            topLeftTo: parent,\n          ),\n          Container(\n            color: const Color(0xFFFFD500),\n          ).applyConstraint(\n            id: rightChild,\n            width: 200,\n            height: matchConstraint,\n            centerRightTo: parent,\n            heightPercent: 0.5,\n            verticalBias: 0,\n          ),\n          const Text(\n            'Align to barrier',\n            style: TextStyle(\n              fontSize: 40,\n              color: Colors.blue,\n            ),\n          ).applyConstraint(\n            centerHorizontalTo: parent,\n            top: barrier.bottom,\n          )\n        ],\n      ),\n    );\n  }\n}   \n```\n\n5. Every frame, ConstraintLayout compares the parameters and decides the following things:\n    1. Does the constraint need to be recalculated?\n    2. Does it need to be relayout?\n    3. Does it need to be redrawn?\n    4. Do you need to rearrange the drawing order?\n    5. Do you need to rearrange the order of event distribution?\n\nThese comparisons will not be a performance bottleneck, but will increase CPU usage. If you know\nenough about the internals of ConstraintLayout, you can use ConstraintLayoutController to manually\ntrigger these operations to stop parameter comparison.\n\n```dart\nclass ConstraintControllerExampleState extends State\u003cConstraintControllerExample\u003e {\n  double x = 0;\n  double y = 0;\n  ConstraintLayoutController controller = ConstraintLayoutController();\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: const CustomAppBar(\n        title: 'Constraint Controller',\n        codePath: 'example/constraint_controller.dart',\n      ),\n      body: ConstraintLayout(\n        controller: controller,\n        children: [\n          GestureDetector(\n            child: Container(\n              color: Colors.pink,\n              alignment: Alignment.center,\n              child: const Text('box draggable'),\n            ),\n            onPanUpdate: (details) {\n              setState(() {\n                x += details.delta.dx;\n                y += details.delta.dy;\n                controller.markNeedsPaint();\n              });\n            },\n          ).applyConstraint(\n            size: 200,\n            centerTo: parent,\n            translate: Offset(x, y),\n          )\n        ],\n      ),\n    );\n  }\n}\n```\n\n# Extension\n\nConstraintLayout's constraint-based layout algorithm is extremely powerful and flexible, and it\nseems that it can become a general layout framework. You just need to generate constraints and hand\nover the task of layout to ConstraintLayout. Some built-in features like circle position, staggered\ngrid, grid, and list are available in extended form.\n\nThe charts in the online example is a typical extension:\n\n![charts.gif](https://github.com/hackware1993/flutter-constraintlayout/blob/master/charts.gif?raw=true)\n\nExtensions for ConstraintLayout are welcome.\n\n# Support me\n\nIf it helps you a lot, consider sponsoring me a cup of milk tea, or giving a star. Your support is\nthe driving force for me to continue to maintain.\n\n[Paypal](https://www.paypal.com/paypalme/hackware1993)\n\n![sponsorship.webp](https://github.com/hackware1993/flutter-constraintlayout/blob/master/sponsorship.webp?raw=true)\n\nThanks to the following netizens for their sponsorship, let's make Flutter better and better\ntogether.\n\n1. 栢陶 2022.05.15\n2. CaiGo 2022.05.17\n\n# Contact\n\nhackware1993@gmail.com\n\nSubscribe to my WeChat official account to get the latest news of ConstraintLayout. Follow-up will\nalso share some high-quality, unique, and thoughtful Flutter technical articles.\n\n![official_account.webp](https://github.com/hackware1993/flutter-constraintlayout/blob/master/official_account.webp?raw=true)\n\nScan the code to add my personal WeChat, pull you into the Flutter technical exchange WeChat group,\nplease note 【add technical group】\n\n![communication.webp](https://github.com/hackware1993/flutter-constraintlayout/blob/master/communication.webp?raw=true)\n\n# License\n\n```\nMIT License\n\nCopyright (c) 2022 hackware1993\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and\nassociated documentation files (the \"Software\"), to deal in the Software without restriction,\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute,\nsublicense, and/or sell copies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial\nportions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\nNOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES\nOR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhackware1993%2Fflutter_constraintlayout","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhackware1993%2Fflutter_constraintlayout","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhackware1993%2Fflutter_constraintlayout/lists"}