children;
74 |
75 | @override
76 | Widget build(BuildContext context) {
77 | return CustomBoxy(
78 | delegate: EvenSizedBoxy(),
79 | children: children,
80 | );
81 | }
82 | }
83 |
84 | class EvenSizedBoxy extends BoxyDelegate {
85 | @override
86 | Size layout() {
87 | // Find the max intrinsic width of each child
88 | //
89 | // Intrinsics are a little scary but `getMaxIntrinsicWidth(double.infinity)`
90 | // just calculates the width of the child as if its maximum height is
91 | // infinite
92 | var childWidth = 0.0;
93 | for (final child in children) {
94 | childWidth = max(
95 | childWidth,
96 | child.render.getMaxIntrinsicWidth(double.infinity),
97 | );
98 | }
99 |
100 | // Clamp the width so children don't overflow
101 | childWidth = min(childWidth, constraints.maxWidth / children.length);
102 |
103 | // Find the max intrinsic height
104 | //
105 | // We calculate childHeight after childWidth because the height of text
106 | // depends on its width (i.e. wrapping), `getMinIntrinsicHeight(childWidth)`
107 | // calculates what the child's height would be if it's width is childWidth.
108 | var childHeight = 0.0;
109 | for (final child in children) {
110 | childHeight = max(
111 | childHeight,
112 | child.render.getMinIntrinsicHeight(childWidth),
113 | );
114 | }
115 |
116 | // Force each child to be the same size
117 | final childConstraints = BoxConstraints.tight(
118 | Size(childWidth, childHeight),
119 | );
120 |
121 | var x = 0.0;
122 | for (final child in children) {
123 | child.layout(childConstraints);
124 |
125 | // Space them out evenly
126 | child.position(Offset(x, 0));
127 | x += childWidth;
128 | }
129 |
130 | return Size(childWidth * children.length, childHeight);
131 | }
132 | }
133 | ```
134 |
135 | Constraining the layout's width shows that the children are distributed evenly and don't overflow, the text has correct wrapping behavior as well:
136 |
137 | 
138 |
--------------------------------------------------------------------------------
/website/docs/custom-boxy/examples/ftest_2ETeGIqwH8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/examples/ftest_2ETeGIqwH8.png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/examples/ftest_4KetSQxXfe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/examples/ftest_4KetSQxXfe.png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/examples/ftest_7Je17IzRnr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/examples/ftest_7Je17IzRnr.png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/examples/ftest_GCKLEFXEnu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/examples/ftest_GCKLEFXEnu.png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/examples/ftest_MyQB0wRzDZ.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/examples/ftest_MyQB0wRzDZ.png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/examples/ftest_UHm3QStdY7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/examples/ftest_UHm3QStdY7.png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/examples/ftest_UTDKLOvcAU.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/examples/ftest_UTDKLOvcAU.png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/examples/ftest_X0YPu1QG3P.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/examples/ftest_X0YPu1QG3P.png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/examples/ftest_pqqiRVzZwz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/examples/ftest_pqqiRVzZwz.png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/examples/image (1) (1) (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/examples/image (1) (1) (1).png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/examples/product-tile.md:
--------------------------------------------------------------------------------
1 | # Product Tile
2 |
3 | This is an interesting layout I stumbled upon when searching StackOverflow, it contains Title, Seller, and Info widgets arranged so that the Seller is positioned above the space between Title and Info.
4 |
5 | Normally for something like this you would use Stack, but that unfortunately doesn't work if each widget is interactable and has a dynamic size.
6 |
7 | ### Complete Example
8 |
9 | 
10 |
11 | ```dart
12 | class MyWidget extends StatelessWidget {
13 | const MyWidget({Key? key}) : super(key: key);
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | return ProductTile(
18 | title: Container(
19 | decoration: BoxDecoration(
20 | color: const Color(0xff4881bd),
21 | borderRadius: BorderRadius.circular(8.0),
22 | ),
23 | width: 350,
24 | height: 200,
25 | alignment: Alignment.center,
26 | child: const Text('Title'),
27 | ),
28 | seller: Container(
29 | decoration: BoxDecoration(
30 | color: const Color(0xff5148bd),
31 | border: Border.all(color: darkBlue, width: 8),
32 | shape: BoxShape.circle,
33 | ),
34 | alignment: Alignment.center,
35 | child: const Text('Seller'),
36 | width: 64,
37 | height: 64,
38 | ),
39 | info: Container(
40 | decoration: BoxDecoration(
41 | color: const Color(0xff5148bd),
42 | borderRadius: BorderRadius.circular(8.0),
43 | ),
44 | alignment: Alignment.center,
45 | child: const Text('Info'),
46 | padding: const EdgeInsets.all(16.0),
47 | ),
48 | );
49 | }
50 | }
51 |
52 | @immutable
53 | class ProductTileStyle {
54 | /// How far to the left the seller is inset
55 | final double sellerInset;
56 |
57 | /// The size of the gap between the title and description
58 | final double gapHeight;
59 |
60 | const ProductTileStyle({
61 | this.sellerInset = 16.0,
62 | this.gapHeight = 8.0,
63 | });
64 |
65 | @override
66 | bool operator ==(Object? other) =>
67 | identical(this, other) ||
68 | (other is ProductTileStyle &&
69 | other.sellerInset == sellerInset &&
70 | other.gapHeight == gapHeight);
71 |
72 | @override
73 | int get hashCode => hashValues(sellerInset, gapHeight);
74 | }
75 |
76 | class ProductTile extends StatelessWidget {
77 | final Widget title;
78 | final Widget info;
79 | final Widget seller;
80 | final ProductTileStyle style;
81 |
82 | const ProductTile({
83 | Key? key,
84 | required this.title,
85 | required this.info,
86 | required this.seller,
87 | this.style = const ProductTileStyle(),
88 | }) : super(key: key);
89 |
90 | @override
91 | Widget build(context) {
92 | return CustomBoxy(
93 | delegate: ProductTileDelegate(style: style),
94 | children: [
95 | // Children are in paint order, put the seller last so it can sit
96 | // above the others
97 | BoxyId(id: #title, child: title),
98 | BoxyId(id: #info, child: info),
99 | BoxyId(id: #seller, child: seller),
100 | ],
101 | );
102 | }
103 | }
104 |
105 | class ProductTileDelegate extends BoxyDelegate {
106 | final ProductTileStyle style;
107 |
108 | ProductTileDelegate({required this.style});
109 |
110 | @override
111 | Size layout() {
112 | // We can grab children by name using BoxyId and getChild
113 | final title = getChild(#title);
114 | final seller = getChild(#seller);
115 | final info = getChild(#info);
116 |
117 | // Lay out the seller first so it can provide a minimum height to the title
118 | // and info
119 | final sellerSize = seller.layout(constraints.deflate(
120 | EdgeInsets.only(right: style.sellerInset),
121 | ));
122 |
123 | // Lay out and position the title
124 | final titleSize = title.layout(constraints.copyWith(
125 | minHeight: sellerSize.height / 2 + style.gapHeight / 2,
126 | ));
127 | title.position(Offset.zero);
128 |
129 | // Position the seller at the bottom right of the title, offset to the left
130 | // by sellerInset
131 | seller.position(Offset(
132 | titleSize.width - (sellerSize.width + style.sellerInset),
133 | (titleSize.height - sellerSize.height / 2) + style.gapHeight / 2,
134 | ));
135 |
136 | // Lay out info to match the width of title and position it below the title
137 | final infoSize = info.layout(BoxConstraints(
138 | minHeight: sellerSize.height / 2,
139 | minWidth: titleSize.width,
140 | maxWidth: titleSize.width,
141 | ));
142 | info.position(Offset(0, titleSize.height + style.gapHeight));
143 |
144 | return Size(
145 | titleSize.width,
146 | titleSize.height + infoSize.height + style.gapHeight,
147 | );
148 | }
149 |
150 | // Any BoxyDelegate with parameters should always implement shouldRelaout,
151 | // otherwise it won't update when its properties do.
152 | @override
153 | bool shouldRelayout(ProductTileDelegate oldDelegate) =>
154 | style != oldDelegate.style;
155 | }
156 | ```
157 |
158 | With some images and text, we get a finished product tile that is fully adaptive:
159 |
160 | 
161 |
162 | 
163 |
164 | 
165 |
166 | 
167 |
168 | 
169 |
--------------------------------------------------------------------------------
/website/docs/custom-boxy/examples/simplified_tree_view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/examples/simplified_tree_view.png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/examples/square-layout.md:
--------------------------------------------------------------------------------
1 | # Square Layout
2 |
3 | In the interactive example of [Introduction To Layout](/primer/interactive-example/) we showed a custom [RenderObject](https://api.flutter.dev/flutter/rendering/RenderObject-class.html) with a single child, let's see how [CustomBoxy](https://pub.dev/documentation/boxy/latest/boxy/CustomBoxy-class.html) can cut down all of the boilerplate.
4 |
5 | The end goal of this example is to take an arbitrarily sized widget, and size itself so that it's width and height are equal. Ideally the child is also centered in the resulting square.
6 |
7 | ### Complete Example
8 |
9 | To make the widget square, we will create a [BoxyDelegate](https://pub.dev/documentation/boxy/latest/boxy/BoxyDelegate-class.html) that overrides [layout](https://pub.dev/documentation/boxy/latest/boxy/BoxyDelegate/layout.html):
10 |
11 | %20(1)%20(1).png)
12 |
13 | ```dart
14 | class Square extends StatelessWidget {
15 | const Square({Key? key}) : super(key: key);
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return Container(
20 | // Add a border so we can see the an outline showing the size
21 | decoration: BoxDecoration(border: Border.all(color: Colors.blue)),
22 | child: CustomBoxy(
23 | delegate: SquareBoxyDelegate(),
24 | children: const [
25 | Text('Hello, World!'),
26 | ],
27 | ),
28 | );
29 | }
30 | }
31 |
32 | class SquareBoxyDelegate extends BoxyDelegate {
33 | BoxyChild get child => children.single;
34 |
35 | @override
36 | Size layout() {
37 | // Lay out the child, pass through constraints.
38 | final childSize = child.layout(constraints);
39 |
40 | // Calculate the width of our square by getting the max of the child's
41 | // width and height.
42 | final width = max(childSize.width, childSize.height);
43 |
44 | // Position the child in the center
45 | child.position(Offset(
46 | (width - childSize.width) / 2,
47 | (width - childSize.height) / 2,
48 | ));
49 |
50 | // Return our size
51 | return Size.square(width);
52 |
53 | // An alternate way to center the child using inscribe:
54 | //
55 | // final rect = Offset.zero & Size.square(width);
56 | // child.position(Alignment.center.inscribe(childSize, rect).topLeft);
57 | // return rect.size;
58 | }
59 | }
60 | ```
61 |
62 | There was a little math involved to center the child, otherwise that was easy-peasy!
63 |
--------------------------------------------------------------------------------
/website/docs/custom-boxy/ftest_XBEjnnpsdS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/ftest_XBEjnnpsdS.png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/ftest_fcR5Z2lEZD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/ftest_fcR5Z2lEZD.png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/ftest_frMkXTvID9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/ftest_frMkXTvID9.png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/ftest_m3xCKjHuvM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/ftest_m3xCKjHuvM.png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/hello-world.md:
--------------------------------------------------------------------------------
1 | # Hello, World!
2 |
3 | To start, create a [CustomBoxy](https://pub.dev/documentation/boxy/latest/boxy/CustomBoxy-class.html) widget and pass it a subclass of [BoxyDelegate](https://pub.dev/documentation/boxy/latest/boxy/BoxyDelegate-class.html):
4 |
5 | %20(1)%20(1)%20(1)%20(1)%20(1).png)
6 |
7 | ```dart
8 | class MyWidget extends StatelessWidget {
9 | const MyWidget({Key? key}) : super(key: key);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return CustomBoxy(
14 | delegate: MyBoxyDelegate(),
15 | children: const [
16 | Text('Hello, World!'),
17 | ],
18 | );
19 | }
20 | }
21 |
22 | class MyBoxyDelegate extends BoxyDelegate {}
23 | ```
24 |
25 | [CustomBoxy](https://pub.dev/documentation/boxy/latest/boxy/CustomBoxy-class.html) accepts a list of children, it's default behavior is similar to a [Stack](https://api.flutter.dev/flutter/widgets/Stack-class.html), passing through the constraints to each child and sizing itself to the biggest one.
26 |
27 | There are many methods you can override in [BoxyDelegate](https://pub.dev/documentation/boxy/latest/boxy/BoxyDelegate-class.html), the most common being [layout](https://pub.dev/documentation/boxy/latest/boxy/BoxyDelegate/layout.html).
28 |
29 | ### Custom Layout
30 |
31 |
32 |
33 | To customize layout, override the [layout](https://pub.dev/documentation/boxy/latest/boxy/BoxyDelegate/layout.html) method to return a size:
34 |
35 | ```dart
36 | class MyBoxyDelegate extends BoxyDelegate {
37 | @override
38 | // Choose the smallest size that our constraints allow, just like
39 | // an empty SizedBox().
40 | Size layout() => constraints.smallest;
41 | }
42 | ```
43 |
44 | [BoxyDelegate](https://pub.dev/documentation/boxy/latest/boxy/BoxyDelegate-class.html) includes several getters that are useful for layout, including:
45 |
46 | * [constraints](https://pub.dev/documentation/boxy/latest/render\_boxy/BoxBoxyDelegateMixin/constraints.html), the [BoxConstraints](https://api.flutter.dev/flutter/rendering/BoxConstraints-class.html) provided by the parent
47 | * [children](https://pub.dev/documentation/boxy/latest/render\_boxy/BaseBoxyDelegate/children.html), a list of [BoxyChild](https://pub.dev/documentation/boxy/latest/boxy/BoxyChild-class.html) instances which let you interact with things passed to [CustomBoxy](https://pub.dev/documentation/boxy/latest/boxy/CustomBoxy-class.html)
48 | * [getChild](https://pub.dev/documentation/boxy/latest/render\_boxy/BaseBoxyDelegate/getChild.html), a method that can get a child by id using [BoxyId](https://pub.dev/documentation/boxy/latest/boxy/BoxyId-class.html)
49 | * [hasChild](https://pub.dev/documentation/boxy/latest/render\_boxy/BaseBoxyDelegate/hasChild.html), a method that returns true if there is a child with a given id
50 | * [layoutData](https://pub.dev/documentation/boxy/latest/render\_boxy/BaseBoxyDelegate/layoutData.html), a variable you can use to hold additional data created during layout
51 | * [render](https://pub.dev/documentation/boxy/latest/render\_boxy/BoxBoxyDelegateMixin/render.html), a raw reference to the [RenderBoxy](https://pub.dev/documentation/boxy/latest/render\_boxy/RenderBoxy-class.html) of [CustomBoxy](https://pub.dev/documentation/boxy/latest/boxy/CustomBoxy-class.html)
52 | * [buildContext](https://pub.dev/documentation/boxy/latest/render\_boxy/BaseBoxyDelegate/buildContext.html), the [BuildContext](https://api.flutter.dev/flutter/widgets/BuildContext-class.html) of the [CustomBoxy](https://pub.dev/documentation/boxy/latest/boxy/CustomBoxy-class.html).
53 |
--------------------------------------------------------------------------------
/website/docs/custom-boxy/image (1) (1) (1) (1) (1) (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/image (1) (1) (1) (1) (1) (1).png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/image (1) (1) (1) (1) (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/image (1) (1) (1) (1) (1).png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/image (1) (1) (1) (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/image (1) (1) (1) (1).png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/image (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/image (1).png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/image (3).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/custom-boxy/image (3).png
--------------------------------------------------------------------------------
/website/docs/custom-boxy/introduction-to-customboxy.md:
--------------------------------------------------------------------------------
1 | # Introduction to CustomBoxy
2 |
3 | [:fontawesome-solid-book: CustomBoxy API Docs](https://pub.dev/documentation/boxy/latest/boxy/CustomBoxy-class.html){ .md-button .md-button--primary .block }
4 |
5 | [CustomBoxy](https://pub.dev/documentation/boxy/latest/boxy/CustomBoxy-class.html) is a widget that uses a delegate to implement a custom [RenderObject](https://api.flutter.dev/flutter/rendering/RenderObject-class.html).
6 |
7 | This is essentially a more powerful version of [CustomMultiChildLayout](https://api.flutter.dev/flutter/widgets/CustomMultiChildLayout-class.html) or [CustomPaint](https://api.flutter.dev/flutter/widgets/CustomPaint-class.html), it allows you to inflate, constrain, and lay out each child manually, it also allows its size to depend on the layout of its children.
8 |
9 | This is overkill in most cases, so before diving in you may want to check if some combination of [Stack](https://api.flutter.dev/flutter/widgets/Stack-class.html), [LayoutBuilder](https://api.flutter.dev/flutter/widgets/LayoutBuilder-class.html), [CustomMultiChildLayout](https://api.flutter.dev/flutter/widgets/CustomMultiChildLayout-class.html), or [Flow](https://api.flutter.dev/flutter/widgets/Flow-class.html) is more suitable.
10 |
11 | ### Sections
12 |
13 |
18 |
19 |
24 |
25 |
30 |
31 |
36 |
37 |
42 |
43 |
48 |
49 | ### Examples
50 |
51 |
56 |
57 |
62 |
63 |
68 |
69 |
74 |
--------------------------------------------------------------------------------
/website/docs/custom-boxy/layers.md:
--------------------------------------------------------------------------------
1 | # Layers
2 |
3 | Another way we can customize the way children are painted is with [layers](https://pub.dev/documentation/boxy/latest/render\_boxy/BaseBoxyDelegate/layers.html), this is a fancy wrapper around the low level compositing [Layers](https://api.flutter.dev/flutter/rendering/Layer-class.html) used for widgets like [Opacity](https://api.flutter.dev/flutter/widgets/Opacity-class.html) and [BackdropFilter](https://api.flutter.dev/flutter/widgets/BackdropFilter-class.html).
4 |
5 | %20(1)%20(1)%20(1).png)
6 |
7 | ```dart
8 | class MyWidget extends StatelessWidget {
9 | const MyWidget({Key? key}) : super(key: key);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return CustomBoxy(
14 | delegate: MyBoxyDelegate(),
15 | children: [
16 | Container(
17 | color: Colors.blue,
18 | width: 48,
19 | height: 48,
20 | ),
21 | ],
22 | );
23 | }
24 | }
25 |
26 | class MyBoxyDelegate extends BoxyDelegate {
27 | @override
28 | void paintChildren() {
29 | // Make the square blurry
30 | layers.imageFilter(
31 | imageFilter: ImageFilter.blur(
32 | sigmaX: 2,
33 | sigmaY: 2,
34 | tileMode: TileMode.decal,
35 | ),
36 | paint: children.single.paint,
37 | );
38 | }
39 | }
40 | ```
41 |
--------------------------------------------------------------------------------
/website/docs/custom-boxy/painting.md:
--------------------------------------------------------------------------------
1 | # Painting
2 |
3 | By overriding [paint](https://pub.dev/documentation/boxy/latest/render\_boxy/BaseBoxyDelegate/paint.html) or [paintForeground](https://pub.dev/documentation/boxy/latest/render\_boxy/BaseBoxyDelegate/paintForeground.html) you can get functionality similar to [CustomPaint](https://api.flutter.dev/flutter/widgets/CustomPaint-class.html):
4 |
5 | 
6 |
7 | ```dart
8 | class MyBoxyDelegate extends BoxyDelegate {
9 | @override
10 | Size layout() => const Size(32, 32);
11 |
12 | @override
13 | void paint() {
14 | canvas.drawRect(
15 | Offset.zero & render.size,
16 | Paint()..color = Colors.blue,
17 | );
18 | }
19 | }
20 | ```
21 |
22 | The [paint](https://pub.dev/documentation/boxy/latest/render\_boxy/BaseBoxyDelegate/paint.html) and [paintForeground](https://pub.dev/documentation/boxy/latest/render\_boxy/BaseBoxyDelegate/paintForeground.html) methods are the same, but [paintForeground](https://pub.dev/documentation/boxy/latest/render\_boxy/BaseBoxyDelegate/paintForeground.html) is called after [paintChildren](https://api.flutter.dev/flutter/rendering/FlowDelegate/paintChildren.html).
23 |
24 | ### Painting children
25 |
26 | We can customize the way children are painted by overriding [paintChildren](https://api.flutter.dev/flutter/rendering/FlowDelegate/paintChildren.html), this is useful if you want to change their paint order for example:
27 |
28 |  %20(1)%20(1)%20(1)%20(1).png)
29 |
30 | ```dart
31 | class MyWidget extends StatelessWidget {
32 | const MyWidget({Key? key}) : super(key: key);
33 |
34 | @override
35 | Widget build(BuildContext context) {
36 | return CustomBoxy(
37 | delegate: MyBoxyDelegate(),
38 | children: [
39 | Container(
40 | color: Colors.blue,
41 | width: 48,
42 | height: 48,
43 | ),
44 | Container(
45 | color: Colors.red,
46 | width: 96,
47 | height: 48,
48 | ),
49 | ],
50 | );
51 | }
52 | }
53 |
54 | class MyBoxyDelegate extends BoxyDelegate {
55 | @override
56 | void paintChildren() {
57 | children[1].paint();
58 | children[0].paint();
59 | }
60 | }
61 | ```
62 |
63 | Note that the [canvas](https://pub.dev/documentation/boxy/latest/render\_boxy/BaseBoxyDelegate/canvas.html) is still available, so we can use [paintChildren](https://api.flutter.dev/flutter/rendering/FlowDelegate/paintChildren.html) to paint things between children:
64 |
65 | .png)
66 |
67 | ```dart
68 | class MyBoxyDelegate extends BoxyDelegate {
69 | @override
70 | void paintChildren() {
71 | children[1].paint();
72 | canvas.save();
73 | canvas.drawCircle(
74 | // Unlike the paint method, the canvas of paintChildren is not transformed
75 | // into the local coordinate space, so we need to offset by paintOffset.
76 | paintOffset + const Offset(48, 24),
77 | 16,
78 | Paint()..color = Colors.white,
79 | );
80 | canvas.restore();
81 | children[0].paint();
82 | }
83 | }
84 | ```
85 |
--------------------------------------------------------------------------------
/website/docs/custom-boxy/widget-inflation.md:
--------------------------------------------------------------------------------
1 | # Widget Inflation
2 |
3 | The most powerful feature of Boxy is the ability to [inflate](https://pub.dev/documentation/boxy/latest/render\_boxy/BaseBoxyDelegate/inflate.html) arbitrary widgets at layout time.
4 |
5 | In the below example we construct a [Text](https://api.flutter.dev/flutter/widgets/Text-class.html) widget based on the size of another child. This would be extremely difficult to accomplish without Boxy, even using a custom [Element](https://api.flutter.dev/flutter/widgets/Element-class.html) and [RenderObject](https://api.flutter.dev/flutter/rendering/RenderObject-class.html).
6 |
7 | 
8 |
9 | ```dart
10 | class MyWidget extends StatelessWidget {
11 | const MyWidget({Key? key}) : super(key: key);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return CustomBoxy(
16 | delegate: MyBoxyDelegate(),
17 | children: [
18 | Container(
19 | color: Colors.blue,
20 | width: 50,
21 | height: 50,
22 | ),
23 | ],
24 | );
25 | }
26 | }
27 |
28 | class MyBoxyDelegate extends BoxyDelegate {
29 | @override
30 | Size layout() {
31 | // Lay out the container first.
32 | final container = children.single;
33 | final containerSize = container.layout(constraints);
34 |
35 | // Inflate a Text widget based on the containers size.
36 | final text = inflate(
37 | Text('^ $containerSize'),
38 | id: #text,
39 | );
40 | final textSize = text.layout(constraints);
41 |
42 | // Position the text below the container.
43 | text.position(Offset(0, containerSize.height));
44 |
45 | return Size(
46 | max(containerSize.width, textSize.width),
47 | containerSize.height + textSize.height,
48 | );
49 | }
50 | }
51 | ```
52 |
--------------------------------------------------------------------------------
/website/docs/helpers/cross-axis-alignment.md:
--------------------------------------------------------------------------------
1 | # Cross-axis alignment
2 |
3 | One of the limitations of a regular [Row](https://api.flutter.dev/flutter/widgets/Row-class.html) or [Column](https://api.flutter.dev/flutter/widgets/Column-class.html) is not being able to use a different cross-axis alignment for each child.
4 |
5 | [BoxyFlexible.align](https://pub.dev/documentation/boxy/latest/flex/BoxyFlexible/BoxyFlexible.align.html) lets you do exactly that:
6 |
7 | 
8 |
9 | ```dart
10 | class MyWidget extends StatelessWidget {
11 | const MyWidget({Key? key}) : super(key: key);
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return SizedBox(
16 | width: 100,
17 | child: BoxyColumn(
18 | mainAxisSize: MainAxisSize.min,
19 | crossAxisAlignment: CrossAxisAlignment.center,
20 | children: [
21 | BoxyFlexible.align(
22 | child: Container(
23 | width: 50,
24 | height: 25,
25 | color: Colors.blueAccent,
26 | alignment: Alignment.center,
27 | child: const Text('start'),
28 | ),
29 | crossAxisAlignment: CrossAxisAlignment.start,
30 | ),
31 | const SizedBox(height: 4),
32 | BoxyFlexible.align(
33 | child: Container(
34 | width: 50,
35 | height: 25,
36 | color: Colors.purpleAccent,
37 | alignment: Alignment.center,
38 | child: const Text('center'),
39 | ),
40 | crossAxisAlignment: CrossAxisAlignment.center,
41 | ),
42 | const SizedBox(height: 4),
43 | BoxyFlexible.align(
44 | child: Container(
45 | width: 50,
46 | height: 25,
47 | color: Colors.pinkAccent,
48 | alignment: Alignment.center,
49 | child: const Text('end'),
50 | ),
51 | crossAxisAlignment: CrossAxisAlignment.end,
52 | ),
53 | const SizedBox(height: 4),
54 | BoxyFlexible.align(
55 | child: Container(
56 | height: 25,
57 | color: Colors.red,
58 | alignment: Alignment.center,
59 | child: const Text('stretch'),
60 | ),
61 | crossAxisAlignment: CrossAxisAlignment.stretch,
62 | ),
63 | ],
64 | ),
65 | );
66 | }
67 | }
68 | ```
69 |
--------------------------------------------------------------------------------
/website/docs/helpers/dominant.md:
--------------------------------------------------------------------------------
1 | # Dominant
2 |
3 | The [Dominant](https://pub.dev/documentation/boxy/latest/flex/Dominant-class.html) widget tells a [BoxyRow](https://pub.dev/documentation/boxy/latest/flex/BoxyRow-class.html) or [BoxyColumn](https://pub.dev/documentation/boxy/latest/flex/BoxyColumn-class.html) to constrain every other widget to match its cross-axis size:
4 |
5 | 
6 |
7 | ```dart
8 | class MyWidget extends StatelessWidget {
9 | const MyWidget({Key? key}) : super(key: key);
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return BoxyRow(
14 | mainAxisSize: MainAxisSize.min,
15 | crossAxisAlignment: CrossAxisAlignment.center,
16 | children: [
17 | // Blue container should match the height of the pink one below
18 | Container(
19 | color: Colors.blue,
20 | width: 25,
21 | ),
22 | Dominant(
23 | child: Container(
24 | width: 50,
25 | height: 50,
26 | color: Colors.pink,
27 | ),
28 | ),
29 | ],
30 | );
31 | }
32 | }
33 | ```
34 |
35 | Due to the quirky nature of [ParentDataWidgets](https://api.flutter.dev/flutter/widgets/ParentDataWidget-class.html), you can't wrap a [Dominant](https://pub.dev/documentation/boxy/latest/flex/Dominant-class.html) widget inside an [Expanded](https://api.flutter.dev/flutter/widgets/Expanded-class.html) widget.
36 |
37 | To make it expanded, use the alternate [Dominant.expanded](https://pub.dev/documentation/boxy/latest/flex/Dominant/Dominant.expanded.html) constructor:
38 |
39 | .png)
40 |
41 | ```dart
42 | class MyWidget extends StatelessWidget {
43 | const MyWidget({Key? key}) : super(key: key);
44 |
45 | @override
46 | Widget build(BuildContext context) {
47 | return Container(
48 | width: 300,
49 | decoration: BoxDecoration(
50 | border: Border.all(color: Colors.white38),
51 | borderRadius: BorderRadius.circular(2),
52 | ),
53 | padding: const EdgeInsets.all(4.0),
54 | child: BoxyRow(
55 | mainAxisSize: MainAxisSize.min,
56 | children: [
57 | Container(
58 | color: Colors.blue,
59 | child: const RotatedBox(
60 | quarterTurns: -1,
61 | child: Text('Chapter 1'),
62 | ),
63 | padding: const EdgeInsets.all(2.0),
64 | ),
65 | const SizedBox(width: 8.0),
66 | const Dominant.expanded(
67 | child: Text(
68 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed '
69 | 'do eiusmod tempor incididunt ut labore et dolore magna '
70 | 'aliqua. Ut enim ad minim veniam, quis nostrud exercitation '
71 | 'ullamco laboris nisi ut aliquip ex ea commodo consequat.',
72 | ),
73 | ),
74 | ],
75 | ),
76 | );
77 | }
78 | }
79 | ```
80 |
--------------------------------------------------------------------------------
/website/docs/helpers/ftest_IKQC577sJP.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/helpers/ftest_IKQC577sJP.png
--------------------------------------------------------------------------------
/website/docs/helpers/ftest_jInY0aelEY.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/helpers/ftest_jInY0aelEY.png
--------------------------------------------------------------------------------
/website/docs/helpers/ftest_nmZYWRSqsy (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/helpers/ftest_nmZYWRSqsy (1).png
--------------------------------------------------------------------------------
/website/docs/helpers/ftest_yiTCTxZ1s9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/helpers/ftest_yiTCTxZ1s9.png
--------------------------------------------------------------------------------
/website/docs/helpers/image (1) (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/helpers/image (1) (1).png
--------------------------------------------------------------------------------
/website/docs/helpers/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/helpers/image.png
--------------------------------------------------------------------------------
/website/docs/helpers/sliver-card.md:
--------------------------------------------------------------------------------
1 | # SliverCard
2 |
3 | [SliverCard](https://pub.dev/documentation/boxy/latest/slivers/SliverCard-class.html) is a [Card](https://api.flutter.dev/flutter/material/Card-class.html) that you can wrap slivers in:
4 |
5 | %20(1).png)
6 |
7 | ```dart
8 | final colors = [
9 | Colors.purple.shade50,
10 | Colors.purple.shade100,
11 | Colors.purple.shade200,
12 | Colors.purple.shade300,
13 | Colors.purple.shade400,
14 | Colors.purple.shade500,
15 | Colors.purple.shade600,
16 | Colors.purple.shade700,
17 | Colors.purple.shade800,
18 | Colors.purple.shade900,
19 | ];
20 |
21 | class MyWidget extends StatelessWidget {
22 | const MyWidget({Key? key}) : super(key: key);
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | return CustomScrollView(
27 | slivers: [
28 | for (var color in colors)
29 | SliverPadding(
30 | padding: MediaQuery.of(context).padding,
31 | sliver: SliverCard(
32 | color: color,
33 | margin: const EdgeInsets.symmetric(
34 | horizontal: 16.0,
35 | vertical: 2.0,
36 | ),
37 | sliver: SliverPadding(
38 | padding: const EdgeInsets.all(4.0),
39 | sliver: SliverToBoxAdapter(
40 | child: Text('#${(color.value & 0xFFFFFF).toRadixString(16)}'),
41 | ),
42 | ),
43 | ),
44 | ),
45 | ],
46 | );
47 | }
48 | }
49 | ```
50 |
--------------------------------------------------------------------------------
/website/docs/helpers/sliver-container.md:
--------------------------------------------------------------------------------
1 | # SliverContainer
2 |
3 | [SliverContainer](https://pub.dev/documentation/boxy/latest/slivers/SliverContainer-class.html) is a sliver that gives its sliver a foreground or background box widget, this is useful if you want a sliver to look and feel like the child of a regular widget.
4 |
5 | In the below example we have two [SliverLists](https://api.flutter.dev/flutter/widgets/SliverList-class.html) with [DecoratedBox](https://api.flutter.dev/flutter/widgets/DecoratedBox-class.html) as a background:
6 |
7 | 
8 |
9 | By giving the [CustomScrollView](https://api.flutter.dev/flutter/widgets/CustomScrollView-class.html) a clip of [Clip.none](https://api.flutter.dev/flutter/dart-ui/Clip.html), you can see how this is possible:
10 |
11 | 
12 |
13 | The [DecoratedBoxes](https://api.flutter.dev/flutter/widgets/DecoratedBox-class.html) are stretched so that their top and bottom edge are barely out of view, while the contents of [SliverList](https://api.flutter.dev/flutter/widgets/SliverList-class.html) are still lazily built.
14 |
15 | ```dart
16 | final colors = [
17 | [
18 | Colors.blue.shade50,
19 | Colors.blue.shade100,
20 | Colors.blue.shade200,
21 | Colors.blue.shade300,
22 | Colors.blue.shade400,
23 | Colors.blue.shade500,
24 | Colors.blue.shade600,
25 | Colors.blue.shade700,
26 | Colors.blue.shade800,
27 | Colors.blue.shade900,
28 | ],
29 | [
30 | Colors.purple.shade50,
31 | Colors.purple.shade100,
32 | Colors.purple.shade200,
33 | Colors.purple.shade300,
34 | Colors.purple.shade400,
35 | Colors.purple.shade500,
36 | Colors.purple.shade600,
37 | Colors.purple.shade700,
38 | Colors.purple.shade800,
39 | Colors.purple.shade900,
40 | ],
41 | ];
42 |
43 | class MyWidget extends StatelessWidget {
44 | const MyWidget({Key? key}) : super(key: key);
45 |
46 | @override
47 | Widget build(BuildContext context) {
48 | return CustomScrollView(
49 | slivers: [
50 | for (var swatch in colors)
51 | SliverContainer(
52 | background: DecoratedBox(
53 | decoration: BoxDecoration(
54 | border: Border.all(color: Colors.blue),
55 | borderRadius: BorderRadius.circular(6.0),
56 | color: Colors.black,
57 | ),
58 | ),
59 | bufferExtent: 6.0,
60 | padding: const EdgeInsets.only(bottom: 4.0),
61 | margin: const EdgeInsets.symmetric(
62 | horizontal: 16.0,
63 | vertical: 4.0,
64 | ),
65 | sliver: SliverList(
66 | delegate: SliverChildBuilderDelegate(
67 | (context, index) {
68 | return Container(
69 | decoration: BoxDecoration(
70 | color: swatch[index],
71 | borderRadius: BorderRadius.circular(4.0),
72 | ),
73 | height: 25.0,
74 | margin: const EdgeInsets.only(
75 | left: 4.0,
76 | right: 4.0,
77 | top: 4.0,
78 | ),
79 | );
80 | },
81 | childCount: swatch.length,
82 | ),
83 | ),
84 | ),
85 | ],
86 | );
87 | }
88 | }
89 | ```
90 |
--------------------------------------------------------------------------------
/website/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | hide:
3 | - navigation
4 | ---
5 |
6 | #
7 |
8 | 
9 |
10 | Boxy is a Flutter package created to overcome the limitations of built-in layout widgets, it provides utilities for flex, custom multi-child layouts, dynamic widget inflation, slivers, and more!
11 |
12 | This package is ready for production use, it has excellent documentation, test coverage, and passes strict analysis.
13 |
14 |
15 | :fontawesome-solid-book: __API Docs__
16 | :fontawesome-brands-github: __GitHub__
17 | :simple-dart: __Pub__
18 | :fontawesome-brands-discord: __Discord__
19 |
20 |
21 | ### Getting Started
22 |
23 | To install Boxy, add it to your dependencies in `pubspec.yaml`:
24 |
25 | ```yaml
26 | dependencies:
27 | boxy: ^2.2.1
28 | ```
29 |
30 | Alternatively, you can also use the pub command:
31 |
32 | ```
33 | flutter pub add boxy
34 | ```
35 |
36 | After installing the package and running `flutter pub get`, import one of the top-level libraries:
37 |
38 | ```dart
39 | import 'package:boxy/boxy.dart';
40 | import 'package:boxy/flex.dart';
41 | import 'package:boxy/padding.dart';
42 | import 'package:boxy/slivers.dart';
43 | import 'package:boxy/utils.dart';
44 | ```
45 |
46 | ### Sections
47 |
48 |
53 |
54 |
59 |
60 |
65 |
66 | ### Examples
67 |
68 |
73 |
74 |
79 |
80 |
85 |
86 |
91 |
--------------------------------------------------------------------------------
/website/docs/primer/box-constraints.md:
--------------------------------------------------------------------------------
1 | # BoxConstraints
2 |
3 | [BoxConstraints](https://api.flutter.dev/flutter/rendering/BoxConstraints-class.html) define a minimum and maximum length for each axis, by default it has a minimum width / height of 0, and maximum of infinity.
4 |
5 |
6 | ### Tight Constraints
7 |
8 | An axis is said to be **tight** if the minimum and maximum is the same, e.g. `BoxConstraints(minWidth: 10.0, maxWidth: 10.0)` has a tight width. The child will not be able to size itself on that axis.
9 |
10 | [SizedBox](https://api.flutter.dev/flutter/widgets/SizedBox-class.html) is an example of a way to provide tight constraints to a child:
11 |
12 | ```dart
13 | SizedBox(
14 | width: 100,
15 | child: Text('My width is 100, no more, no less.'),
16 | )
17 | ```
18 |
19 | ### Loose Constraints
20 |
21 | An axis is said to be **loose** if the minimum is 0. The child will be able to choose its size on that axis assuming the maximum is not also 0.
22 |
23 | [Center](https://api.flutter.dev/flutter/widgets/Center-class.html) is a common way of loosening constraints:
24 |
25 | ```dart
26 | SizedBox(
27 | width: 200,
28 | height: 200,
29 | child: Center(
30 | child: Text('I can be any size I want, as long as its < 200.'),
31 | ),
32 | )
33 | ```
34 |
35 | ### Unconstrained / Unbounded Constraints
36 |
37 | An axis is said to be **unbounded** if the maximum is infinity. The child will have to determine its own size on that axis, which can cause issues if the child wants to fill its available space.
38 |
39 | An axis is said to be **unconstrained** if the the minimum is 0 and the maximum is infinity. Unbounded constraints are usually also unconstrained, the child can choose any size it wants.
40 |
41 | The most common way widgets become unconstrained is inside a list, like a [ListView](https://api.flutter.dev/flutter/widgets/ListView-class.html) or [Column](https://api.flutter.dev/flutter/widgets/Column-class.html):
42 |
43 | ```dart
44 | ListView(
45 | children: [
46 | Text('I have a constrained width, but an unconstrained height.'),
47 | ],
48 | )
49 | // or
50 | Column(
51 | children: [
52 | Text('I also have an unconstrained height.'),
53 | ],
54 | )
55 | ```
56 |
57 | Problems can happen when a child wants to consume all of the space available, but its constraints don't let it:
58 |
59 | ```dart
60 | ListView(
61 | children: [
62 | // Oops, the height constraint is loosened by ListView
63 | Column(
64 | children: [
65 | // This throws an error :(
66 | Expanded(child: Text('I want to be as tall as possible')),
67 | ],
68 | ),
69 | ],
70 | )
71 | ```
72 |
73 | ### Quirks and Features 🚗
74 |
75 | One notable quirk is that children are forced to follow the constraints given by their parent, which can be unintuitive sometimes:
76 |
77 | ```dart
78 | SizedBox(
79 | width: 100,
80 | child: SizedBox(
81 | width: 200,
82 | child: Text('Is my width 100 or 200?'),
83 | ),
84 | )
85 | ```
86 |
87 | Do you think the width of this text is 100 or 200 pixels wide? If you chose 100, you are correct.
88 |
89 | The implementation of [RenderConstrainedBox](https://api.flutter.dev/flutter/rendering/RenderConstrainedBox-class.html) reveals why:
90 |
91 | ```dart
92 | child!.layout(_additionalConstraints.enforce(constraints), parentUsesSize: true);
93 | ```
94 |
95 | Before the tight constraints are passed down to the child, it enforces the constraints provided by the SizedBox's parent, otherwise the child would overflow.
96 |
--------------------------------------------------------------------------------
/website/docs/primer/image (2).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/primer/image (2).png
--------------------------------------------------------------------------------
/website/docs/primer/introduction-to-layout.md:
--------------------------------------------------------------------------------
1 | # Introduction to Layout
2 |
3 | When Flutter was created, it set out to provide a render architecture that was simple, performant, and modular. Compare this to [HTML](https://developer.chrome.com/articles/layoutng/) or Android [View](https://developer.android.com/reference/android/view/View)s, which have many complex, slow, and implementation-specific rendering protocols.
4 |
5 | Most of the layout widgets you use in Flutter are actually pretty simple and elegant under the hood, there is rarely any magic, so try not to be intimidated by it!
6 |
7 | ### Constraints go down, Sizes go up
8 |
9 | You can think of layout in Flutter as a bunch of functions that take in BoxConstraints and return a Size:
10 |
11 | ```dart title="(simplification)"
12 | Size layout(BoxConstraints constraints) {
13 | final childSize = child.layout(BoxConstraints()));
14 | child.position(Offset.zero);
15 | return childSize;
16 | }
17 | ```
18 |
19 | This is called the [RenderBox](https://api.flutter.dev/flutter/rendering/RenderBox-class.html) protocol, it's simplicity is what enables animations in Flutter to outperform native Android and iOS.
20 |
21 | The downside of being simple is that developers have to put in a little extra effort to constrain widgets and avoid those pesky flex overflow, unbounded constraints, and infinite size errors.
22 |
23 | The Flutter team made a great article on the design philosophy / performance implications of RenderObjects: [https://docs.flutter.dev/resources/inside-flutter](https://docs.flutter.dev/resources/inside-flutter)
24 |
--------------------------------------------------------------------------------
/website/docs/primer/learn-more.md:
--------------------------------------------------------------------------------
1 | # Learn More
2 |
3 | [:simple-flutter: Understanding Constraints](https://docs.flutter.dev/development/ui/layout/constraints){ .md-button .md-button--primary .block }
4 |
5 | [:simple-flutter: Layout Widgets](https://docs.flutter.dev/development/ui/widgets/layout){ .md-button .md-button--primary .block }
6 |
7 | [:simple-flutter: Layouts in Flutter](https://docs.flutter.dev/development/ui/layout){ .md-button .md-button--primary .block }
8 |
9 | [:simple-gitbook: Widgets - Flutter Internals Wiki](https://flutter.megathink.com/data-model/widgets){ .md-button .md-button--primary .block }
10 |
11 |
12 |
--------------------------------------------------------------------------------
/website/docs/primer/the-many-trees.md:
--------------------------------------------------------------------------------
1 | # The Many Trees
2 |
3 | Before creating your own [RenderObject](https://api.flutter.dev/flutter/rendering/RenderObject-class.html), we should understand the relationship between the Widget, Element, and Render trees.
4 |
5 | 
6 |
7 | You are probably familiar with how [State](https://api.flutter.dev/flutter/widgets/State-class.html) works, it's a persistent instance with methods you can override to know when to initialize, build, and dispose.
8 |
9 | State is actually just a fancy delegate for [ComponentElement](https://api.flutter.dev/flutter/widgets/ComponentElement-class.html) to hide it's ugly internals, other than that [Element](https://api.flutter.dev/flutter/widgets/Element-class.html) and [State](https://api.flutter.dev/flutter/widgets/State-class.html) are essentially the same thing!
10 |
11 | Elements implement [BuildContext](https://api.flutter.dev/flutter/widgets/BuildContext-class.html), which also exists to hide ugly internals.
12 |
13 | The Element tree is formed by recursively calling [Widget.createElement](https://api.flutter.dev/flutter/widgets/Widget/createElement.html), Flutter does the dirty work of reactively mounting, building, reparenting, and unmounting them for you.
14 |
15 | When [RenderObjectElement](https://api.flutter.dev/flutter/widgets/RenderObjectElement-class.html)s are mounted they call [RenderObjectWidget.createRenderObject](https://api.flutter.dev/flutter/widgets/RenderObjectWidget/createRenderObject.html) to create a [RenderObject](https://api.flutter.dev/flutter/rendering/RenderObject-class.html).
16 |
17 | For example, [ColoredBox](https://api.flutter.dev/flutter/widgets/ColoredBox-class.html) is a [SingleChildRenderObjectWidget](https://api.flutter.dev/flutter/widgets/SingleChildRenderObjectWidget-class.html) that creates a [SingleChildRenderObjectElement](https://api.flutter.dev/flutter/widgets/SingleChildRenderObjectElement-class.html), and [Row](https://api.flutter.dev/flutter/widgets/Row-class.html) is a [MultiChildRenderObjectWidget](https://api.flutter.dev/flutter/widgets/MultiChildRenderObjectWidget-class.html) that creates a [MultiChildRenderObjectElement](https://api.flutter.dev/flutter/widgets/MultiChildRenderObjectElement-class.html).
18 |
19 | !!! note
20 |
21 | There is technically no such thing as a "widget tree", widgets are more like user-defined data structures that do not share a root node. People are usually referring to the element tree, since elements form a global tree and provide context.
22 |
--------------------------------------------------------------------------------
/website/docs/primer/trees.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pingbird/boxy/9d17f98f88c9d7dcd1f0db2dd4f16ea63d3b8220/website/docs/primer/trees.png
--------------------------------------------------------------------------------
/website/docs/stylesheets/boxy.css:
--------------------------------------------------------------------------------
1 | [data-md-color-scheme="slate"] {
2 | /*--md-primary-fg-color: #FF6188;*/
3 | --md-primary-fg-color: #221f22;
4 | --md-accent-fg-color: #221f22;
5 | --md-typeset-a-color: #ff7295;
6 | --md-default-bg-color: #2d2a2e;
7 | --md-footer-bg-color: #221f22;
8 | --md-footer-bg-color--dark: #221f22;
9 | --md-code-bg-color: #221f22;
10 | }
11 |
12 | .md-typeset a:focus, .md-typeset a:hover {
13 | color: #ff96b1;
14 | }
15 |
16 | .md-nav__link:is(a:focus,label:focus), .md-nav__link:is(a:hover,label:hover) {
17 | color: #fdced8;
18 | }
19 |
20 | .md-typeset a {
21 | font-weight: bold;
22 | }
23 |
24 | .md-typeset .grid.cards>:is(ul,ol)>li:is(:focus-within,:hover), .md-typeset .grid>.card:is(:focus-within,:hover) {
25 | background-color: #2a262a;
26 | transition: border 0s, box-shadow 0s;
27 | }
28 |
29 | .md-typeset .grid .card.md-button.md-button--primary {
30 | border-bottom: 3px #b2b2b2 solid;
31 | }
32 |
33 | .md-typeset .grid .card.md-button.md-button--primary:is(:hover) {
34 | border-bottom: 3px #fff solid;
35 | }
36 |
37 | .md-typeset .grid.cards>:is(ul,ol)>li:is(:focus-within,:hover), .md-typeset .grid>.card:is(:focus-within,:hover) {
38 | box-shadow: none;
39 | }
40 |
41 | .md-typeset .grid.cards>:is(ul,ol)>li:is(:focus-within,:hover), .md-typeset .grid>.card {
42 | border-radius: 4px;
43 | }
44 |
45 | .md-button.md-button--primary .twemoji {
46 | margin-right: 16px;
47 | }
48 |
49 | .md-footer {
50 | margin-top: 30px;
51 | }
52 |
53 | .highlight span.filename {
54 | border-radius: 4px 4px 0 0;
55 | }
56 |
57 | .md-typeset h1 {
58 | color: var(--md-typeset-color);
59 | font-weight: bold;
60 | }
61 |
62 | .boxy-content-card {
63 | margin-block-start: 16px;
64 | margin-block-end: 16px;
65 | border-radius: 4px;
66 | background-position: center;
67 | background-size: cover;
68 | }
69 |
70 | .boxy-content-card>a {
71 | display: block;
72 | border: 2px solid var(--md-default-fg-color--lightest);
73 | border-radius: 4px;
74 | padding: 16px;
75 | overflow: hidden;
76 | position: relative;
77 | color: var(--md-typeset-color) !important;
78 | backdrop-filter: blur(4px) saturate(60%);
79 | }
80 |
81 | .boxy-content-card>a:hover {
82 | color: var(--md-typeset-color) !important;
83 | }
84 |
85 | .boxy-content-card .description {
86 | font-weight: normal;
87 | font-size: 90%;
88 | }
89 |
90 | .md-button.block {
91 | display: block !important;
92 | }
93 |
94 | .md-typeset .md-button:is(:focus,:hover) {
95 | background-color: #2a262a;
96 | border-color: #2a262a;
97 | }
98 |
99 | .md-search-result mark {
100 | color: #ff7295;
101 | }
102 |
--------------------------------------------------------------------------------
/website/docs/stylesheets/extra.css:
--------------------------------------------------------------------------------
1 | /* Make tabs smaller and add indicator */
2 | .md-footer .md-social {
3 | padding: 0;
4 | }
5 | .md-tabs .md-tabs__link {
6 | margin: 0;
7 | }
8 | .md-tabs .md-tabs__item {
9 | height: inherit;
10 | padding: 0;
11 | display: flex;
12 | align-content: stretch;
13 | }
14 |
15 | .md-tabs .md-tabs__item a {
16 | vertical-align: middle;
17 | padding: 0 8px;
18 | margin: 0 8px;
19 | }
20 | .md-tabs .md-tabs__link {
21 | box-sizing: border-box;
22 | border-bottom: 2px solid rgba(0, 0, 0, 0);
23 | }
24 | .md-tabs .md-tabs__link--active {
25 | border-bottom: 2px solid;
26 | }
27 | .md-tabs .md-tabs__list {
28 | height: 48px;
29 | display: flex;
30 | flex-direction: row;
31 | }
32 |
33 |
34 | /* Make content a little wider */
35 | .md-grid {
36 | max-width: 1300px;
37 | }
38 |
39 | /* Disable breakpoint text scaling */
40 | html {
41 | font-size: 125%;
42 | }
43 |
44 | /* Bigger logo */
45 | .md-header__button.md-logo :-webkit-any(img,svg) {
46 | height: 32px;
47 | }
48 | .md-header__button.md-logo {
49 | padding: 0;
50 | }
51 |
52 | /* Make sidebar invisible instead of collapsed when hidden */
53 | .md-main .md-sidebar--primary[hidden] {
54 | display: initial;
55 | visibility: hidden;
56 | }
57 |
58 | @media screen and (max-width: 76.1875em) {
59 | .md-main .md-sidebar--primary[hidden] {
60 | visibility: visible;
61 | }
62 | }
63 |
64 | [data-md-color-primary="white"] {
65 | --md-button-hover-bg-color: hsla(0, 0, 0, 0.1);
66 | }
67 |
68 | [data-md-color-primary="slate"] {
69 | --md-button-hover-bg-color: hsla(0, 0, 0, 0.1);
70 | }
71 |
72 | /* Better looking buttons */
73 | .md-typeset .md-button {
74 | border-radius: 4px;
75 | margin: 4px;
76 | color: var(--md-typeset-color);
77 | border-color: var(--md-default-fg-color--lightest);
78 | }
79 |
80 | .md-typeset .md-button:is(:focus,:hover):not(.md-button--primary) {
81 | background-color: var(--md-default-fg-color--lightest);
82 | border-color: var(--md-default-fg-color--lightest);
83 | }
84 |
85 | .md-typeset .md-button.md-button--primary {
86 | color: var(--md-primary-bg-color);
87 | border-color: var(--md-primary-fg-color);
88 | }
89 |
90 | .md-typeset .md-button:is(:focus,:hover) {
91 | background-color: var(--md-primary-fg-color);
92 | border-color: var(--md-default-bg-color--light);
93 | }
94 |
95 | /* Better looking tabs */
96 | .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,
97 | .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),
98 | .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),
99 | .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),
100 | .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),
101 | .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),
102 | .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),
103 | .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),
104 | .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),
105 | .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),
106 | .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),
107 | .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),
108 | .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),
109 | .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),
110 | .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),
111 | .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),
112 | .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),
113 | .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),
114 | .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),
115 | .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20) {
116 | color: var(--md-typeset-a-color);
117 | }
118 | .md-typeset .tabbed-labels>label:hover {
119 | color: var(--md-typeset-color--light);
120 | }
121 | .js .md-typeset .tabbed-labels:before {
122 | background: var(--md-typeset-a-color);
123 | }
124 |
125 | /* 🌠 */
126 | .star-list li {
127 | text-indent: 4px;
128 | list-style-image: url(/docs/assets/star.svg);
129 | }
130 | .star-list li::marker {
131 | font-size: 2rem;
132 | margin: 0;
133 | line-height: 0.5;
134 | }
135 |
--------------------------------------------------------------------------------
/website/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: Boxy
2 | site_url: https://boxy.wiki
3 | nav:
4 | - Home: index.md
5 | - Primer:
6 | - primer/introduction-to-layout.md
7 | - primer/box-constraints.md
8 | - primer/the-many-trees.md
9 | - primer/interactive-example.md
10 | - primer/learn-more.md
11 | - CustomBoxy:
12 | - custom-boxy/introduction-to-customboxy.md
13 | - custom-boxy/hello-world.md
14 | - custom-boxy/boxy-child.md
15 | - custom-boxy/boxy-id.md
16 | - custom-boxy/painting.md
17 | - custom-boxy/layers.md
18 | - custom-boxy/widget-inflation.md
19 | - "Example: Square Layout": custom-boxy/examples/square-layout.md
20 | - "Example: Evenly Sized Row": custom-boxy/examples/evenly-sized-row.md
21 | - "Example: Product Tile": custom-boxy/examples/product-tile.md
22 | - "Example: Tree View": custom-boxy/examples/tree-view.md
23 | - Helpers:
24 | - Flex:
25 | - helpers/cross-axis-alignment.md
26 | - helpers/dominant.md
27 | - Slivers:
28 | - helpers/sliver-container.md
29 | - helpers/sliver-card.md
30 | theme:
31 | name: material
32 | custom_dir: overrides
33 | logo: assets/beeper.png
34 | favicon: assets/beeper.png
35 | palette:
36 | - scheme: slate
37 | primary: blue
38 | accent: blue
39 | features:
40 | - navigation.tabs
41 | - navigation.instant
42 | - navigation.expand
43 | - toc.follow
44 | - content.code.annotate
45 | markdown_extensions:
46 | - tables
47 | - admonition
48 | - pymdownx.highlight:
49 | anchor_linenums: true
50 | - pymdownx.emoji:
51 | emoji_index: !!python/name:materialx.emoji.twemoji
52 | emoji_generator: !!python/name:materialx.emoji.to_svg
53 | - pymdownx.inlinehilite
54 | - pymdownx.snippets
55 | - pymdownx.superfences
56 | - pymdownx.tabbed:
57 | alternate_style: true
58 | - attr_list
59 | - md_in_html
60 | - pymdownx.details
61 | extra:
62 | generator: false
63 | social:
64 | - icon: fontawesome/solid/heart
65 | link: https://tst.sh
66 | analytics:
67 | provider: google
68 | property: G-3Q8MDN3K8F
69 | repo_url: https://github.com/PixelToast/flutter-boxy
70 | extra_css:
71 | - stylesheets/extra.css
72 | - stylesheets/boxy.css
73 |
--------------------------------------------------------------------------------
/website/overrides/partials/comments.html:
--------------------------------------------------------------------------------
1 | {% if page.meta.comments %}
2 |
3 |
18 |
19 |
20 |
48 | {% endif %}
--------------------------------------------------------------------------------
/website/overrides/partials/tabs-item.html:
--------------------------------------------------------------------------------
1 | {#-
2 | This file was automatically generated - do not edit
3 | -#}
4 | {% if not class %}
5 | {% set class = "md-tabs__link" %}
6 | {% if nav_item.active %}
7 | {% set class = class ~ " md-tabs__link--active" %}
8 | {% endif %}
9 | {% endif %}
10 | {% if nav_item.children %}
11 | {% set title = title | d(nav_item.title) %}
12 | {% set nav_item = nav_item.children | first %}
13 | {% if nav_item.children %}
14 | {% include "partials/tabs-item.html" %}
15 | {% else %}
16 |
17 |
18 | {{ title }}
19 |
20 |
21 | {% endif %}
22 | {% else %}
23 |
24 |
25 | {{ nav_item.title }}
26 |
27 |
28 | {% endif %}
29 |
--------------------------------------------------------------------------------