Commit 5766cdac authored by Hans Muller's avatar Hans Muller Committed by GitHub

Define LayoutWidgetBuilder in terms of BoxConstraints instead of Size (#4578)

parent 661740d2
...@@ -90,7 +90,8 @@ class _PestoDemoState extends State<PestoDemo> { ...@@ -90,7 +90,8 @@ class _PestoDemoState extends State<PestoDemo> {
) )
], ],
flexibleSpace: new LayoutBuilder( flexibleSpace: new LayoutBuilder(
builder: (BuildContext context, Size size) { builder: (BuildContext context, BoxConstraints constraints) {
final Size size = constraints.biggest;
double appBarHeight = size.height - statusBarHeight; double appBarHeight = size.height - statusBarHeight;
double bestHeight = _kLogoImages.keys.lastWhere( double bestHeight = _kLogoImages.keys.lastWhere(
(double height) => appBarHeight >= height (double height) => appBarHeight >= height
...@@ -293,27 +294,33 @@ class _RecipePageState extends State<_RecipePage> { ...@@ -293,27 +294,33 @@ class _RecipePageState extends State<_RecipePage> {
return new Stack( return new Stack(
children: <Widget>[ children: <Widget>[
_buildContainer(context), _buildContainer(context),
new Padding( new Positioned(
padding: new EdgeInsets.only(top: statusBarHeight), top: 0.0,
child: new AppBar( left: 0.0,
backgroundColor: Colors.transparent, right: 0.0,
elevation: 0, child: new Container(
leading: new IconButton( height: kToolBarHeight + statusBarHeight,
icon: Icons.arrow_back, padding: new EdgeInsets.only(top: statusBarHeight),
onPressed: () => Navigator.pop(context), child: new AppBar(
tooltip: 'Back' backgroundColor: Colors.transparent,
), elevation: 0,
actions: <Widget>[ leading: new IconButton(
new PopupMenuButton<String>( icon: Icons.arrow_back,
onSelected: (String item) {}, onPressed: () => Navigator.pop(context),
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[ tooltip: 'Back'
_buildMenuItem(Icons.share, 'Tweet recipe'), ),
_buildMenuItem(Icons.email, 'Email recipe'), actions: <Widget>[
_buildMenuItem(Icons.message, 'Message recipe'), new PopupMenuButton<String>(
_buildMenuItem(Icons.people, 'Share on Facebook'), onSelected: (String item) {},
] itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
) _buildMenuItem(Icons.share, 'Tweet recipe'),
] _buildMenuItem(Icons.email, 'Email recipe'),
_buildMenuItem(Icons.message, 'Message recipe'),
_buildMenuItem(Icons.people, 'Share on Facebook'),
]
)
]
)
) )
) )
] ]
......
...@@ -178,8 +178,9 @@ class AppBar extends StatelessWidget { ...@@ -178,8 +178,9 @@ class AppBar extends StatelessWidget {
return ((appBarHeight - statusBarHeight) / tabBarHeight).clamp(0.0, 1.0); return ((appBarHeight - statusBarHeight) / tabBarHeight).clamp(0.0, 1.0);
} }
Widget _buildForSize(BuildContext context, Size size) { Widget _buildForSize(BuildContext context, BoxConstraints constraints) {
assert(size.height < double.INFINITY); assert(constraints.maxHeight < double.INFINITY);
final Size size = constraints.biggest;
final double statusBarHeight = MediaQuery.of(context).padding.top; final double statusBarHeight = MediaQuery.of(context).padding.top;
final ThemeData theme = Theme.of(context); final ThemeData theme = Theme.of(context);
...@@ -274,6 +275,8 @@ class AppBar extends StatelessWidget { ...@@ -274,6 +275,8 @@ class AppBar extends StatelessWidget {
child: appBar child: appBar
) )
); );
} else if (flexibleSpace != null) {
appBar = new Positioned(top: 0.0, left: 0.0, right: 0.0, child: appBar);
} }
if (flexibleSpace != null) { if (flexibleSpace != null) {
......
...@@ -9,14 +9,15 @@ import 'package:flutter/rendering.dart'; ...@@ -9,14 +9,15 @@ import 'package:flutter/rendering.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
/// The signature of the [LayoutBuilder] builder function. /// The signature of the [LayoutBuilder] builder function.
typedef Widget LayoutWidgetBuilder(BuildContext context, Size size); typedef Widget LayoutWidgetBuilder(BuildContext context, BoxConstraints constraints);
/// Builds a widget tree that can depend on the parent widget's size. /// Builds a widget tree that can depend on the parent widget's size.
/// ///
/// Similar to the [Builder] widget except that the framework calls the [builder] /// Similar to the [Builder] widget except that the framework calls the [builder]
/// function at layout time and provides the parent widget's size. This is useful /// function at layout time and provides the parent widget's constraints. This
/// when the parent constrains the child's size and doesn't depend on the child's /// is useful when the parent constrains the child's size and doesn't depend on
/// intrinsic size. /// the child's intrinsic size. The LayoutBuilder's final size will match its
/// child's size.
class LayoutBuilder extends RenderObjectWidget { class LayoutBuilder extends RenderObjectWidget {
/// Creates a widget that defers its building until layout. /// Creates a widget that defers its building until layout.
/// ///
...@@ -89,20 +90,16 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren ...@@ -89,20 +90,16 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren
return 0.0; return 0.0;
} }
@override
bool get sizedByParent => true;
@override
void performResize() {
size = constraints.biggest;
}
@override @override
void performLayout() { void performLayout() {
if (callback != null) if (callback != null)
invokeLayoutCallback(callback); invokeLayoutCallback(callback);
if (child != null) if (child != null) {
child.layout(constraints.loosen()); child.layout(constraints, parentUsesSize: true);
size = constraints.constrain(child.size);
} else {
size = constraints.biggest;
}
} }
@override @override
...@@ -169,7 +166,7 @@ class _LayoutBuilderElement extends RenderObjectElement { ...@@ -169,7 +166,7 @@ class _LayoutBuilderElement extends RenderObjectElement {
owner.lockState(() { owner.lockState(() {
Widget built; Widget built;
try { try {
built = widget.builder(this, constraints.biggest); built = widget.builder(this, constraints);
debugWidgetBuilderValue(widget, built); debugWidgetBuilderValue(widget, built);
} catch (e, stack) { } catch (e, stack) {
_debugReportException('building $widget', e, stack); _debugReportException('building $widget', e, stack);
......
...@@ -10,19 +10,20 @@ void main() { ...@@ -10,19 +10,20 @@ void main() {
testWidgets('LayoutBuilder parent size', (WidgetTester tester) async { testWidgets('LayoutBuilder parent size', (WidgetTester tester) async {
Size layoutBuilderSize; Size layoutBuilderSize;
Key childKey = new UniqueKey(); Key childKey = new UniqueKey();
Key parentKey = new UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
new Center( new Center(
child: new SizedBox( child: new ConstrainedBox(
width: 100.0, constraints: const BoxConstraints(maxWidth: 100.0, maxHeight: 200.0),
height: 200.0,
child: new LayoutBuilder( child: new LayoutBuilder(
builder: (BuildContext context, Size size) { key: parentKey,
layoutBuilderSize = size; builder: (BuildContext context, BoxConstraints constraints) {
layoutBuilderSize = constraints.biggest;
return new SizedBox( return new SizedBox(
key: childKey, key: childKey,
width: size.width / 2.0, width: layoutBuilderSize.width / 2.0,
height: size.height / 2.0 height: layoutBuilderSize.height / 2.0
); );
} }
) )
...@@ -31,46 +32,56 @@ void main() { ...@@ -31,46 +32,56 @@ void main() {
); );
expect(layoutBuilderSize, const Size(100.0, 200.0)); expect(layoutBuilderSize, const Size(100.0, 200.0));
RenderBox box = tester.renderObject(find.byKey(childKey)); RenderBox parentBox = tester.renderObject(find.byKey(parentKey));
expect(box.size, equals(const Size(50.0, 100.0))); expect(parentBox.size, equals(const Size(50.0, 100.0)));
RenderBox childBox = tester.renderObject(find.byKey(childKey));
expect(childBox.size, equals(const Size(50.0, 100.0)));
}); });
testWidgets('LayoutBuilder stateful child', (WidgetTester tester) async { testWidgets('LayoutBuilder stateful child', (WidgetTester tester) async {
Size layoutBuilderSize; Size layoutBuilderSize;
StateSetter setState; StateSetter setState;
Key childKey = new UniqueKey(); Key childKey = new UniqueKey();
Key parentKey = new UniqueKey();
double childWidth = 10.0; double childWidth = 10.0;
double childHeight = 20.0; double childHeight = 20.0;
await tester.pumpWidget( await tester.pumpWidget(
new LayoutBuilder( new Center(
builder: (BuildContext context, Size size) { child: new LayoutBuilder(
layoutBuilderSize = size; key: parentKey,
return new StatefulBuilder( builder: (BuildContext context, BoxConstraints constraints) {
builder: (BuildContext context, StateSetter setter) { layoutBuilderSize = constraints.biggest;
setState = setter; return new StatefulBuilder(
return new SizedBox( builder: (BuildContext context, StateSetter setter) {
key: childKey, setState = setter;
width: childWidth, return new SizedBox(
height: childHeight key: childKey,
); width: childWidth,
} height: childHeight
); );
} }
);
}
)
) )
); );
expect(layoutBuilderSize, equals(const Size(800.0, 600.0))); expect(layoutBuilderSize, equals(const Size(800.0, 600.0)));
RenderBox box = tester.renderObject(find.byKey(childKey)); RenderBox parentBox = tester.renderObject(find.byKey(parentKey));
expect(box.size, equals(const Size(10.0, 20.0))); expect(parentBox.size, equals(const Size(10.0, 20.0)));
RenderBox childBox = tester.renderObject(find.byKey(childKey));
expect(childBox.size, equals(const Size(10.0, 20.0)));
setState(() { setState(() {
childWidth = 100.0; childWidth = 100.0;
childHeight = 200.0; childHeight = 200.0;
}); });
await tester.pump(); await tester.pump();
box = tester.renderObject(find.byKey(childKey)); parentBox = tester.renderObject(find.byKey(parentKey));
expect(box.size, equals(const Size(100.0, 200.0))); expect(parentBox.size, equals(const Size(100.0, 200.0)));
childBox = tester.renderObject(find.byKey(childKey));
expect(childBox.size, equals(const Size(100.0, 200.0)));
}); });
testWidgets('LayoutBuilder stateful parent', (WidgetTester tester) async { testWidgets('LayoutBuilder stateful parent', (WidgetTester tester) async {
...@@ -89,12 +100,12 @@ void main() { ...@@ -89,12 +100,12 @@ void main() {
width: childWidth, width: childWidth,
height: childHeight, height: childHeight,
child: new LayoutBuilder( child: new LayoutBuilder(
builder: (BuildContext context, Size size) { builder: (BuildContext context, BoxConstraints constraints) {
layoutBuilderSize = size; layoutBuilderSize = constraints.biggest;
return new SizedBox( return new SizedBox(
key: childKey, key: childKey,
width: size.width, width: layoutBuilderSize.width,
height: size.height height: layoutBuilderSize.height
); );
} }
) )
...@@ -117,10 +128,11 @@ void main() { ...@@ -117,10 +128,11 @@ void main() {
expect(box.size, equals(const Size(100.0, 200.0))); expect(box.size, equals(const Size(100.0, 200.0)));
}); });
testWidgets('LayoutBuilder and Inherited -- do not rebuild when not using inherited', (WidgetTester tester) async { testWidgets('LayoutBuilder and Inherited -- do not rebuild when not using inherited', (WidgetTester tester) async {
int built = 0; int built = 0;
Widget target = new LayoutBuilder( Widget target = new LayoutBuilder(
builder: (BuildContext context, Size size) { builder: (BuildContext context, BoxConstraints constraints) {
built += 1; built += 1;
return new Container(); return new Container();
} }
...@@ -143,7 +155,7 @@ void main() { ...@@ -143,7 +155,7 @@ void main() {
testWidgets('LayoutBuilder and Inherited -- do rebuild when using inherited', (WidgetTester tester) async { testWidgets('LayoutBuilder and Inherited -- do rebuild when using inherited', (WidgetTester tester) async {
int built = 0; int built = 0;
Widget target = new LayoutBuilder( Widget target = new LayoutBuilder(
builder: (BuildContext context, Size size) { builder: (BuildContext context, BoxConstraints constraints) {
built += 1; built += 1;
MediaQuery.of(context); MediaQuery.of(context);
return new Container(); return new Container();
......
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