mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Improve debugging output
Teach dumpRenderTree() to draw actual trees. Make the TextStyle output terser so it doesn't overflow the output. Make debugDumpApp() say what mode we're in (checked vs release). Hide lifecycle state from release mode dumps (since it's checked-only state).
This commit is contained in:
parent
6e91cfa49a
commit
1f40d96fbf
@ -11,6 +11,7 @@ import 'dart:ui' as ui;
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
import 'stock_data.dart';
|
||||
|
||||
|
@ -112,7 +112,7 @@ class StockHomeState extends State<StockHome> {
|
||||
),
|
||||
new DrawerItem(
|
||||
icon: 'device/dvr',
|
||||
onPressed: () { debugDumpApp(); },
|
||||
onPressed: () { debugDumpApp(); debugDumpRenderTree(); },
|
||||
child: new Text('Dump App to Console')
|
||||
),
|
||||
new DrawerDivider(),
|
||||
|
@ -252,25 +252,131 @@ class TextStyle {
|
||||
List<String> result = <String>[];
|
||||
if (color != null)
|
||||
result.add('${prefix}color: $color');
|
||||
// TODO(hansmuller): escape the fontFamily string.
|
||||
if (fontFamily != null)
|
||||
result.add('${prefix}fontFamily: "$fontFamily"');
|
||||
result.add('${prefix}family: "$fontFamily"');
|
||||
if (fontSize != null)
|
||||
result.add('${prefix}fontSize: $fontSize');
|
||||
if (fontWeight != null)
|
||||
result.add('${prefix}fontWeight: $fontWeight');
|
||||
if (fontStyle != null)
|
||||
result.add('${prefix}fontStyle: $fontStyle');
|
||||
if (textAlign != null)
|
||||
result.add('${prefix}textAlign: $textAlign');
|
||||
if (textBaseline != null)
|
||||
result.add('${prefix}textBaseline: $textBaseline');
|
||||
if (decoration != null)
|
||||
result.add('${prefix}decoration: $decoration');
|
||||
if (decorationColor != null)
|
||||
result.add('${prefix}decorationColor: $decorationColor');
|
||||
if (decorationStyle != null)
|
||||
result.add('${prefix}decorationStyle: $decorationStyle');
|
||||
result.add('${prefix}size: $fontSize');
|
||||
if (fontWeight != null) {
|
||||
switch (fontWeight) {
|
||||
case FontWeight.w100:
|
||||
result.add('${prefix}weight: 100');
|
||||
break;
|
||||
case FontWeight.w200:
|
||||
result.add('${prefix}weight: 200');
|
||||
break;
|
||||
case FontWeight.w300:
|
||||
result.add('${prefix}weight: 300');
|
||||
break;
|
||||
case FontWeight.w400:
|
||||
result.add('${prefix}weight: 400');
|
||||
break;
|
||||
case FontWeight.w500:
|
||||
result.add('${prefix}weight: 500');
|
||||
break;
|
||||
case FontWeight.w600:
|
||||
result.add('${prefix}weight: 600');
|
||||
break;
|
||||
case FontWeight.w700:
|
||||
result.add('${prefix}weight: 700');
|
||||
break;
|
||||
case FontWeight.w800:
|
||||
result.add('${prefix}weight: 800');
|
||||
break;
|
||||
case FontWeight.w900:
|
||||
result.add('${prefix}weight: 900');
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fontStyle != null) {
|
||||
switch (fontStyle) {
|
||||
case FontStyle.normal:
|
||||
result.add('${prefix}style: normal');
|
||||
break;
|
||||
case FontStyle.italic:
|
||||
result.add('${prefix}style: italic');
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (textAlign != null) {
|
||||
switch (textAlign) {
|
||||
case TextAlign.left:
|
||||
result.add('${prefix}align: left');
|
||||
break;
|
||||
case TextAlign.right:
|
||||
result.add('${prefix}align: right');
|
||||
break;
|
||||
case TextAlign.center:
|
||||
result.add('${prefix}align: center');
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (textBaseline != null) {
|
||||
switch (textBaseline) {
|
||||
case TextBaseline.alphabetic:
|
||||
result.add('${prefix}baseline: alphabetic');
|
||||
break;
|
||||
case TextBaseline.ideographic:
|
||||
result.add('${prefix}baseline: ideographic');
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (decoration != null || decorationColor != null || decorationStyle != null) {
|
||||
String decorationDescription = '${prefix}decoration: ';
|
||||
bool haveDecorationDescription = false;
|
||||
if (decorationStyle != null) {
|
||||
switch (decorationStyle) {
|
||||
case TextDecorationStyle.solid:
|
||||
decorationDescription += 'solid';
|
||||
break;
|
||||
case TextDecorationStyle.double:
|
||||
decorationDescription += 'double';
|
||||
break;
|
||||
case TextDecorationStyle.dotted:
|
||||
decorationDescription += 'dotted';
|
||||
break;
|
||||
case TextDecorationStyle.dashed:
|
||||
decorationDescription += 'dashed';
|
||||
break;
|
||||
case TextDecorationStyle.wavy:
|
||||
decorationDescription += 'wavy';
|
||||
break;
|
||||
}
|
||||
haveDecorationDescription = true;
|
||||
}
|
||||
if (decorationColor != null) {
|
||||
if (haveDecorationDescription)
|
||||
decorationDescription += ' ';
|
||||
decorationDescription += '$decorationColor';
|
||||
haveDecorationDescription = true;
|
||||
}
|
||||
if (decoration != null) {
|
||||
if (haveDecorationDescription)
|
||||
decorationDescription += ' ';
|
||||
bool multipleDecorations = false;
|
||||
for (TextDecoration value in decoration) {
|
||||
if (multipleDecorations)
|
||||
decorationDescription += '+';
|
||||
switch (value) {
|
||||
case TextDecoration.none:
|
||||
decorationDescription += 'none';
|
||||
break;
|
||||
case TextDecoration.underline:
|
||||
decorationDescription += 'underline';
|
||||
break;
|
||||
case TextDecoration.overline:
|
||||
decorationDescription += 'overline';
|
||||
break;
|
||||
case TextDecoration.lineThrough:
|
||||
decorationDescription += 'line-through';
|
||||
break;
|
||||
}
|
||||
multipleDecorations = true;
|
||||
}
|
||||
haveDecorationDescription = true;
|
||||
}
|
||||
assert(haveDecorationDescription);
|
||||
result.add(decorationDescription);
|
||||
}
|
||||
if (result.isEmpty)
|
||||
return '$prefix<no style specified>';
|
||||
return result.join('\n');
|
||||
|
@ -1139,11 +1139,18 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
/// Returns a description of the tree rooted at this node.
|
||||
/// If the prefix argument is provided, then every line in the output
|
||||
/// will be prefixed by that string.
|
||||
String toStringDeep([String prefix = '']) {
|
||||
String toStringDeep([String prefixLineOne = '', String prefixOtherLines = '']) {
|
||||
RenderObject debugPreviousActiveLayout = _debugActiveLayout;
|
||||
_debugActiveLayout = null;
|
||||
prefix += ' ';
|
||||
String result = '$this\n${debugDescribeSettings(prefix)}${debugDescribeChildren(prefix)}';
|
||||
String result = '$prefixLineOne$this\n';
|
||||
final String childrenDescription = debugDescribeChildren(prefixOtherLines);
|
||||
final String settingsPrefix = childrenDescription != '' ? '$prefixOtherLines \u2502 ' : '$prefixOtherLines ';
|
||||
result += debugDescribeSettings(settingsPrefix);
|
||||
if (childrenDescription != '')
|
||||
result += '$prefixOtherLines \u2502\n';
|
||||
else
|
||||
result += '$prefixOtherLines\n';
|
||||
result += childrenDescription;
|
||||
_debugActiveLayout = debugPreviousActiveLayout;
|
||||
return result;
|
||||
}
|
||||
@ -1198,7 +1205,7 @@ abstract class RenderObjectWithChildMixin<ChildType extends RenderObject> implem
|
||||
}
|
||||
String debugDescribeChildren(String prefix) {
|
||||
if (child != null)
|
||||
return '${prefix}child: ${child.toStringDeep(prefix)}';
|
||||
return '${child.toStringDeep("$prefix \u2514\u2500child: ", "$prefix ")}';
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@ -1442,14 +1449,20 @@ abstract class ContainerRenderObjectMixin<ChildType extends RenderObject, Parent
|
||||
|
||||
String debugDescribeChildren(String prefix) {
|
||||
String result = '';
|
||||
int count = 1;
|
||||
if (_firstChild != null) {
|
||||
ChildType child = _firstChild;
|
||||
while (child != null) {
|
||||
result += '${prefix}child $count: ${child.toStringDeep(prefix)}';
|
||||
int count = 1;
|
||||
while (child != _lastChild) {
|
||||
result += '${child.toStringDeep("$prefix \u251C\u2500child $count: ", "$prefix \u2502")}';
|
||||
count += 1;
|
||||
final ParentDataType childParentData = child.parentData;
|
||||
child = childParentData.nextSibling;
|
||||
}
|
||||
if (child != null) {
|
||||
assert(child == _lastChild);
|
||||
result += '${child.toStringDeep("$prefix \u2514\u2500child $count: ", "$prefix ")}';
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -883,6 +883,7 @@ class FractionalOffset {
|
||||
value = 37 * value + y.hashCode;
|
||||
return value;
|
||||
}
|
||||
String toString() => '$runtimeType($x, $y)';
|
||||
}
|
||||
|
||||
/// Applies a transformation before painting its child
|
||||
@ -1016,7 +1017,7 @@ class RenderTransform extends RenderProxyBox {
|
||||
String debugDescribeSettings(String prefix) {
|
||||
List<String> result = _transform.toString().split('\n').map((String s) => '$prefix $s\n').toList();
|
||||
result.removeLast();
|
||||
return '${super.debugDescribeSettings(prefix)}${prefix}transform matrix:\n${result.join()}\n${prefix}origin: $origin\n';
|
||||
return '${super.debugDescribeSettings(prefix)}${prefix}transform matrix:\n${result.join()}\n${prefix}origin: $origin\nalignment: $alignment\n';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,9 @@ void runApp(Widget app) {
|
||||
void debugDumpApp() {
|
||||
assert(WidgetFlutterBinding.instance != null);
|
||||
assert(WidgetFlutterBinding.instance.renderViewElement != null);
|
||||
String mode = 'RELEASE MODE';
|
||||
assert(() { mode = 'CHECKED MODE'; return true; });
|
||||
print('${WidgetFlutterBinding.instance.runtimeType} - $mode');
|
||||
WidgetFlutterBinding.instance.renderViewElement.toStringDeep().split('\n').forEach(print);
|
||||
}
|
||||
|
||||
|
@ -394,8 +394,11 @@ abstract class State<T extends StatefulComponent> {
|
||||
|
||||
void debugFillDescription(List<String> description) {
|
||||
description.add('$hashCode');
|
||||
assert(() {
|
||||
if (_debugLifecycleState != _StateLifecycle.ready)
|
||||
description.add('$_debugLifecycleState');
|
||||
return true;
|
||||
});
|
||||
if (_config == null)
|
||||
description.add('no config');
|
||||
if (_element == null)
|
||||
@ -829,9 +832,7 @@ abstract class Element<T extends Widget> implements BuildContext {
|
||||
String toStringDeep([String prefixLineOne = '', String prefixOtherLines = '']) {
|
||||
String result = '$prefixLineOne$this\n';
|
||||
List<Element> children = <Element>[];
|
||||
visitChildren((Element child) {
|
||||
children.add(child);
|
||||
});
|
||||
visitChildren(children.add);
|
||||
if (children.length > 0) {
|
||||
Element last = children.removeLast();
|
||||
for (Element child in children)
|
||||
|
Loading…
Reference in New Issue
Block a user