Commit 400f118d authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Improve the Flex overflow marker style (#11723)

* Improve the Flex overflow marker style

* Update basic.dart
parent 1c372c68
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'dart:math' as math;
import 'dart:ui' as ui;
import 'box.dart';
import 'object.dart';
......@@ -933,6 +934,17 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
return defaultHitTestChildren(result, position: position);
}
static const Color _black = const Color(0xBF000000);
static const Color _yellow = const Color(0xBFFFFF00);
static const double _kMarkerSize = 0.1;
static const TextStyle _debugMarkerTextStyle = const TextStyle(
color: const Color(0xFF900000),
fontSize: 7.5,
fontWeight: FontWeight.w800,
);
static Paint _debugMarkerPaint;
TextPainter _debugMarkerLabel;
@override
void paint(PaintingContext context, Offset offset) {
if (_overflow <= 0.0) {
......@@ -944,34 +956,65 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
context.pushClipRect(needsCompositing, offset, Offset.zero & size, defaultPaint);
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).
final Paint markerPaint = new Paint()..color = const Color(0xE0FF0000);
final Paint highlightPaint = new Paint()..color = const Color(0x7FFF0000);
const double kMarkerSize = 0.1;
Rect markerRect, overflowRect;
switch(direction) {
// In debug mode, if you have overflow, we highlight where the overflow
// would be by painting the edge of that area with a yellow and black
// striped bar.
_debugMarkerPaint ??= new Paint()
..shader = new ui.Gradient.linear(
const Offset(0.0, 0.0),
const Offset(10.0, 10.0),
<Color>[_black, _yellow, _yellow, _black],
<double>[0.25, 0.25, 0.75, 0.75],
TileMode.repeated,
);
String pixels;
if (_overflow > 10.0) {
pixels = _overflow.toStringAsFixed(0);
} else if (_overflow > 1.0) {
pixels = _overflow.toStringAsFixed(1);
} else {
pixels = _overflow.toStringAsPrecision(3);
}
String label;
Rect markerRect;
switch (direction) {
case Axis.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);
markerRect = offset + new Offset(size.width * (1.0 - _kMarkerSize), 0.0) &
new Size(size.width * _kMarkerSize, size.height);
label = 'ROW OVERFLOWED BY $pixels PIXELS';
break;
case Axis.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);
markerRect = offset + new Offset(0.0, size.height * (1.0 - _kMarkerSize)) &
new Size(size.width, size.height * _kMarkerSize);
label = 'COLUMN OVERFLOWED BY $pixels PIXELS';
break;
}
context.canvas.drawRect(markerRect, markerPaint);
context.canvas.drawRect(overflowRect, highlightPaint);
context.canvas.drawRect(markerRect, _debugMarkerPaint);
_debugMarkerLabel ??= new TextPainter();
_debugMarkerLabel.text = new TextSpan( // this is a no-op if the label hasn't changed
text: label,
style: _debugMarkerTextStyle,
);
_debugMarkerLabel.layout(); // this is a no-op if the label hasn't changed
// TODO(ianh): RTL support
switch (direction) {
case Axis.horizontal:
context.canvas.save();
final Offset offset = markerRect.centerRight;
context.canvas.translate(offset.dx, offset.dy);
context.canvas.rotate(-math.PI / 2.0);
_debugMarkerLabel.paint(context.canvas, new Offset(-_debugMarkerLabel.width / 2.0, 0.0));
context.canvas.restore();
break;
case Axis.vertical:
_debugMarkerLabel.paint(context.canvas, markerRect.bottomCenter - new Offset(_debugMarkerLabel.width / 2.0, 0.0));
break;
}
return true;
});
}
......
......@@ -2916,12 +2916,15 @@ class Flex extends MultiChildRenderObjectWidget {
///
/// ## Troubleshooting
///
/// ### Why is my row turning red?
/// ### Why does my row have a yellow and black warning stripe?
///
/// If the contents of the row overflow, meaning that together they are wider
/// than the row, then the row runs out of space to give its [Expanded] and
/// [Flexible] children, and reports this by drawing a red warning box on the
/// edge that is overflowing.
/// If the non-flexible contents of the row (those that are not wrapped in
/// [Expanded] or [Flexible] widgets) are together wider than the row itself,
/// then the row is said to have overflowed. When a row overflows, the row does
/// not have any remaining space to share between its [Expanded] and [Flexible]
/// children. The row reports this by drawing a yellow and black striped
/// warning box on the edge that is overflowing. If there is room on the outside
/// of the row, the amount of overflow is printed in red lettering.
///
/// #### Story time
///
......@@ -2947,7 +2950,7 @@ class Flex extends MultiChildRenderObjectWidget {
/// be thiiiiiiiiiiiiiiiiiiiis wide.", and goes well beyond the space that the
/// row has available, not wrapping. The row responds, "That's not fair, now I
/// have no more room available for my other children!", and gets angry and
/// turns red.
/// sprouts a yellow and black strip.
///
/// The fix is to wrap the second child in an [Expanded] widget, which tells the
/// row that the child should be given the remaining room:
......@@ -3109,6 +3112,58 @@ class Row extends Flex {
/// )
/// ```
///
/// ## Troubleshooting
///
/// ### When the incoming vertical constraints are unbounded
///
/// When a [Column] has one or more [Expanded] or [Flexible] children, and is
/// placed in another [Column], or in a [ListView], or in some other context
/// that does not provide a maximum height constraint for the [Column], you will
/// get an exception at runtime saying that there are children with non-zero
/// flex but the vertical constraints are unbounded.
///
/// The problem, as described in the details that accompany that exception, is
/// that using [Flexible] or [Expanded] means that the remaining space after
/// laying out all the other children must be shared equally, but if the
/// incoming vertical constraints are unbounded, there is infinite remaining
/// space.
///
/// The key to solving this problem is usually to determine why the [Column] is
/// receiving unbounded vertical constraints.
///
/// One common reason for this to happen is that the [Column] has been placed in
/// another [Column] (without using [Expanded] or [Flexible] around the inner
/// nested [Column]). When a [Column] lays out its non-flex children (those that
/// have neither [Expanded] or [Flexible] around them), it gives them unbounded
/// constraints so that they can determine their own dimensions (passing
/// unbounded constraints usually signals to the child that it should
/// shrink-wrap its contents). The solution in this case is typically to just
/// wrap the inner column in an [Expanded] to indicate that it should take the
/// remaining space of the outer column, rather than being allowed to take any
/// amount of room it desires.
///
/// Another reason for this message to be displayed is nesting a [Column] inside
/// a [ListView] or other vertical scrollable. In that scenario, there really is
/// infinite vertical space (the whole point of a vertical scrolling list is to
/// allow infinite space vertically). In such scenarios, it is usually worth
/// examining why the inner [Column] should have an [Expanded] or [Flexible]
/// child: what size should the inner children really be? The solution in this
/// case is typically to remove the [Expanded] or [Flexible] widgets from around
/// the inner children.
///
/// For more discussion about constraints, see [BoxConstraints].
///
/// ### The yellow and black striped banner
///
/// When the contents of a [Column] exceed the amount of space available, the
/// [Column] overflows, and the contents are clipped. In debug mode, a yellow
/// and black striped bar is rendered at the overflowing edge to indicate the
/// problem, and a message is printed below the [Column] saying how much
/// overflow was detected.
///
/// The usual solution is to use a [ListView] rather than a [Column], to enable
/// the contents to scroll when vertical space is limited.
///
/// ## Layout algorithm
///
/// _This section describes how a [Column] is rendered by the framework._
......
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