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