mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Reimplement 'stretch' for flexible items correctly.
Fixes #698 to actually work. Also, adds some debugging aids around Flex. And a test to check this fix.
This commit is contained in:
parent
47921c196f
commit
1cdfe25958
@ -396,6 +396,7 @@ abstract class RenderBox extends RenderObject {
|
||||
assert(value._owner.parent == this);
|
||||
}
|
||||
_size = inDebugBuild ? new _DebugSize(value, this, debugCanParentUseSize) : value;
|
||||
assert(debugDoesMeetConstraints());
|
||||
}
|
||||
|
||||
void applyPaintTransform(Matrix4 transform) {
|
||||
|
||||
@ -85,7 +85,6 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
|
||||
}
|
||||
}
|
||||
|
||||
// Set during layout if overflow occurred on the main axis
|
||||
TextBaseline _textBaseline;
|
||||
TextBaseline get textBaseline => _textBaseline;
|
||||
void set textBaseline (TextBaseline value) {
|
||||
@ -95,6 +94,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
|
||||
}
|
||||
}
|
||||
|
||||
// Set during layout if overflow occurred on the main axis
|
||||
double _overflow;
|
||||
|
||||
void setupParentData(RenderBox child) {
|
||||
@ -344,29 +344,29 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
|
||||
if (alignItems == FlexAlignItems.stretch) {
|
||||
switch (_direction) {
|
||||
case FlexDirection.horizontal:
|
||||
innerConstraints = new BoxConstraints(minWidth: constraints.maxWidth,
|
||||
maxWidth: constraints.maxWidth,
|
||||
minHeight: constraints.minHeight,
|
||||
innerConstraints = new BoxConstraints(minWidth: spaceForChild,
|
||||
maxWidth: spaceForChild,
|
||||
minHeight: constraints.maxHeight,
|
||||
maxHeight: constraints.maxHeight);
|
||||
break;
|
||||
case FlexDirection.vertical:
|
||||
innerConstraints = new BoxConstraints(minWidth: constraints.minWidth,
|
||||
innerConstraints = new BoxConstraints(minWidth: constraints.maxWidth,
|
||||
maxWidth: constraints.maxWidth,
|
||||
minHeight: constraints.maxHeight,
|
||||
maxHeight: constraints.maxHeight);
|
||||
minHeight: spaceForChild,
|
||||
maxHeight: spaceForChild);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (_direction) {
|
||||
case FlexDirection.horizontal:
|
||||
innerConstraints = new BoxConstraints(maxHeight: constraints.maxHeight,
|
||||
minWidth: spaceForChild,
|
||||
maxWidth: spaceForChild);
|
||||
innerConstraints = new BoxConstraints(minWidth: spaceForChild,
|
||||
maxWidth: spaceForChild,
|
||||
maxHeight: constraints.maxHeight);
|
||||
break;
|
||||
case FlexDirection.vertical:
|
||||
innerConstraints = new BoxConstraints(minHeight: spaceForChild,
|
||||
maxHeight: spaceForChild,
|
||||
maxWidth: constraints.maxWidth);
|
||||
innerConstraints = new BoxConstraints(maxWidth: constraints.maxWidth,
|
||||
minHeight: spaceForChild,
|
||||
maxHeight: spaceForChild);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -467,35 +467,54 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
|
||||
}
|
||||
|
||||
void paint(PaintingContext context, Offset offset) {
|
||||
if (_overflow > 0) {
|
||||
context.canvas.save();
|
||||
context.canvas.clipRect(offset & size);
|
||||
if (_overflow <= 0.0) {
|
||||
defaultPaint(context, offset);
|
||||
context.canvas.restore();
|
||||
} else {
|
||||
defaultPaint(context, offset);
|
||||
}
|
||||
}
|
||||
|
||||
void debugPaintSize(PaintingContext context, Offset offset) {
|
||||
super.debugPaintSize(context, offset);
|
||||
if (_overflow <= 0)
|
||||
return;
|
||||
|
||||
// Draw a red rectangle over the overflow area in debug mode
|
||||
// You should be using a Clip if you want to clip your children
|
||||
Paint paint = new Paint()..color = const Color(0x7FFF0000);
|
||||
Rect overflowRect;
|
||||
switch(direction) {
|
||||
case FlexDirection.horizontal:
|
||||
overflowRect = offset + new Offset(size.width, 0.0) &
|
||||
new Size(_overflow, size.height);
|
||||
break;
|
||||
case FlexDirection.vertical:
|
||||
overflowRect = offset + new Offset(0.0, size.height) &
|
||||
new Size(size.width, _overflow);
|
||||
break;
|
||||
}
|
||||
context.canvas.drawRect(overflowRect, paint);
|
||||
|
||||
// We have overflow. Clip it.
|
||||
context.canvas.save();
|
||||
context.canvas.clipRect(offset & size);
|
||||
defaultPaint(context, offset);
|
||||
context.canvas.restore();
|
||||
assert(() {
|
||||
// In debug mode, if you have overflow, we highlight where the
|
||||
// overflow would be by painting that area red. Since that is
|
||||
// likely to be clipped by an ancestor, we also draw a thick red
|
||||
// line at the edge that's overflowing.
|
||||
|
||||
// If you do want clipping, use a RenderClip (Clip in the
|
||||
// Widgets library).
|
||||
|
||||
Paint markerPaint = new Paint()..color = const Color(0xE0FF0000);
|
||||
Paint highlightPaint = new Paint()..color = const Color(0x7FFF0000);
|
||||
const kMarkerSize = 0.1;
|
||||
Rect markerRect, overflowRect;
|
||||
switch(direction) {
|
||||
case FlexDirection.horizontal:
|
||||
markerRect = offset + new Offset(size.width * (1.0 - kMarkerSize), 0.0) &
|
||||
new Size(size.width * kMarkerSize, size.height);
|
||||
overflowRect = offset + new Offset(size.width, 0.0) &
|
||||
new Size(_overflow, size.height);
|
||||
break;
|
||||
case FlexDirection.vertical:
|
||||
markerRect = offset + new Offset(0.0, size.height * (1.0 - kMarkerSize)) &
|
||||
new Size(size.width, size.height * kMarkerSize);
|
||||
overflowRect = offset + new Offset(0.0, size.height) &
|
||||
new Size(size.width, _overflow);
|
||||
break;
|
||||
}
|
||||
context.canvas.drawRect(markerRect, markerPaint);
|
||||
context.canvas.drawRect(overflowRect, highlightPaint);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
String toStringName() {
|
||||
String header = super.toStringName();
|
||||
if (_overflow > 0.0)
|
||||
header += ' OVERFLOWING';
|
||||
return header;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -738,6 +738,13 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
String toString([String prefix = '']) {
|
||||
RenderObject debugPreviousActiveLayout = _debugActiveLayout;
|
||||
_debugActiveLayout = null;
|
||||
String header = toStringName();
|
||||
prefix += ' ';
|
||||
String result = '${header}\n${debugDescribeSettings(prefix)}${debugDescribeChildren(prefix)}';
|
||||
_debugActiveLayout = debugPreviousActiveLayout;
|
||||
return result;
|
||||
}
|
||||
String toStringName() {
|
||||
String header = '${runtimeType}';
|
||||
if (_relayoutSubtreeRoot != null && _relayoutSubtreeRoot != this) {
|
||||
int count = 1;
|
||||
@ -752,10 +759,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
header += ' NEEDS-LAYOUT';
|
||||
if (!attached)
|
||||
header += ' DETACHED';
|
||||
prefix += ' ';
|
||||
String result = '${header}\n${debugDescribeSettings(prefix)}${debugDescribeChildren(prefix)}';
|
||||
_debugActiveLayout = debugPreviousActiveLayout;
|
||||
return result;
|
||||
return header;
|
||||
}
|
||||
String debugDescribeSettings(String prefix) => '${prefix}parentData: ${parentData}\n${prefix}constraints: ${constraints}\n';
|
||||
String debugDescribeChildren(String prefix) => '';
|
||||
|
||||
68
sky/tests/widgets/flex-expected.txt
Normal file
68
sky/tests/widgets/flex-expected.txt
Normal file
@ -0,0 +1,68 @@
|
||||
TestRenderView enabled
|
||||
|
||||
PAINT FOR FRAME #1 ----------------------------------------------
|
||||
1 | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
------------------------------------------------------------------------
|
||||
|
||||
PAINT FOR FRAME #2 ----------------------------------------------
|
||||
2 | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | paintChild RenderPadding at Point(0.0, 0.0)
|
||||
2 | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | paintChild RenderFlex at Point(50.0, 50.0)
|
||||
2 | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | paintChild RenderPadding at Point(50.0, 50.0)
|
||||
2 | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | paintChild RenderDecoratedBox at Point(54.0, 54.0)
|
||||
2 | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | drawRRect(Instance of 'RRect', Paint(color:Color(0xffffffff), drawLooper:true))
|
||||
2 | | | | | paintChild RenderClipRRect at Point(54.0, 54.0)
|
||||
2 | | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | | saveLayer(Rect.fromLTRB(54.0, 54.0, 354.0, 546.0), Paint(color:Color(0xff000000)))
|
||||
2 | | | | | | clipRRect()
|
||||
2 | | | | | | paintChild RenderConstrainedBox at Point(54.0, 54.0)
|
||||
2 | | | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | | | paintChild RenderFlex at Point(54.0, 54.0)
|
||||
2 | | | | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | | | | paintChild RenderParagraph at Point(54.0, 54.0)
|
||||
2 | | | | | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | | | | | translate(54.0, 54.0)
|
||||
2 | | | | | | | | | translate(-54.0, -54.0)
|
||||
2 | | | | | | | | paintChild RenderDecoratedBox at Point(54.0, 74.0)
|
||||
2 | | | | | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | | | | | drawRect(Rect.fromLTRB(54.0, 74.0, 354.0, 546.0), Paint(color:Color(0xff509050)))
|
||||
2 | | | | | | | | | paintChild RenderFlex at Point(54.0, 74.0)
|
||||
2 | | | | | | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | | | | | | paintChild RenderParagraph at Point(54.0, 74.0)
|
||||
2 | | | | | | | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | | | | | | | translate(54.0, 74.0)
|
||||
2 | | | | | | | | | | | translate(-54.0, -74.0)
|
||||
2 | | | | | | restore
|
||||
2 | | | paintChild RenderPadding at Point(358.0, 50.0)
|
||||
2 | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | paintChild RenderDecoratedBox at Point(362.0, 54.0)
|
||||
2 | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | drawRRect(Instance of 'RRect', Paint(color:Color(0xffffffff), drawLooper:true))
|
||||
2 | | | | | paintChild RenderClipRRect at Point(362.0, 54.0)
|
||||
2 | | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | | saveLayer(Rect.fromLTRB(362.0, 54.0, 662.0, 546.0), Paint(color:Color(0xff000000)))
|
||||
2 | | | | | | clipRRect()
|
||||
2 | | | | | | paintChild RenderConstrainedBox at Point(362.0, 54.0)
|
||||
2 | | | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | | | paintChild RenderFlex at Point(362.0, 54.0)
|
||||
2 | | | | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | | | | paintChild RenderDecoratedBox at Point(362.0, 54.0)
|
||||
2 | | | | | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | | | | | drawRect(Rect.fromLTRB(362.0, 54.0, 662.0, 526.0), Paint(color:Color(0xff509050)))
|
||||
2 | | | | | | | | | paintChild RenderFlex at Point(362.0, 54.0)
|
||||
2 | | | | | | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | | | | | | paintChild RenderParagraph at Point(362.0, 54.0)
|
||||
2 | | | | | | | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | | | | | | | translate(362.0, 54.0)
|
||||
2 | | | | | | | | | | | translate(-362.0, -54.0)
|
||||
2 | | | | | | | | paintChild RenderParagraph at Point(362.0, 526.0)
|
||||
2 | | | | | | | | | TestPaintingCanvas() constructor: 800.0 x 600.0
|
||||
2 | | | | | | | | | translate(362.0, 526.0)
|
||||
2 | | | | | | | | | translate(-362.0, -526.0)
|
||||
2 | | | | | | restore
|
||||
------------------------------------------------------------------------
|
||||
PAINTED 2 FRAMES
|
||||
69
sky/tests/widgets/flex.dart
Normal file
69
sky/tests/widgets/flex.dart
Normal file
@ -0,0 +1,69 @@
|
||||
// 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:sky/widgets.dart';
|
||||
|
||||
import '../resources/display_list.dart';
|
||||
|
||||
class TestApp extends App {
|
||||
Widget build() {
|
||||
return new Container(
|
||||
padding: new EdgeDims.all(50.0),
|
||||
child: new Flex([
|
||||
new Card(
|
||||
child: new Container(
|
||||
width: 300.0,
|
||||
height: 500.0,
|
||||
child: new Flex([
|
||||
new Text('TOP'),
|
||||
new Flexible(
|
||||
child: new Container(
|
||||
decoration: new BoxDecoration(backgroundColor: new Color(0xFF509050)),
|
||||
child: new Flex([new Text('bottom')],
|
||||
direction: FlexDirection.vertical,
|
||||
alignItems: FlexAlignItems.stretch
|
||||
)
|
||||
)
|
||||
)
|
||||
],
|
||||
alignItems: FlexAlignItems.stretch,
|
||||
direction: FlexDirection.vertical
|
||||
)
|
||||
)
|
||||
),
|
||||
new Card(
|
||||
child: new Container(
|
||||
width: 300.0,
|
||||
height: 500.0,
|
||||
child: new Flex([
|
||||
new Flexible(
|
||||
child: new Container(
|
||||
decoration: new BoxDecoration(backgroundColor: new Color(0xFF509050)),
|
||||
child: new Flex([new Text('top')],
|
||||
direction: FlexDirection.vertical,
|
||||
alignItems: FlexAlignItems.stretch
|
||||
)
|
||||
)
|
||||
),
|
||||
new Text('BOTTOM')
|
||||
],
|
||||
alignItems: FlexAlignItems.stretch,
|
||||
direction: FlexDirection.vertical
|
||||
)
|
||||
)
|
||||
)
|
||||
],
|
||||
direction: FlexDirection.horizontal
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
main() async {
|
||||
TestRenderView renderViewOverride = new TestRenderView();
|
||||
TestApp app = new TestApp();
|
||||
runApp(app, renderViewOverride: renderViewOverride);
|
||||
await renderViewOverride.checkFrame();
|
||||
renderViewOverride.endTest();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user