diff --git a/packages/flutter/lib/rendering/block.dart b/packages/flutter/lib/rendering/block.dart index 7214c533d7..6b842dd106 100644 --- a/packages/flutter/lib/rendering/block.dart +++ b/packages/flutter/lib/rendering/block.dart @@ -76,6 +76,7 @@ abstract class RenderBlockBase extends RenderBox with ContainerRenderObjectMixin assert(!size.isInfinite); } + String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}direction: ${direction}\n'; } class RenderBlock extends RenderBlockBase { @@ -259,4 +260,5 @@ class RenderBlockViewport extends RenderBlockBase { defaultHitTestChildren(result, position: position + new Offset(0.0, -startOffset)); } + String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}startOffset: ${startOffset}\n'; } diff --git a/packages/flutter/lib/rendering/proxy_box.dart b/packages/flutter/lib/rendering/proxy_box.dart index 3b63a00f1a..418d59a80f 100644 --- a/packages/flutter/lib/rendering/proxy_box.dart +++ b/packages/flutter/lib/rendering/proxy_box.dart @@ -213,6 +213,7 @@ class RenderShrinkWrapWidth extends RenderProxyBox { } BoxConstraints _getInnerConstraints(BoxConstraints constraints) { + assert(child != null); if (constraints.hasTightWidth) return constraints; double width = child.getMaxIntrinsicWidth(constraints); @@ -233,14 +234,14 @@ class RenderShrinkWrapWidth extends RenderProxyBox { double getMinIntrinsicHeight(BoxConstraints constraints) { if (child == null) - return constraints.constrainWidth(0.0); + return constraints.constrainHeight(0.0); double childResult = child.getMinIntrinsicHeight(_getInnerConstraints(constraints)); return constraints.constrainHeight(applyStep(childResult, _stepHeight)); } double getMaxIntrinsicHeight(BoxConstraints constraints) { if (child == null) - return constraints.constrainWidth(0.0); + return constraints.constrainHeight(0.0); double childResult = child.getMaxIntrinsicHeight(_getInnerConstraints(constraints)); return constraints.constrainHeight(applyStep(childResult, _stepHeight)); } @@ -261,6 +262,61 @@ class RenderShrinkWrapWidth extends RenderProxyBox { } +class RenderShrinkWrapHeight extends RenderProxyBox { + + // This class will attempt to size its child to the child's maximum + // intrinsic height, given the provided constraints; and will then + // adopt the child's resulting dimensions. + + // Note: laying out this class is relatively expensive. Avoid using + // it where possible. + + RenderShrinkWrapHeight({ + RenderBox child + }) : super(child); + + BoxConstraints _getInnerConstraints(BoxConstraints constraints) { + assert(child != null); + if (constraints.hasTightHeight) + return constraints; + double height = child.getMaxIntrinsicHeight(constraints); + assert(height == constraints.constrainHeight(height)); + return constraints.applyHeight(height); + } + + double getMinIntrinsicWidth(BoxConstraints constraints) { + if (child == null) + return constraints.constrainWidth(0.0); + return child.getMinIntrinsicWidth(_getInnerConstraints(constraints)); + } + + double getMaxIntrinsicWidth(BoxConstraints constraints) { + if (child == null) + return constraints.constrainWidth(0.0); + return child.getMaxIntrinsicWidth(_getInnerConstraints(constraints)); + } + + double getMinIntrinsicHeight(BoxConstraints constraints) { + return getMaxIntrinsicHeight(constraints); + } + + double getMaxIntrinsicHeight(BoxConstraints constraints) { + if (child == null) + return constraints.constrainHeight(0.0); + return child.getMaxIntrinsicHeight(constraints); + } + + void performLayout() { + if (child != null) { + child.layout(_getInnerConstraints(constraints), parentUsesSize: true); + size = child.size; + } else { + performResize(); + } + } + +} + class RenderOpacity extends RenderProxyBox { RenderOpacity({ RenderBox child, double opacity }) : this._opacity = opacity, super(child) { diff --git a/packages/flutter/lib/widgets/basic.dart b/packages/flutter/lib/widgets/basic.dart index 89133056b3..cc5b86aca3 100644 --- a/packages/flutter/lib/widgets/basic.dart +++ b/packages/flutter/lib/widgets/basic.dart @@ -267,7 +267,7 @@ class ShrinkWrapWidth extends OneChildRenderObjectWrapper { final double stepWidth; final double stepHeight; - RenderShrinkWrapWidth createNode() => new RenderShrinkWrapWidth(); + RenderShrinkWrapWidth createNode() => new RenderShrinkWrapWidth(stepWidth: stepWidth, stepHeight: stepHeight); RenderShrinkWrapWidth get renderObject => super.renderObject; void syncRenderObject(ShrinkWrapWidth old) { @@ -277,6 +277,16 @@ class ShrinkWrapWidth extends OneChildRenderObjectWrapper { } } +class ShrinkWrapHeight extends OneChildRenderObjectWrapper { + ShrinkWrapHeight({ Key key, Widget child }) + : super(key: key, child: child); + + RenderShrinkWrapHeight createNode() => new RenderShrinkWrapHeight(); + RenderShrinkWrapHeight get renderObject => super.renderObject; + + // Nothing to sync, so we don't implement syncRenderObject() +} + class Baseline extends OneChildRenderObjectWrapper { Baseline({ Key key, this.baseline, this.baselineType: TextBaseline.alphabetic, Widget child }) : super(key: key, child: child); diff --git a/packages/unit/test/rendering/shrink_wrap_test.dart b/packages/unit/test/rendering/shrink_wrap_test.dart new file mode 100644 index 0000000000..356cb325aa --- /dev/null +++ b/packages/unit/test/rendering/shrink_wrap_test.dart @@ -0,0 +1,64 @@ +import 'dart:sky' as sky; + +import 'package:sky/rendering.dart'; +import 'package:test/test.dart'; + +import 'layout_utils.dart'; + +class RenderTestBox extends RenderBox { + RenderTestBox(this._intrinsicDimensions); + + final BoxConstraints _intrinsicDimensions; + + double getMinIntrinsicWidth(BoxConstraints constraints) { + return constraints.constrainWidth(_intrinsicDimensions.minWidth); + } + + double getMaxIntrinsicWidth(BoxConstraints constraints) { + return constraints.constrainWidth(_intrinsicDimensions.maxWidth); + } + + double getMinIntrinsicHeight(BoxConstraints constraints) { + return constraints.constrainHeight(_intrinsicDimensions.minHeight); + } + + double getMaxIntrinsicHeight(BoxConstraints constraints) { + return constraints.constrainHeight(_intrinsicDimensions.maxHeight); + } + + bool get sizedByParent => true; + void performResize() { + size = constraints.constrain(new Size(_intrinsicDimensions.minWidth + (_intrinsicDimensions.maxWidth-_intrinsicDimensions.minWidth) / 2.0, + _intrinsicDimensions.minHeight + (_intrinsicDimensions.maxHeight-_intrinsicDimensions.minHeight) / 2.0)); + } +} + +void main() { + test('Shrink-wrapping width', () { + RenderBox child = new RenderTestBox(new BoxConstraints(minWidth: 10.0, maxWidth: 100.0, minHeight: 20.0, maxHeight: 200.0)); + + RenderBox parent = new RenderShrinkWrapWidth(child: child); + layout(parent, + constraints: new BoxConstraints( + minWidth: 5.0, + minHeight: 8.0, + maxWidth: 500.0, + maxHeight: 800.0)); + expect(parent.size.width, equals(100.0)); + expect(parent.size.height, equals(110.0)); + }); + + test('Shrink-wrapping height', () { + RenderBox child = new RenderTestBox(new BoxConstraints(minWidth: 10.0, maxWidth: 100.0, minHeight: 20.0, maxHeight: 200.0)); + + RenderBox parent = new RenderShrinkWrapHeight(child: child); + layout(parent, + constraints: new BoxConstraints( + minWidth: 5.0, + minHeight: 8.0, + maxWidth: 500.0, + maxHeight: 800.0)); + expect(parent.size.width, equals(55.0)); + expect(parent.size.height, equals(200.0)); + }); +}