Commit 262dd7a6 authored by Adam Barth's avatar Adam Barth

Add support for autolayout to widgets

This patch teaches the widget framework how to use Cassowary-based
autolayout. To integrate autolayout with widgets, I had to refactor how
RenderAutoLayout worked a bit. Now RenderAutoLayout follows the same
delegate pattern we use for custom paint and custom layout.
parent cdc40554
// Copyright 2015 The Chromium Authors. All rights reserved.
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
......@@ -8,6 +8,45 @@
import 'package:cassowary/cassowary.dart' as al;
import 'package:flutter/rendering.dart';
class _MyAutoLayoutDelegate extends AutoLayoutDelegate {
AutoLayoutParams p1 = new AutoLayoutParams();
AutoLayoutParams p2 = new AutoLayoutParams();
AutoLayoutParams p3 = new AutoLayoutParams();
AutoLayoutParams p4 = new AutoLayoutParams();
List<al.Constraint> getConstraints(AutoLayoutParams parentParams) {
return <al.Constraint>[
// Sum of widths of each box must be equal to that of the container
(p1.width + p2.width + p3.width == parentParams.width) as al.Constraint,
// The boxes must be stacked left to right
p1.rightEdge <= p2.leftEdge,
p2.rightEdge <= p3.leftEdge,
// The widths of the first and the third boxes should be equal
(p1.width == p3.width) as al.Constraint,
// The width of the second box should be twice as much as that of the first
// and third
(p2.width * al.cm(2.0) == p1.width) as al.Constraint,
// The height of the three boxes should be equal to that of the container
(p1.height == p2.height) as al.Constraint,
(p2.height == p3.height) as al.Constraint,
(p3.height == parentParams.height) as al.Constraint,
// The fourth box should be half as wide as the second and must be attached
// to the right edge of the same (by its center)
(p4.width == p2.width / al.cm(2.0)) as al.Constraint,
(p4.height == al.cm(50.0)) as al.Constraint,
(p4.horizontalCenter == p2.rightEdge) as al.Constraint,
(p4.verticalCenter == p2.height / al.cm(2.0)) as al.Constraint,
];
}
bool shouldUpdateConstraints(AutoLayoutDelegate oldDelegate) => true;
}
void main() {
RenderDecoratedBox c1 = new RenderDecoratedBox(
decoration: new BoxDecoration(backgroundColor: const Color(0xFFFF0000))
......@@ -25,40 +64,22 @@ void main() {
decoration: new BoxDecoration(backgroundColor: const Color(0xFFFFFFFF))
);
RenderAutoLayout root = new RenderAutoLayout(children: <RenderBox>[c1, c2, c3, c4]);
AutoLayoutParentData p1 = c1.parentData;
AutoLayoutParentData p2 = c2.parentData;
AutoLayoutParentData p3 = c3.parentData;
AutoLayoutParentData p4 = c4.parentData;
root.addConstraints(<al.Constraint>[
// Sum of widths of each box must be equal to that of the container
(p1.width + p2.width + p3.width == root.width) as al.Constraint,
_MyAutoLayoutDelegate delegate = new _MyAutoLayoutDelegate();
// The boxes must be stacked left to right
p1.rightEdge <= p2.leftEdge,
p2.rightEdge <= p3.leftEdge,
// The widths of the first and the third boxes should be equal
(p1.width == p3.width) as al.Constraint,
// The width of the second box should be twice as much as that of the first
// and third
(p2.width * al.cm(2.0) == p1.width) as al.Constraint,
RenderAutoLayout root = new RenderAutoLayout(
delegate: delegate,
children: <RenderBox>[c1, c2, c3, c4]
);
// The height of the three boxes should be equal to that of the container
(p1.height == p2.height) as al.Constraint,
(p2.height == p3.height) as al.Constraint,
(p3.height == root.height) as al.Constraint,
AutoLayoutParentData parentData1 = c1.parentData;
AutoLayoutParentData parentData2 = c2.parentData;
AutoLayoutParentData parentData3 = c3.parentData;
AutoLayoutParentData parentData4 = c4.parentData;
// The fourth box should be half as wide as the second and must be attached
// to the right edge of the same (by its center)
(p4.width == p2.width / al.cm(2.0)) as al.Constraint,
(p4.height == al.cm(50.0)) as al.Constraint,
(p4.horizontalCenter == p2.rightEdge) as al.Constraint,
(p4.verticalCenter == p2.height / al.cm(2.0)) as al.Constraint,
]);
parentData1.params = delegate.p1;
parentData2.params = delegate.p2;
parentData3.params = delegate.p3;
parentData4.params = delegate.p4;
new RenderingFlutterBinding(root: root);
}
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This example shows how to use the Cassowary autolayout system with widgets.
import 'package:cassowary/cassowary.dart' as al;
import 'package:flutter/widgets.dart';
class _MyAutoLayoutDelegate extends AutoLayoutDelegate {
AutoLayoutParams p1 = new AutoLayoutParams();
AutoLayoutParams p2 = new AutoLayoutParams();
AutoLayoutParams p3 = new AutoLayoutParams();
AutoLayoutParams p4 = new AutoLayoutParams();
List<al.Constraint> getConstraints(AutoLayoutParams parentParams) {
return <al.Constraint>[
// Sum of widths of each box must be equal to that of the container
(p1.width + p2.width + p3.width == parentParams.width) as al.Constraint,
// The boxes must be stacked left to right
p1.rightEdge <= p2.leftEdge,
p2.rightEdge <= p3.leftEdge,
// The widths of the first and the third boxes should be equal
(p1.width == p3.width) as al.Constraint,
// The width of the second box should be twice as much as that of the first
// and third
(p2.width * al.cm(2.0) == p1.width) as al.Constraint,
// The height of the three boxes should be equal to that of the container
(p1.height == p2.height) as al.Constraint,
(p2.height == p3.height) as al.Constraint,
(p3.height == parentParams.height) as al.Constraint,
// The fourth box should be half as wide as the second and must be attached
// to the right edge of the same (by its center)
(p4.width == p2.width / al.cm(2.0)) as al.Constraint,
(p4.height == al.cm(50.0)) as al.Constraint,
(p4.horizontalCenter == p2.rightEdge) as al.Constraint,
(p4.verticalCenter == p2.height / al.cm(2.0)) as al.Constraint,
];
}
bool shouldUpdateConstraints(AutoLayoutDelegate oldDelegate) => true;
}
class ColoredBox extends StatelessComponent {
ColoredBox({ Key key, this.params, this.color }) : super(key: key);
final AutoLayoutParams params;
final Color color;
Widget build(BuildContext context) {
return new AutoLayoutChild(
params: params,
child: new DecoratedBox(
decoration: new BoxDecoration(backgroundColor: color)
)
);
}
}
class ColoredBoxes extends StatefulComponent {
_ColoredBoxesState createState() => new _ColoredBoxesState();
}
class _ColoredBoxesState extends State<ColoredBoxes> {
final _MyAutoLayoutDelegate delegate = new _MyAutoLayoutDelegate();
Widget build(BuildContext context) {
return new AutoLayout(
delegate: delegate,
children: <Widget>[
new ColoredBox(params: delegate.p1, color: const Color(0xFFFF0000)),
new ColoredBox(params: delegate.p2, color: const Color(0xFF00FF00)),
new ColoredBox(params: delegate.p3, color: const Color(0xFF0000FF)),
new ColoredBox(params: delegate.p4, color: const Color(0xFFFFFFFF)),
]
);
}
}
void main() {
runApp(new ColoredBoxes());
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/rendering.dart';
import 'framework.dart';
export 'package:flutter/rendering.dart' show
AutoLayoutParams,
AutoLayoutDelegate;
class AutoLayout extends MultiChildRenderObjectWidget {
AutoLayout({
Key key,
this.delegate,
List<Widget> children: const <Widget>[]
}) : super(key: key, children: children);
final AutoLayoutDelegate delegate;
RenderAutoLayout createRenderObject() => new RenderAutoLayout(delegate: delegate);
void updateRenderObject(RenderAutoLayout renderObject, AutoLayout oldWidget) {
renderObject.delegate = delegate;
}
}
class AutoLayoutChild extends ParentDataWidget<AutoLayout> {
AutoLayoutChild({ Key key, this.params, Widget child })
: super(key: key, child: child);
final AutoLayoutParams params;
void applyParentData(RenderObject renderObject) {
assert(renderObject.parentData is AutoLayoutParentData);
final AutoLayoutParentData parentData = renderObject.parentData;
// AutoLayoutParentData filters out redundant writes and marks needs layout
// as appropriate.
parentData.params = params;
}
}
......@@ -6,6 +6,7 @@
library widgets;
export 'src/widgets/asset_vendor.dart';
export 'src/widgets/auto_layout.dart';
export 'src/widgets/basic.dart';
export 'src/widgets/binding.dart';
export 'src/widgets/checked_mode_banner.dart';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment