从代码调试 Flutter 应用
如何从你的代码和命令行启用各种调试工具。
本指南介绍了可以在代码中启用的调试功能。有关完整的调试和分析工具列表,请查看 调试 页面。
在你的应用程序中添加日志记录
#以下列表包含一些可用于记录应用程序行为的语句。你可以在 DevTools 的 日志视图 或系统控制台中查看你的日志。
-
print():打印一个stdout(标准输出)消息。是dart:io库的一部分。 -
stderr.method_to_invoke():打印一个stderr(标准错误)消息。将method_to_invoke()替换为stderr属性支持的方法,例如writeln()或write()。通常在try...catch块中使用。是dart:io库的一部分。dartstderr.writeln('print me'); -
log():包含更精细的粒度和更多信息在日志输出中。是dart:developer库的一部分。 -
debugPrint():如果过多的输出导致日志行被丢弃,请使用此方法来保留这些行。除非是调试模式检查或断言的一部分,否则将在发布模式下打印消息。是foundations库的一部分。
示例 1
#import 'dart:developer' as developer;
void main() {
developer.log('log me', name: 'my.app.category');
developer.log('log me 1', name: 'my.other.category');
developer.log('log me 2', name: 'my.other.category');
}
你还可以将应用程序数据传递给日志调用。为此的约定是在 log() 调用中使用 error: 命名参数,将要发送的对象 JSON 编码,并将编码后的字符串传递给 error 参数。
示例 2
#import 'dart:convert';
import 'dart:developer' as developer;
void main() {
var myCustomObject = MyCustomObject();
developer.log(
'log me',
name: 'my.app.category',
error: jsonEncode(myCustomObject),
);
}
DevTool 的日志视图将 JSON 编码的 error 参数解释为数据对象。DevTool 在该日志条目的详细信息视图中进行渲染。
设置断点
#你可以在 DevTools 的 调试器 或 IDE 的内置调试器中设置断点。
要设置程序化断点
将
dart:developer包导入到相关文件中。-
使用
debugger()语句插入程序化断点。该语句接受一个可选的when参数。此布尔参数在给定的条件解析为 true 时设置断点。示例 3 说明了这一点。
示例 3
#import 'dart:developer';
void someFunction(double offset) {
debugger(when: offset > 30);
// ...
}
使用标志调试应用层
#Flutter 框架的每一层都提供了一个函数,用于使用 debugPrint 属性将当前状态或事件转储到控制台。
打印小部件树
#要转储 Widgets 库的状态,请调用 debugDumpApp() 函数。
- 打开你的源文件。
- 导入
package:flutter/rendering.dart。 - 从
runApp()函数中调用debugDumpApp()函数。你需要将你的应用置于调试模式下。你不能在应用构建时在build()方法中调用此函数。 - 如果你尚未启动你的应用,请使用你的 IDE 进行调试。
- 如果你已经启动了你的应用,请保存你的源文件。热重载会重新渲染你的应用。
示例 4:调用 debugDumpApp()
#
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: AppHome()));
}
class AppHome extends StatelessWidget {
const AppHome({super.key});
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: TextButton(
onPressed: () {
debugDumpApp();
},
child: const Text('Dump Widget Tree'),
),
),
);
}
}
此函数从小部件树的根开始递归调用 toStringDeep() 方法。它返回一个“扁平化”的树。
示例 4 生成以下小部件树。它包括
通过各种构建函数投影的所有小部件。
-
许多未出现在你的应用源代码中的小部件。框架的小部件的构建函数在构建期间插入它们。
以下树,例如,显示了
_InkFeatures。该类实现了Material小部件的一部分。它未出现在 示例 4 中的任何代码中。
展开以查看示例 4 的小部件树
flutter: WidgetsFlutterBinding - DEBUG MODE
flutter: [root](renderObject: RenderView#06beb)
flutter: └View-[GlobalObjectKey FlutterView#7971c]
flutter: └_ViewScope
flutter: └_MediaQueryFromView(state: _MediaQueryFromViewState#d790c)
flutter: └MediaQuery(MediaQueryData(size: Size(800.0, 600.0), devicePixelRatio: 1.0, textScaleFactor: 1.0, platformBrightness: Brightness.dark, padding: EdgeInsets.zero, viewPadding: EdgeInsets.zero, viewInsets: EdgeInsets.zero, systemGestureInsets: EdgeInsets.zero, alwaysUse24HourFormat: false, accessibleNavigation: false, highContrast: false, disableAnimations: false, invertColors: false, boldText: false, navigationMode: traditional, gestureSettings: DeviceGestureSettings(touchSlop: null), displayFeatures: []))
flutter: └MaterialApp(state: _MaterialAppState#27fa9)
flutter: └ScrollConfiguration(behavior: MaterialScrollBehavior)
flutter: └HeroControllerScope
flutter: └Focus(state: _FocusState#d7f97)
flutter: └_FocusInheritedScope
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#a6464)
flutter: └WidgetsApp-[GlobalObjectKey _MaterialAppState#27fa9](state: _WidgetsAppState#b5b17)
flutter: └RootRestorationScope(state: _RootRestorationScopeState#6b028)
flutter: └UnmanagedRestorationScope
flutter: └RestorationScope(dependencies: [UnmanagedRestorationScope], state: _RestorationScopeState#d1369)
flutter: └UnmanagedRestorationScope
flutter: └SharedAppData(state: _SharedAppDataState#95e82)
flutter: └_SharedAppModel
flutter: └Shortcuts(shortcuts: <Default WidgetsApp Shortcuts>, state: _ShortcutsState#272dc)
flutter: └Focus(debugLabel: "Shortcuts", dependencies: [_FocusInheritedScope], state: _FocusState#a3300)
flutter: └_FocusInheritedScope
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#db110)
flutter: └DefaultTextEditingShortcuts
flutter: └Shortcuts(shortcuts: <Default Text Editing Shortcuts>, state: _ShortcutsState#1d796)
flutter: └Focus(debugLabel: "Shortcuts", dependencies: [_FocusInheritedScope], state: _FocusState#0081b)
flutter: └_FocusInheritedScope
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#0d70e)
flutter: └Shortcuts(shortcuts: <Web Disabling Text Editing Shortcuts>, state: _ShortcutsState#56bac)
flutter: └Focus(debugLabel: "Shortcuts", dependencies: [_FocusInheritedScope], state: _FocusState#3152e)
flutter: └_FocusInheritedScope
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#b7eaf)
flutter: └Actions(dispatcher: null, actions: {DoNothingIntent: DoNothingAction#0fda1, DoNothingAndStopPropagationIntent: DoNothingAction#17f30, RequestFocusIntent: RequestFocusAction#10bd0, NextFocusIntent: NextFocusAction#60317, PreviousFocusIntent: PreviousFocusAction#2a933, DirectionalFocusIntent: DirectionalFocusAction#a6922, ScrollIntent: _OverridableContextAction<ScrollIntent>#964fe(defaultAction: ScrollAction#ffb50), PrioritizedIntents: PrioritizedAction#be0e2, VoidCallbackIntent: VoidCallbackAction#805fa}, state: _ActionsState#bbd25)
flutter: └_ActionsScope
flutter: └FocusTraversalGroup(policy: ReadingOrderTraversalPolicy#f1e76, state: _FocusTraversalGroupState#0c200)
flutter: └Focus(debugLabel: "FocusTraversalGroup", focusNode: _FocusTraversalGroupNode#ffcad(FocusTraversalGroup [IN FOCUS PATH]), dependencies: [_FocusInheritedScope], state: _FocusState#c7dc2)
flutter: └_FocusInheritedScope
flutter: └TapRegionSurface(renderObject: RenderTapRegionSurface#17aba)
flutter: └ShortcutRegistrar(state: _ShortcutRegistrarState#44954)
flutter: └_ShortcutRegistrarScope
flutter: └Shortcuts(manager: ShortcutManager#eb38c(shortcuts: {}), shortcuts: {}, state: _ShortcutsState#f85ac)
flutter: └Focus(debugLabel: "Shortcuts", dependencies: [_FocusInheritedScope], state: _FocusState#8c1a7)
flutter: └_FocusInheritedScope
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#1fc98)
flutter: └Localizations(locale: en_US, delegates: [DefaultMaterialLocalizations.delegate(en_US), DefaultCupertinoLocalizations.delegate(en_US), DefaultWidgetsLocalizations.delegate(en_US)], state: _LocalizationsState#ae3a0)
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, textDirection: ltr, renderObject: RenderSemanticsAnnotations#8776e)
flutter: └_LocalizationsScope-[GlobalKey#61ca6]
flutter: └Directionality(textDirection: ltr)
flutter: └Title(color: Color(0xff2196f3))
flutter: └CheckedModeBanner("DEBUG")
flutter: └Banner("DEBUG", textDirection: ltr, location: topEnd, Color(0xa0b71c1c), text inherit: true, text color: Color(0xffffffff), text size: 10.2, text weight: 900, text height: 1.0x, dependencies: [Directionality])
flutter: └CustomPaint(renderObject: RenderCustomPaint#c014d)
flutter: └DefaultTextStyle(debugLabel: fallback style; consider putting your text in a Material, inherit: true, color: Color(0xd0ff0000), family: monospace, size: 48.0, weight: 900, decoration: double Color(0xffffff00) TextDecoration.underline, softWrap: wrapping at box width, overflow: clip)
flutter: └Builder(dependencies: [MediaQuery])
flutter: └ScaffoldMessenger(dependencies: [MediaQuery], state: ScaffoldMessengerState#5b36e)
flutter: └_ScaffoldMessengerScope
flutter: └DefaultSelectionStyle
flutter: └AnimatedTheme(duration: 200ms, state: _AnimatedThemeState#cd149(ticker inactive, ThemeDataTween(ThemeData#ef3b2 → ThemeData#ef3b2)))
flutter: └Theme(ThemeData#ef3b2, dependencies: [DefaultSelectionStyle])
flutter: └_InheritedTheme
flutter: └CupertinoTheme(brightness: light, primaryColor: MaterialColor(primary value: Color(0xff2196f3)), primaryContrastingColor: Color(0xffffffff), scaffoldBackgroundColor: Color(0xfffafafa), actionTextStyle: TextStyle(inherit: false, color: MaterialColor(primary value: Color(0xff2196f3)), family: .SF Pro Text, size: 17.0, letterSpacing: -0.4, decoration: TextDecoration.none), navActionTextStyle: TextStyle(inherit: false, color: MaterialColor(primary value: Color(0xff2196f3)), family: .SF Pro Text, size: 17.0, letterSpacing: -0.4, decoration: TextDecoration.none))
flutter: └_InheritedCupertinoTheme
flutter: └IconTheme(color: MaterialColor(primary value: Color(0xff2196f3)))
flutter: └IconTheme(color: Color(0xdd000000))
flutter: └DefaultSelectionStyle
flutter: └FocusScope(debugLabel: "Navigator Scope", AUTOFOCUS, dependencies: [_FocusInheritedScope], state: _FocusScopeState#acbd8)
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#ab3f0)
flutter: └_FocusInheritedScope
flutter: └Navigator-[GlobalObjectKey<NavigatorState> _WidgetsAppState#b5b17](dependencies: [HeroControllerScope, UnmanagedRestorationScope], state: NavigatorState#1395a(tickers: tracking 1 ticker))
flutter: └HeroControllerScope
flutter: └Listener(listeners: [down, up, cancel], behavior: deferToChild, renderObject: RenderPointerListener#34172)
flutter: └AbsorbPointer(absorbing: false, renderObject: RenderAbsorbPointer#f8711)
flutter: └FocusTraversalGroup(policy: ReadingOrderTraversalPolicy#f1e76, state: _FocusTraversalGroupState#8d61a)
flutter: └Focus(debugLabel: "FocusTraversalGroup", focusNode: _FocusTraversalGroupNode#dd2b1(FocusTraversalGroup [IN FOCUS PATH]), dependencies: [_FocusInheritedScope], state: _FocusState#0bb03)
flutter: └_FocusInheritedScope
flutter: └Focus(debugLabel: "Navigator", AUTOFOCUS, focusNode: FocusNode#a3309(Navigator [IN FOCUS PATH]), dependencies: [_FocusInheritedScope], state: _FocusState#d3d07)
flutter: └_FocusInheritedScope
flutter: └UnmanagedRestorationScope
flutter: └Overlay-[LabeledGlobalKey<OverlayState>#5485a](state: OverlayState#5bd52(entries: [OverlayEntry#fc947(opaque: true; maintainState: false), OverlayEntry#05a32(opaque: false; maintainState: true)]))
flutter: └_Theater(skipCount: 0, dependencies: [Directionality], renderObject: _RenderTheater#e86c3)
flutter: ├_OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#1b37e](state: _OverlayEntryWidgetState#06ab0)
flutter: │└TickerMode(state: _TickerModeState#0b4ac(requested mode: enabled))
flutter: │ └_EffectiveTickerMode(effective mode: enabled)
flutter: │ └_RenderTheaterMarker
flutter: │ └IgnorePointer(ignoring: false, renderObject: RenderIgnorePointer#34c66)
flutter: │ └ModalBarrier
flutter: │ └BlockSemantics(blocking: true, renderObject: RenderBlockSemantics#97799)
flutter: │ └ExcludeSemantics(excluding: true, renderObject: RenderExcludeSemantics#8c4ce)
flutter: │ └_ModalBarrierGestureDetector
flutter: │ └RawGestureDetector(state: RawGestureDetectorState#556f6(gestures: [any tap], behavior: opaque))
flutter: │ └_GestureSemantics(renderObject: RenderSemanticsGestureHandler#616f1)
flutter: │ └Listener(listeners: [down, panZoomStart], behavior: opaque, renderObject: RenderPointerListener#c2b89)
flutter: │ └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#c3b31)
flutter: │ └MouseRegion(listeners: <none>, cursor: SystemMouseCursor(basic), renderObject: RenderMouseRegion#53cdb)
flutter: │ └ConstrainedBox(BoxConstraints(biggest), renderObject: RenderConstrainedBox#faa51)
flutter: └_OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#bc0aa](state: _OverlayEntryWidgetState#cbf35)
flutter: └TickerMode(state: _TickerModeState#23e73(requested mode: enabled))
flutter: └_EffectiveTickerMode(effective mode: enabled)
flutter: └_RenderTheaterMarker
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, sortKey: OrdinalSortKey#135f4(order: 0.0), renderObject: RenderSemanticsAnnotations#5565e)
flutter: └_ModalScope<dynamic>-[LabeledGlobalKey<_ModalScopeState<dynamic>>#4fe82](state: _ModalScopeState<dynamic>#4da7d)
flutter: └AnimatedBuilder(listenable: ValueNotifier<String?>#d87c6(null), state: _AnimatedState#dde81)
flutter: └RestorationScope(dependencies: [UnmanagedRestorationScope], state: _RestorationScopeState#78c51)
flutter: └UnmanagedRestorationScope
flutter: └_ModalScopeStatus(active)
flutter: └Offstage(offstage: false, renderObject: RenderOffstage#5e498)
flutter: └PageStorage
flutter: └Builder
flutter: └Actions(dispatcher: null, actions: {DismissIntent: _DismissModalAction#6279e}, state: _ActionsState#48019)
flutter: └_ActionsScope
flutter: └PrimaryScrollController(ScrollController#6a546(no clients))
flutter: └FocusScope(debugLabel: "_ModalScopeState<dynamic> Focus Scope", focusNode: FocusScopeNode#0e2af(_ModalScopeState<dynamic> Focus Scope [PRIMARY FOCUS]), dependencies: [_FocusInheritedScope], state: _FocusScopeState#0bac4)
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#44b4e)
flutter: └_FocusInheritedScope
flutter: └RepaintBoundary(renderObject: RenderRepaintBoundary#38f41)
flutter: └AnimatedBuilder(listenable: Listenable.merge([AnimationController#9d623(⏭ 1.000; paused; for MaterialPageRoute<dynamic>(/))➩ProxyAnimation, kAlwaysDismissedAnimation➩ProxyAnimation➩ProxyAnimation]), dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#61ca6]], state: _AnimatedState#47725)
flutter: └CupertinoPageTransition(dependencies: [Directionality])
flutter: └SlideTransition(listenable: kAlwaysDismissedAnimation➩ProxyAnimation➩ProxyAnimation➩Cubic(0.35, 0.91, 0.33, 0.97)ₒₙ/Cubic(0.67, 0.03, 0.65, 0.09)➩Tween<Offset>(Offset(0.0, 0.0) → Offset(-0.3, 0.0))➩Offset(0.0, 0.0), state: _AnimatedState#b6162)
flutter: └FractionalTranslation(renderObject: RenderFractionalTranslation#fb461)
flutter: └SlideTransition(listenable: AnimationController#9d623(⏭ 1.000; paused; for MaterialPageRoute<dynamic>(/))➩ProxyAnimation➩ThreePointCubic ₒₙ/FlippedCurve(ThreePointCubic )➩Tween<Offset>(Offset(1.0, 0.0) → Offset(0.0, 0.0))➩Offset(0.0, 0.0), state: _AnimatedState#834bf)
flutter: └FractionalTranslation(renderObject: RenderFractionalTranslation#73ea4)
flutter: └DecoratedBoxTransition(listenable: AnimationController#9d623(⏭ 1.000; paused; for MaterialPageRoute<dynamic>(/))➩ProxyAnimation➩Cubic(0.35, 0.91, 0.33, 0.97)➩DecorationTween(_CupertinoEdgeShadowDecoration(colors: null) → _CupertinoEdgeShadowDecoration(colors: [Color(0x04000000), Color(0x00000000)]))➩_CupertinoEdgeShadowDecoration(colors: [Color(0x04000000), Color(0x00000000)]), state: _AnimatedState#a7fca)
flutter: └DecoratedBox(bg: _CupertinoEdgeShadowDecoration(colors: [Color(0x04000000), Color(0x00000000)]), dependencies: [Directionality, MediaQuery, _LocalizationsScope-[GlobalKey#61ca6]], renderObject: RenderDecoratedBox#9965c)
flutter: └_CupertinoBackGestureDetector<dynamic>(dependencies: [Directionality, MediaQuery], state: _CupertinoBackGestureDetectorState<dynamic>#ab8cd)
flutter: └Stack(alignment: AlignmentDirectional.topStart, fit: passthrough, dependencies: [Directionality], renderObject: RenderStack#b2b7c)
flutter: ├AnimatedBuilder(listenable: ValueNotifier<bool>#1a88e(false), state: _AnimatedState#6e33c)
flutter: │└IgnorePointer(ignoring: false, renderObject: RenderIgnorePointer#2b763)
flutter: │ └RepaintBoundary-[GlobalKey#628f4](renderObject: RenderRepaintBoundary#5a53b)
flutter: │ └Builder
flutter: │ └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#f8795)
flutter: │ └AppHome
flutter: │ └Material(type: canvas, dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#61ca6]], state: _MaterialState#7d183)
flutter: │ └AnimatedPhysicalModel(duration: 200ms, shape: rectangle, borderRadius: BorderRadius.zero, elevation: 0.0, color: Color(0xfffafafa), animateColor: false, shadowColor: Color(0xff000000), animateShadowColor: true, state: _AnimatedPhysicalModelState#d479e(ticker inactive))
flutter: │ └PhysicalModel(shape: rectangle, borderRadius: BorderRadius.zero, elevation: 0.0, color: Color(0xfffafafa), shadowColor: Color(0xff000000), renderObject: RenderPhysicalModel#c60b5)
flutter: │ └NotificationListener<LayoutChangedNotification>
flutter: │ └_InkFeatures-[GlobalKey#e9da0 ink renderer](renderObject: _RenderInkFeatures#d8e6d)
flutter: │ └AnimatedDefaultTextStyle(duration: 200ms, debugLabel: (englishLike bodyMedium 2014).merge(blackRedwoodCity bodyMedium), inherit: false, color: Color(0xdd000000), family: .AppleSystemUIFont, size: 14.0, weight: 400, baseline: alphabetic, decoration: TextDecoration.none, softWrap: wrapping at box width, overflow: clip, state: _AnimatedDefaultTextStyleState#12f43(ticker inactive))
flutter: │ └DefaultTextStyle(debugLabel: (englishLike bodyMedium 2014).merge(blackRedwoodCity bodyMedium), inherit: false, color: Color(0xdd000000), family: .AppleSystemUIFont, size: 14.0, weight: 400, baseline: alphabetic, decoration: TextDecoration.none, softWrap: wrapping at box width, overflow: clip)
flutter: │ └Center(alignment: Alignment.center, dependencies: [Directionality], renderObject: RenderPositionedBox#b088f)
flutter: │ └TextButton(dirty, dependencies: [MediaQuery, _InheritedTheme, _LocalizationsScope-[GlobalKey#61ca6]], state: _ButtonStyleState#687c9)
flutter: │ └Semantics(container: true, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#ca411 relayoutBoundary=up1)
flutter: │ └_InputPadding(renderObject: _RenderInputPadding#60ede relayoutBoundary=up2)
flutter: │ └ConstrainedBox(BoxConstraints(56.0<=w<=Infinity, 28.0<=h<=Infinity), renderObject: RenderConstrainedBox#34800 relayoutBoundary=up3)
flutter: │ └Material(type: button, color: Color(0x00000000), shadowColor: Color(0xff000000), textStyle.debugLabel: ((englishLike labelLarge 2014).merge(blackRedwoodCity labelLarge)).copyWith, textStyle.inherit: false, textStyle.color: MaterialColor(primary value: Color(0xff2196f3)), textStyle.family: .AppleSystemUIFont, textStyle.size: 14.0, textStyle.weight: 500, textStyle.baseline: alphabetic, textStyle.decoration: TextDecoration.none, shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(4.0)), dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#61ca6]], state: _MaterialState#50a4d(tickers: tracking 5 tickers))
flutter: │ └_MaterialInterior(duration: 200ms, shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(4.0)), elevation: 0.0, color: Color(0x00000000), shadowColor: Color(0xff000000), dependencies: [Directionality, _InheritedTheme, _LocalizationsScope-[GlobalKey#61ca6]], state: _MaterialInteriorState#d296d(ticker inactive))
flutter: │ └PhysicalShape(clipper: ShapeBorderClipper, elevation: 0.0, color: Color(0x00000000), shadowColor: Color(0xff000000), renderObject: RenderPhysicalShape#43df6 relayoutBoundary=up4)
flutter: │ └_ShapeBorderPaint(dependencies: [Directionality])
flutter: │ └CustomPaint(renderObject: RenderCustomPaint#c1a3c relayoutBoundary=up5)
flutter: │ └NotificationListener<LayoutChangedNotification>
flutter: │ └_InkFeatures-[GlobalKey#625bc ink renderer](renderObject: _RenderInkFeatures#54439 relayoutBoundary=up6)
flutter: │ └AnimatedDefaultTextStyle(duration: 200ms, debugLabel: ((englishLike labelLarge 2014).merge(blackRedwoodCity labelLarge)).copyWith, inherit: false, color: MaterialColor(primary value: Color(0xff2196f3)), family: .AppleSystemUIFont, size: 14.0, weight: 500, baseline: alphabetic, decoration: TextDecoration.none, softWrap: wrapping at box width, overflow: clip, state: _AnimatedDefaultTextStyleState#2f29d(ticker inactive))
flutter: │ └DefaultTextStyle(debugLabel: ((englishLike labelLarge 2014).merge(blackRedwoodCity labelLarge)).copyWith, inherit: false, color: MaterialColor(primary value: Color(0xff2196f3)), family: .AppleSystemUIFont, size: 14.0, weight: 500, baseline: alphabetic, decoration: TextDecoration.none, softWrap: wrapping at box width, overflow: clip)
flutter: │ └InkWell
flutter: │ └_InkResponseStateWidget(gestures: [tap], mouseCursor: ButtonStyleButton_MouseCursor, clipped to BoxShape.rectangle, dirty, dependencies: [Directionality, MediaQuery, _InheritedTheme, _LocalizationsScope-[GlobalKey#61ca6]], state: _InkResponseState#0b11d)
flutter: │ └_ParentInkResponseProvider
flutter: │ └Actions(dispatcher: null, actions: {ActivateIntent: CallbackAction<ActivateIntent>#018db, ButtonActivateIntent: CallbackAction<ButtonActivateIntent>#ef87a}, state: _ActionsState#a5eab)
flutter: │ └_ActionsScope
flutter: │ └Focus(dependencies: [_FocusInheritedScope], state: _FocusState#5a9de)
flutter: │ └_FocusInheritedScope
flutter: │ └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#8ac3e relayoutBoundary=up7)
flutter: │ └MouseRegion(listeners: [enter, exit], cursor: SystemMouseCursor(click), renderObject: RenderMouseRegion#13d4e relayoutBoundary=up8)
flutter: │ └Builder(dependencies: [DefaultSelectionStyle])
flutter: │ └DefaultSelectionStyle
flutter: │ └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#d99cc relayoutBoundary=up9)
flutter: │ └GestureDetector(startBehavior: start, dependencies: [MediaQuery])
flutter: │ └RawGestureDetector(state: RawGestureDetectorState#b8d93(gestures: [tap], excludeFromSemantics: true, behavior: opaque))
flutter: │ └Listener(listeners: [down, panZoomStart], behavior: opaque, renderObject: RenderPointerListener#a4c3b relayoutBoundary=up10)
flutter: │ └Builder(dependencies: [IconTheme])
flutter: │ └IconTheme(color: MaterialColor(primary value: Color(0xff2196f3)))
flutter: │ └Padding(padding: EdgeInsets(8.0, 0.0, 8.0, 0.0), dependencies: [Directionality], renderObject: RenderPadding#18a87 relayoutBoundary=up11)
flutter: │ └Align(alignment: Alignment.center, widthFactor: 1.0, heightFactor: 1.0, dependencies: [Directionality], renderObject: RenderPositionedBox#fb8a8 relayoutBoundary=up12)
flutter: │ └Text("Dump Widget Tree", dependencies: [DefaultSelectionStyle, DefaultTextStyle, MediaQuery])
flutter: │ └RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "Dump Widget Tree", dependencies: [Directionality, _LocalizationsScope-[GlobalKey#61ca6]], renderObject: RenderParagraph#d15aa relayoutBoundary=up13)
flutter: └PositionedDirectional(dependencies: [Directionality])
flutter: └Positioned(left: 0.0, top: 0.0, bottom: 0.0, width: 20.0)
flutter: └Listener(listeners: [down], behavior: translucent, renderObject: RenderPointerListener#d884c)
flutter:
flutter:
当按钮从按下状态变为释放状态时,这将调用 debugDumpApp() 函数。它也与 TextButton 对象调用 setState() 从而将其标记为脏状态相吻合。这就是 Flutter 标记特定对象为“脏”的原因。当你在查看小部件树时,查找类似于以下内容的行
└TextButton(dirty, dependencies: [MediaQuery, _InheritedTheme, _LocalizationsScope-[GlobalKey#5880d]], state: _ButtonStyleState#ab76e)
如果你编写自己的小部件,请重写 debugFillProperties() 方法以添加信息。将 DiagnosticsProperty 对象添加到该方法的参数,然后调用超类方法。toString 方法使用此函数来填充小部件的描述。
打印渲染树
#当调试布局问题时,Widgets 层的树可能缺乏细节。接下来的调试级别可能需要渲染树。要转储渲染树
- 打开你的源文件。
- 调用
debugDumpRenderTree()函数。你可以在任何时间调用它,但不要在布局或绘制阶段调用。考虑从 帧回调 或事件处理程序调用它。 - 如果你尚未启动你的应用,请使用你的 IDE 进行调试。
- 如果你已经启动了你的应用,请保存你的源文件。热重载会重新渲染你的应用。
示例 5:调用 debugDumpRenderTree()
#
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: AppHome()));
}
class AppHome extends StatelessWidget {
const AppHome({super.key});
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: TextButton(
onPressed: () {
debugDumpRenderTree();
},
child: const Text('Dump Render Tree'),
),
),
);
}
}
在调试布局问题时,查看 size 和 constraints 字段。约束从树向下流动,大小从树向上流动。
展开以查看示例 5 的渲染树
flutter: RenderView#02c80
flutter: │ debug mode enabled - macos
flutter: │ view size: Size(800.0, 600.0) (in physical pixels)
flutter: │ device pixel ratio: 1.0 (physical pixels per logical pixel)
flutter: │ configuration: Size(800.0, 600.0) at 1.0x (in logical pixels)
flutter: │
flutter: └─child: RenderSemanticsAnnotations#fe6b5
flutter: │ needs compositing
flutter: │ creator: Semantics ← _FocusInheritedScope ← Focus ←
flutter: │ HeroControllerScope ← ScrollConfiguration ← MaterialApp ←
flutter: │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←
flutter: │ View-[GlobalObjectKey FlutterView#6cffa] ← [root]
flutter: │ parentData: <none>
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │
flutter: └─child: RenderSemanticsAnnotations#6edef
flutter: │ needs compositing
flutter: │ creator: Semantics ← _FocusInheritedScope ← Focus ← Shortcuts ←
flutter: │ _SharedAppModel ← SharedAppData ← UnmanagedRestorationScope ←
flutter: │ RestorationScope ← UnmanagedRestorationScope ←
flutter: │ RootRestorationScope ← WidgetsApp-[GlobalObjectKey
flutter: │ _MaterialAppState#5c303] ← Semantics ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │
flutter: └─child: RenderSemanticsAnnotations#e8ce8
flutter: │ needs compositing
flutter: │ creator: Semantics ← _FocusInheritedScope ← Focus ← Shortcuts ←
flutter: │ DefaultTextEditingShortcuts ← Semantics ← _FocusInheritedScope
flutter: │ ← Focus ← Shortcuts ← _SharedAppModel ← SharedAppData ←
flutter: │ UnmanagedRestorationScope ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │
flutter: └─child: RenderSemanticsAnnotations#fc545
flutter: │ needs compositing
flutter: │ creator: Semantics ← _FocusInheritedScope ← Focus ← Shortcuts ←
flutter: │ Semantics ← _FocusInheritedScope ← Focus ← Shortcuts ←
flutter: │ DefaultTextEditingShortcuts ← Semantics ← _FocusInheritedScope
flutter: │ ← Focus ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │
flutter: └─child: RenderTapRegionSurface#ff857
flutter: │ needs compositing
flutter: │ creator: TapRegionSurface ← _FocusInheritedScope ← Focus ←
flutter: │ FocusTraversalGroup ← _ActionsScope ← Actions ← Semantics ←
flutter: │ _FocusInheritedScope ← Focus ← Shortcuts ← Semantics ←
flutter: │ _FocusInheritedScope ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │ behavior: deferToChild
flutter: │
flutter: └─child: RenderSemanticsAnnotations#fe316
flutter: │ needs compositing
flutter: │ creator: Semantics ← _FocusInheritedScope ← Focus ← Shortcuts ←
flutter: │ _ShortcutRegistrarScope ← ShortcutRegistrar ← TapRegionSurface
flutter: │ ← _FocusInheritedScope ← Focus ← FocusTraversalGroup ←
flutter: │ _ActionsScope ← Actions ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │
flutter: └─child: RenderSemanticsAnnotations#fa55c
flutter: │ needs compositing
flutter: │ creator: Semantics ← Localizations ← Semantics ←
flutter: │ _FocusInheritedScope ← Focus ← Shortcuts ←
flutter: │ _ShortcutRegistrarScope ← ShortcutRegistrar ← TapRegionSurface
flutter: │ ← _FocusInheritedScope ← Focus ← FocusTraversalGroup ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │
flutter: └─child: RenderCustomPaint#4b256
flutter: │ needs compositing
flutter: │ creator: CustomPaint ← Banner ← CheckedModeBanner ← Title ←
flutter: │ Directionality ← _LocalizationsScope-[GlobalKey#4a3aa] ←
flutter: │ Semantics ← Localizations ← Semantics ← _FocusInheritedScope ←
flutter: │ Focus ← Shortcuts ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │ painter: null
flutter: │ foregroundPainter: BannerPainter#1bfd7(Instance of
flutter: │ '_SystemFontsNotifier')
flutter: │
flutter: └─child: RenderSemanticsAnnotations#f470f
flutter: │ needs compositing
flutter: │ creator: Semantics ← FocusScope ← DefaultSelectionStyle ←
flutter: │ IconTheme ← IconTheme ← _InheritedCupertinoTheme ←
flutter: │ CupertinoTheme ← _InheritedTheme ← Theme ← AnimatedTheme ←
flutter: │ DefaultSelectionStyle ← _ScaffoldMessengerScope ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │
flutter: └─child: RenderPointerListener#f59c8
flutter: │ needs compositing
flutter: │ creator: Listener ← HeroControllerScope ←
flutter: │ Navigator-[GlobalObjectKey<NavigatorState>
flutter: │ _WidgetsAppState#0d73a] ← _FocusInheritedScope ← Semantics ←
flutter: │ FocusScope ← DefaultSelectionStyle ← IconTheme ← IconTheme ←
flutter: │ _InheritedCupertinoTheme ← CupertinoTheme ← _InheritedTheme ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │ behavior: deferToChild
flutter: │ listeners: down, up, cancel
flutter: │
flutter: └─child: RenderAbsorbPointer#c91bd
flutter: │ needs compositing
flutter: │ creator: AbsorbPointer ← Listener ← HeroControllerScope ←
flutter: │ Navigator-[GlobalObjectKey<NavigatorState>
flutter: │ _WidgetsAppState#0d73a] ← _FocusInheritedScope ← Semantics ←
flutter: │ FocusScope ← DefaultSelectionStyle ← IconTheme ← IconTheme ←
flutter: │ _InheritedCupertinoTheme ← CupertinoTheme ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │ absorbing: false
flutter: │ ignoringSemantics: null
flutter: │
flutter: └─child: _RenderTheater#07897
flutter: │ needs compositing
flutter: │ creator: _Theater ←
flutter: │ Overlay-[LabeledGlobalKey<OverlayState>#49a93] ←
flutter: │ UnmanagedRestorationScope ← _FocusInheritedScope ← Focus ←
flutter: │ _FocusInheritedScope ← Focus ← FocusTraversalGroup ←
flutter: │ AbsorbPointer ← Listener ← HeroControllerScope ←
flutter: │ Navigator-[GlobalObjectKey<NavigatorState>
flutter: │ _WidgetsAppState#0d73a] ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │ skipCount: 0
flutter: │ textDirection: ltr
flutter: │
flutter: ├─onstage 1: RenderIgnorePointer#3b659
flutter: │ │ creator: IgnorePointer ← _RenderTheaterMarker ←
flutter: │ │ _EffectiveTickerMode ← TickerMode ←
flutter: │ │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#a47f4]
flutter: │ │ ← _Theater ← Overlay-[LabeledGlobalKey<OverlayState>#49a93] ←
flutter: │ │ UnmanagedRestorationScope ← _FocusInheritedScope ← Focus ←
flutter: │ │ _FocusInheritedScope ← Focus ← ⋯
flutter: │ │ parentData: not positioned; offset=Offset(0.0, 0.0) (can use
flutter: │ │ size)
flutter: │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ │ size: Size(800.0, 600.0)
flutter: │ │ ignoring: false
flutter: │ │ ignoringSemantics: null
flutter: │ │
flutter: │ └─child: RenderBlockSemantics#7586c
flutter: │ │ creator: BlockSemantics ← ModalBarrier ← IgnorePointer ←
flutter: │ │ _RenderTheaterMarker ← _EffectiveTickerMode ← TickerMode ←
flutter: │ │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#a47f4]
flutter: │ │ ← _Theater ← Overlay-[LabeledGlobalKey<OverlayState>#49a93] ←
flutter: │ │ UnmanagedRestorationScope ← _FocusInheritedScope ← Focus ← ⋯
flutter: │ │ parentData: <none> (can use size)
flutter: │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ │ blocks semantics of earlier render objects below the common
flutter: │ │ boundary
flutter: │ │ size: Size(800.0, 600.0)
flutter: │ │ blocking: true
flutter: │ │
flutter: │ └─child: RenderExcludeSemantics#c1d3f
flutter: │ │ creator: ExcludeSemantics ← BlockSemantics ← ModalBarrier ←
flutter: │ │ IgnorePointer ← _RenderTheaterMarker ← _EffectiveTickerMode ←
flutter: │ │ TickerMode ←
flutter: │ │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#a47f4]
flutter: │ │ ← _Theater ← Overlay-[LabeledGlobalKey<OverlayState>#49a93] ←
flutter: │ │ UnmanagedRestorationScope ← _FocusInheritedScope ← ⋯
flutter: │ │ parentData: <none> (can use size)
flutter: │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ │ size: Size(800.0, 600.0)
flutter: │ │ excluding: true
flutter: │ │
flutter: │ └─child: RenderSemanticsGestureHandler#70b16
flutter: │ │ creator: _GestureSemantics ← RawGestureDetector ←
flutter: │ │ _ModalBarrierGestureDetector ← ExcludeSemantics ←
flutter: │ │ BlockSemantics ← ModalBarrier ← IgnorePointer ←
flutter: │ │ _RenderTheaterMarker ← _EffectiveTickerMode ← TickerMode ←
flutter: │ │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#a47f4]
flutter: │ │ ← _Theater ← ⋯
flutter: │ │ parentData: <none> (can use size)
flutter: │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ │ size: Size(800.0, 600.0)
flutter: │ │ behavior: opaque
flutter: │ │ gestures: <none>
flutter: │ │
flutter: │ └─child: RenderPointerListener#1f34a
flutter: │ │ creator: Listener ← _GestureSemantics ← RawGestureDetector ←
flutter: │ │ _ModalBarrierGestureDetector ← ExcludeSemantics ←
flutter: │ │ BlockSemantics ← ModalBarrier ← IgnorePointer ←
flutter: │ │ _RenderTheaterMarker ← _EffectiveTickerMode ← TickerMode ←
flutter: │ │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#a47f4]
flutter: │ │ ← ⋯
flutter: │ │ parentData: <none> (can use size)
flutter: │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ │ size: Size(800.0, 600.0)
flutter: │ │ behavior: opaque
flutter: │ │ listeners: down, panZoomStart
flutter: │ │
flutter: │ └─child: RenderSemanticsAnnotations#73467
flutter: │ │ creator: Semantics ← Listener ← _GestureSemantics ←
flutter: │ │ RawGestureDetector ← _ModalBarrierGestureDetector ←
flutter: │ │ ExcludeSemantics ← BlockSemantics ← ModalBarrier ←
flutter: │ │ IgnorePointer ← _RenderTheaterMarker ← _EffectiveTickerMode ←
flutter: │ │ TickerMode ← ⋯
flutter: │ │ parentData: <none> (can use size)
flutter: │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ │ size: Size(800.0, 600.0)
flutter: │ │
flutter: │ └─child: RenderMouseRegion#560dc
flutter: │ │ creator: MouseRegion ← Semantics ← Listener ← _GestureSemantics ←
flutter: │ │ RawGestureDetector ← _ModalBarrierGestureDetector ←
flutter: │ │ ExcludeSemantics ← BlockSemantics ← ModalBarrier ←
flutter: │ │ IgnorePointer ← _RenderTheaterMarker ← _EffectiveTickerMode ← ⋯
flutter: │ │ parentData: <none> (can use size)
flutter: │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ │ size: Size(800.0, 600.0)
flutter: │ │ behavior: opaque
flutter: │ │ listeners: <none>
flutter: │ │ cursor: SystemMouseCursor(basic)
flutter: │ │
flutter: │ └─child: RenderConstrainedBox#01e8c
flutter: │ creator: ConstrainedBox ← MouseRegion ← Semantics ← Listener ←
flutter: │ _GestureSemantics ← RawGestureDetector ←
flutter: │ _ModalBarrierGestureDetector ← ExcludeSemantics ←
flutter: │ BlockSemantics ← ModalBarrier ← IgnorePointer ←
flutter: │ _RenderTheaterMarker ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │ additionalConstraints: BoxConstraints(biggest)
flutter: │
flutter: ├─onstage 2: RenderSemanticsAnnotations#8187b
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: Semantics ← _RenderTheaterMarker ← _EffectiveTickerMode
flutter: ╎ │ ← TickerMode ←
flutter: ╎ │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#8cd54]
flutter: ╎ │ ← _Theater ← Overlay-[LabeledGlobalKey<OverlayState>#49a93] ←
flutter: ╎ │ UnmanagedRestorationScope ← _FocusInheritedScope ← Focus ←
flutter: ╎ │ _FocusInheritedScope ← Focus ← ⋯
flutter: ╎ │ parentData: not positioned; offset=Offset(0.0, 0.0) (can use
flutter: ╎ │ size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │
flutter: ╎ └─child: RenderOffstage#f211d
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: Offstage ← _ModalScopeStatus ← UnmanagedRestorationScope
flutter: ╎ │ ← RestorationScope ← AnimatedBuilder ←
flutter: ╎ │ _ModalScope<dynamic>-[LabeledGlobalKey<_ModalScopeState<dynamic>>#db401]
flutter: ╎ │ ← Semantics ← _RenderTheaterMarker ← _EffectiveTickerMode ←
flutter: ╎ │ TickerMode ←
flutter: ╎ │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#8cd54]
flutter: ╎ │ ← _Theater ← ⋯
flutter: ╎ │ parentData: <none> (can use size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │ offstage: false
flutter: ╎ │
flutter: ╎ └─child: RenderSemanticsAnnotations#9436c
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: Semantics ← FocusScope ← PrimaryScrollController ←
flutter: ╎ │ _ActionsScope ← Actions ← Builder ← PageStorage ← Offstage ←
flutter: ╎ │ _ModalScopeStatus ← UnmanagedRestorationScope ←
flutter: ╎ │ RestorationScope ← AnimatedBuilder ← ⋯
flutter: ╎ │ parentData: <none> (can use size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │
flutter: ╎ └─child: RenderRepaintBoundary#f8f28
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: RepaintBoundary ← _FocusInheritedScope ← Semantics ←
flutter: ╎ │ FocusScope ← PrimaryScrollController ← _ActionsScope ← Actions
flutter: ╎ │ ← Builder ← PageStorage ← Offstage ← _ModalScopeStatus ←
flutter: ╎ │ UnmanagedRestorationScope ← ⋯
flutter: ╎ │ parentData: <none> (can use size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ layer: OffsetLayer#e73b7
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │ metrics: 66.7% useful (1 bad vs 2 good)
flutter: ╎ │ diagnosis: insufficient data to draw conclusion (less than five
flutter: ╎ │ repaints)
flutter: ╎ │
flutter: ╎ └─child: RenderFractionalTranslation#c3a54
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: FractionalTranslation ← SlideTransition ←
flutter: ╎ │ CupertinoPageTransition ← AnimatedBuilder ← RepaintBoundary ←
flutter: ╎ │ _FocusInheritedScope ← Semantics ← FocusScope ←
flutter: ╎ │ PrimaryScrollController ← _ActionsScope ← Actions ← Builder ← ⋯
flutter: ╎ │ parentData: <none> (can use size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │ translation: Offset(0.0, 0.0)
flutter: ╎ │ transformHitTests: false
flutter: ╎ │
flutter: ╎ └─child: RenderFractionalTranslation#7fcf2
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: FractionalTranslation ← SlideTransition ←
flutter: ╎ │ FractionalTranslation ← SlideTransition ←
flutter: ╎ │ CupertinoPageTransition ← AnimatedBuilder ← RepaintBoundary ←
flutter: ╎ │ _FocusInheritedScope ← Semantics ← FocusScope ←
flutter: ╎ │ PrimaryScrollController ← _ActionsScope ← ⋯
flutter: ╎ │ parentData: <none> (can use size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │ translation: Offset(0.0, 0.0)
flutter: ╎ │ transformHitTests: true
flutter: ╎ │
flutter: ╎ └─child: RenderDecoratedBox#713ec
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: DecoratedBox ← DecoratedBoxTransition ←
flutter: ╎ │ FractionalTranslation ← SlideTransition ← FractionalTranslation
flutter: ╎ │ ← SlideTransition ← CupertinoPageTransition ← AnimatedBuilder ←
flutter: ╎ │ RepaintBoundary ← _FocusInheritedScope ← Semantics ← FocusScope
flutter: ╎ │ ← ⋯
flutter: ╎ │ parentData: <none> (can use size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │ ├─decoration: _CupertinoEdgeShadowDecoration
flutter: ╎ │ colors: Color(0x04000000), Color(0x00000000)
flutter: ╎ │
flutter: ╎ │ configuration: ImageConfiguration(bundle:
flutter: ╎ │ PlatformAssetBundle#164ca(), devicePixelRatio: 1.0, locale:
flutter: ╎ │ en_US, textDirection: TextDirection.ltr, platform: macOS)
flutter: ╎ │
flutter: ╎ └─child: RenderStack#83b13
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: Stack ← _CupertinoBackGestureDetector<dynamic> ←
flutter: ╎ │ DecoratedBox ← DecoratedBoxTransition ← FractionalTranslation ←
flutter: ╎ │ SlideTransition ← FractionalTranslation ← SlideTransition ←
flutter: ╎ │ CupertinoPageTransition ← AnimatedBuilder ← RepaintBoundary ←
flutter: ╎ │ _FocusInheritedScope ← ⋯
flutter: ╎ │ parentData: <none> (can use size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │ alignment: AlignmentDirectional.topStart
flutter: ╎ │ textDirection: ltr
flutter: ╎ │ fit: passthrough
flutter: ╎ │
flutter: ╎ ├─child 1: RenderIgnorePointer#ad50f
flutter: ╎ │ │ needs compositing
flutter: ╎ │ │ creator: IgnorePointer ← AnimatedBuilder ← Stack ←
flutter: ╎ │ │ _CupertinoBackGestureDetector<dynamic> ← DecoratedBox ←
flutter: ╎ │ │ DecoratedBoxTransition ← FractionalTranslation ←
flutter: ╎ │ │ SlideTransition ← FractionalTranslation ← SlideTransition ←
flutter: ╎ │ │ CupertinoPageTransition ← AnimatedBuilder ← ⋯
flutter: ╎ │ │ parentData: not positioned; offset=Offset(0.0, 0.0) (can use
flutter: ╎ │ │ size)
flutter: ╎ │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ │ size: Size(800.0, 600.0)
flutter: ╎ │ │ ignoring: false
flutter: ╎ │ │ ignoringSemantics: null
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderRepaintBoundary#29754
flutter: ╎ │ │ needs compositing
flutter: ╎ │ │ creator: RepaintBoundary-[GlobalKey#75409] ← IgnorePointer ←
flutter: ╎ │ │ AnimatedBuilder ← Stack ←
flutter: ╎ │ │ _CupertinoBackGestureDetector<dynamic> ← DecoratedBox ←
flutter: ╎ │ │ DecoratedBoxTransition ← FractionalTranslation ←
flutter: ╎ │ │ SlideTransition ← FractionalTranslation ← SlideTransition ←
flutter: ╎ │ │ CupertinoPageTransition ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ │ layer: OffsetLayer#fa835
flutter: ╎ │ │ size: Size(800.0, 600.0)
flutter: ╎ │ │ metrics: 90.9% useful (1 bad vs 10 good)
flutter: ╎ │ │ diagnosis: this is an outstandingly useful repaint boundary and
flutter: ╎ │ │ should definitely be kept
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderSemanticsAnnotations#95566
flutter: ╎ │ │ creator: Semantics ← Builder ← RepaintBoundary-[GlobalKey#75409]
flutter: ╎ │ │ ← IgnorePointer ← AnimatedBuilder ← Stack ←
flutter: ╎ │ │ _CupertinoBackGestureDetector<dynamic> ← DecoratedBox ←
flutter: ╎ │ │ DecoratedBoxTransition ← FractionalTranslation ←
flutter: ╎ │ │ SlideTransition ← FractionalTranslation ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ │ size: Size(800.0, 600.0)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderPhysicalModel#bc9d7
flutter: ╎ │ │ creator: PhysicalModel ← AnimatedPhysicalModel ← Material ←
flutter: ╎ │ │ AppHome ← Semantics ← Builder ←
flutter: ╎ │ │ RepaintBoundary-[GlobalKey#75409] ← IgnorePointer ←
flutter: ╎ │ │ AnimatedBuilder ← Stack ←
flutter: ╎ │ │ _CupertinoBackGestureDetector<dynamic> ← DecoratedBox ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ │ size: Size(800.0, 600.0)
flutter: ╎ │ │ elevation: 0.0
flutter: ╎ │ │ color: Color(0xfffafafa)
flutter: ╎ │ │ shadowColor: Color(0xfffafafa)
flutter: ╎ │ │ shape: BoxShape.rectangle
flutter: ╎ │ │ borderRadius: BorderRadius.zero
flutter: ╎ │ │
flutter: ╎ │ └─child: _RenderInkFeatures#ac819
flutter: ╎ │ │ creator: _InkFeatures-[GlobalKey#d721e ink renderer] ←
flutter: ╎ │ │ NotificationListener<LayoutChangedNotification> ← PhysicalModel
flutter: ╎ │ │ ← AnimatedPhysicalModel ← Material ← AppHome ← Semantics ←
flutter: ╎ │ │ Builder ← RepaintBoundary-[GlobalKey#75409] ← IgnorePointer ←
flutter: ╎ │ │ AnimatedBuilder ← Stack ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ │ size: Size(800.0, 600.0)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderPositionedBox#dc1df
flutter: ╎ │ │ creator: Center ← DefaultTextStyle ← AnimatedDefaultTextStyle ←
flutter: ╎ │ │ _InkFeatures-[GlobalKey#d721e ink renderer] ←
flutter: ╎ │ │ NotificationListener<LayoutChangedNotification> ← PhysicalModel
flutter: ╎ │ │ ← AnimatedPhysicalModel ← Material ← AppHome ← Semantics ←
flutter: ╎ │ │ Builder ← RepaintBoundary-[GlobalKey#75409] ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ │ size: Size(800.0, 600.0)
flutter: ╎ │ │ alignment: Alignment.center
flutter: ╎ │ │ textDirection: ltr
flutter: ╎ │ │ widthFactor: expand
flutter: ╎ │ │ heightFactor: expand
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderSemanticsAnnotations#a0a4b relayoutBoundary=up1
flutter: ╎ │ │ creator: Semantics ← TextButton ← Center ← DefaultTextStyle ←
flutter: ╎ │ │ AnimatedDefaultTextStyle ← _InkFeatures-[GlobalKey#d721e ink
flutter: ╎ │ │ renderer] ← NotificationListener<LayoutChangedNotification> ←
flutter: ╎ │ │ PhysicalModel ← AnimatedPhysicalModel ← Material ← AppHome ←
flutter: ╎ │ │ Semantics ← ⋯
flutter: ╎ │ │ parentData: offset=Offset(329.0, 286.0) (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)
flutter: ╎ │ │ semantic boundary
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │
flutter: ╎ │ └─child: _RenderInputPadding#4672f relayoutBoundary=up2
flutter: ╎ │ │ creator: _InputPadding ← Semantics ← TextButton ← Center ←
flutter: ╎ │ │ DefaultTextStyle ← AnimatedDefaultTextStyle ←
flutter: ╎ │ │ _InkFeatures-[GlobalKey#d721e ink renderer] ←
flutter: ╎ │ │ NotificationListener<LayoutChangedNotification> ← PhysicalModel
flutter: ╎ │ │ ← AnimatedPhysicalModel ← Material ← AppHome ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderConstrainedBox#425d6 relayoutBoundary=up3
flutter: ╎ │ │ creator: ConstrainedBox ← _InputPadding ← Semantics ← TextButton
flutter: ╎ │ │ ← Center ← DefaultTextStyle ← AnimatedDefaultTextStyle ←
flutter: ╎ │ │ _InkFeatures-[GlobalKey#d721e ink renderer] ←
flutter: ╎ │ │ NotificationListener<LayoutChangedNotification> ← PhysicalModel
flutter: ╎ │ │ ← AnimatedPhysicalModel ← Material ← ⋯
flutter: ╎ │ │ parentData: offset=Offset(0.0, 0.0) (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │ additionalConstraints: BoxConstraints(56.0<=w<=Infinity,
flutter: ╎ │ │ 28.0<=h<=Infinity)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderPhysicalShape#8e171 relayoutBoundary=up4
flutter: ╎ │ │ creator: PhysicalShape ← _MaterialInterior ← Material ←
flutter: ╎ │ │ ConstrainedBox ← _InputPadding ← Semantics ← TextButton ←
flutter: ╎ │ │ Center ← DefaultTextStyle ← AnimatedDefaultTextStyle ←
flutter: ╎ │ │ _InkFeatures-[GlobalKey#d721e ink renderer] ←
flutter: ╎ │ │ NotificationListener<LayoutChangedNotification> ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │ elevation: 0.0
flutter: ╎ │ │ color: Color(0x00000000)
flutter: ╎ │ │ shadowColor: Color(0x00000000)
flutter: ╎ │ │ clipper: ShapeBorderClipper
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderCustomPaint#eea46 relayoutBoundary=up5
flutter: ╎ │ │ creator: CustomPaint ← _ShapeBorderPaint ← PhysicalShape ←
flutter: ╎ │ │ _MaterialInterior ← Material ← ConstrainedBox ← _InputPadding ←
flutter: ╎ │ │ Semantics ← TextButton ← Center ← DefaultTextStyle ←
flutter: ╎ │ │ AnimatedDefaultTextStyle ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │ painter: null
flutter: ╎ │ │ foregroundPainter: _ShapeBorderPainter#ac724()
flutter: ╎ │ │
flutter: ╎ │ └─child: _RenderInkFeatures#b19a7 relayoutBoundary=up6
flutter: ╎ │ │ creator: _InkFeatures-[GlobalKey#87971 ink renderer] ←
flutter: ╎ │ │ NotificationListener<LayoutChangedNotification> ← CustomPaint ←
flutter: ╎ │ │ _ShapeBorderPaint ← PhysicalShape ← _MaterialInterior ←
flutter: ╎ │ │ Material ← ConstrainedBox ← _InputPadding ← Semantics ←
flutter: ╎ │ │ TextButton ← Center ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderSemanticsAnnotations#4d1b3 relayoutBoundary=up7
flutter: ╎ │ │ creator: Semantics ← _FocusInheritedScope ← Focus ← _ActionsScope
flutter: ╎ │ │ ← Actions ← _ParentInkResponseProvider ←
flutter: ╎ │ │ _InkResponseStateWidget ← InkWell ← DefaultTextStyle ←
flutter: ╎ │ │ AnimatedDefaultTextStyle ← _InkFeatures-[GlobalKey#87971 ink
flutter: ╎ │ │ renderer] ← NotificationListener<LayoutChangedNotification> ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderMouseRegion#e5b3f relayoutBoundary=up8
flutter: ╎ │ │ creator: MouseRegion ← Semantics ← _FocusInheritedScope ← Focus ←
flutter: ╎ │ │ _ActionsScope ← Actions ← _ParentInkResponseProvider ←
flutter: ╎ │ │ _InkResponseStateWidget ← InkWell ← DefaultTextStyle ←
flutter: ╎ │ │ AnimatedDefaultTextStyle ← _InkFeatures-[GlobalKey#87971 ink
flutter: ╎ │ │ renderer] ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │ behavior: opaque
flutter: ╎ │ │ listeners: enter, exit
flutter: ╎ │ │ cursor: SystemMouseCursor(click)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderSemanticsAnnotations#deb9b relayoutBoundary=up9
flutter: ╎ │ │ creator: Semantics ← DefaultSelectionStyle ← Builder ←
flutter: ╎ │ │ MouseRegion ← Semantics ← _FocusInheritedScope ← Focus ←
flutter: ╎ │ │ _ActionsScope ← Actions ← _ParentInkResponseProvider ←
flutter: ╎ │ │ _InkResponseStateWidget ← InkWell ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderPointerListener#2017a relayoutBoundary=up10
flutter: ╎ │ │ creator: Listener ← RawGestureDetector ← GestureDetector ←
flutter: ╎ │ │ Semantics ← DefaultSelectionStyle ← Builder ← MouseRegion ←
flutter: ╎ │ │ Semantics ← _FocusInheritedScope ← Focus ← _ActionsScope ←
flutter: ╎ │ │ Actions ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │ behavior: opaque
flutter: ╎ │ │ listeners: down, panZoomStart
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderPadding#8455f relayoutBoundary=up11
flutter: ╎ │ │ creator: Padding ← IconTheme ← Builder ← Listener ←
flutter: ╎ │ │ RawGestureDetector ← GestureDetector ← Semantics ←
flutter: ╎ │ │ DefaultSelectionStyle ← Builder ← MouseRegion ← Semantics ←
flutter: ╎ │ │ _FocusInheritedScope ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │ padding: EdgeInsets(8.0, 0.0, 8.0, 0.0)
flutter: ╎ │ │ textDirection: ltr
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderPositionedBox#80b8d relayoutBoundary=up12
flutter: ╎ │ │ creator: Align ← Padding ← IconTheme ← Builder ← Listener ←
flutter: ╎ │ │ RawGestureDetector ← GestureDetector ← Semantics ←
flutter: ╎ │ │ DefaultSelectionStyle ← Builder ← MouseRegion ← Semantics ← ⋯
flutter: ╎ │ │ parentData: offset=Offset(8.0, 0.0) (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(40.0<=w<=784.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(126.0, 28.0)
flutter: ╎ │ │ alignment: Alignment.center
flutter: ╎ │ │ textDirection: ltr
flutter: ╎ │ │ widthFactor: 1.0
flutter: ╎ │ │ heightFactor: 1.0
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderParagraph#59bc2 relayoutBoundary=up13
flutter: ╎ │ │ creator: RichText ← Text ← Align ← Padding ← IconTheme ← Builder
flutter: ╎ │ │ ← Listener ← RawGestureDetector ← GestureDetector ← Semantics ←
flutter: ╎ │ │ DefaultSelectionStyle ← Builder ← ⋯
flutter: ╎ │ │ parentData: offset=Offset(0.0, 6.0) (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(0.0<=w<=784.0, 0.0<=h<=600.0)
flutter: ╎ │ │ size: Size(126.0, 16.0)
flutter: ╎ │ │ textAlign: start
flutter: ╎ │ │ textDirection: ltr
flutter: ╎ │ │ softWrap: wrapping at box width
flutter: ╎ │ │ overflow: clip
flutter: ╎ │ │ locale: en_US
flutter: ╎ │ │ maxLines: unlimited
flutter: ╎ │ ╘═╦══ text ═══
flutter: ╎ │ ║ TextSpan:
flutter: ╎ │ ║ debugLabel: ((englishLike labelLarge 2014).merge(blackRedwoodCity
flutter: ╎ │ ║ labelLarge)).copyWith
flutter: ╎ │ ║ inherit: false
flutter: ╎ │ ║ color: MaterialColor(primary value: Color(0xff2196f3))
flutter: ╎ │ ║ family: .AppleSystemUIFont
flutter: ╎ │ ║ size: 14.0
flutter: ╎ │ ║ weight: 500
flutter: ╎ │ ║ baseline: alphabetic
flutter: ╎ │ ║ decoration: TextDecoration.none
flutter: ╎ │ ║ "Dump Render Tree"
flutter: ╎ │ ╚═══════════
flutter: ╎ └─child 2: RenderPointerListener#db4b5
flutter: ╎ creator: Listener ← Positioned ← PositionedDirectional ← Stack ←
flutter: ╎ _CupertinoBackGestureDetector<dynamic> ← DecoratedBox ←
flutter: ╎ DecoratedBoxTransition ← FractionalTranslation ←
flutter: ╎ SlideTransition ← FractionalTranslation ← SlideTransition ←
flutter: ╎ CupertinoPageTransition ← ⋯
flutter: ╎ parentData: top=0.0; bottom=0.0; left=0.0; width=20.0;
flutter: ╎ offset=Offset(0.0, 0.0) (can use size)
flutter: ╎ constraints: BoxConstraints(w=20.0, h=600.0)
flutter: ╎ size: Size(20.0, 600.0)
flutter: ╎ behavior: translucent
flutter: ╎ listeners: down
flutter: ╎
flutter: └╌no offstage children
flutter:
在 示例 5 的渲染树中
-
RenderView或窗口大小限制了高达包括RenderPositionedBox#dc1df渲染对象的所有渲染对象的大小为屏幕大小。此示例将大小设置为Size(800.0, 600.0) -
每个渲染对象的
constraints属性限制了每个子对象的大小。此属性将BoxConstraints渲染对象作为值。从RenderSemanticsAnnotations#fe6b5开始,约束等于BoxConstraints(w=800.0, h=600.0)。 -
Center小部件在RenderSemanticsAnnotations#8187b子树下创建了RenderPositionedBox#dc1df渲染对象。 -
此渲染对象下的每个子对象都具有最小值和最大值均为
BoxConstraints。例如,RenderSemanticsAnnotations#a0a4b使用BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)。 -
所有
RenderPhysicalShape#8e171渲染对象的子对象都使用BoxConstraints(BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0))。 -
子
RenderPadding#8455f设置padding值为EdgeInsets(8.0, 0.0, 8.0, 0.0)。这为所有后续的此渲染对象的子对象设置了左右填充 8。现在它们具有新的约束:BoxConstraints(40.0<=w<=784.0, 28.0<=h<=600.0)。
此对象,creator 字段告诉我们它可能是 TextButton 的定义的一部分,在其内容上设置了最小宽度 88 像素和特定高度 36.0。这是 TextButton 类实现 Material Design 关于按钮尺寸的指南。
RenderPositionedBox#80b8d 渲染对象再次放宽了约束以将文本居中对齐在按钮内。RenderParagraph#59bc2 渲染对象根据其内容选择其大小。如果你将大小追溯到树,你将看到文本的大小如何影响形成按钮的所有框的宽度。所有父对象都采用其子对象的尺寸来确定自身大小。
另一种注意到这一点的方法是查看每个框描述中的 relayoutBoundary 属性。这会告诉你多少个祖先依赖于此元素的尺寸。
例如,最内层的 RenderPositionedBox 行具有 relayoutBoundary=up13。这意味着当 Flutter 将 RenderConstrainedBox 标记为脏时,它也会将框的 13 个祖先标记为脏,因为新的尺寸可能会影响这些祖先。
要向转储添加信息,如果你编写自己的渲染对象,请重写 debugFillProperties()。将 DiagnosticsProperty 对象添加到该方法的参数,然后调用超类方法。
打印层树
#要调试合成问题,请使用 debugDumpLayerTree()。
示例 6:调用 debugDumpLayerTree()
#
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: AppHome()));
}
class AppHome extends StatelessWidget {
const AppHome({super.key});
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: TextButton(
onPressed: () {
debugDumpLayerTree();
},
child: const Text('Dump Layer Tree'),
),
),
);
}
}
展开以查看示例 6 的层树输出
flutter: TransformLayer#214da
flutter: │ owner: RenderView#ebaaf
flutter: │ creator: [root]
flutter: │ engine layer: TransformEngineLayer#535de
flutter: │ handles: 1
flutter: │ offset: Offset(0.0, 0.0)
flutter: │ transform:
flutter: │ [0] 1.0,0.0,0.0,0.0
flutter: │ [1] 0.0,1.0,0.0,0.0
flutter: │ [2] 0.0,0.0,1.0,0.0
flutter: │ [3] 0.0,0.0,0.0,1.0
flutter: │
flutter: ├─child 1: OffsetLayer#0f766
flutter: │ │ creator: RepaintBoundary ← _FocusInheritedScope ← Semantics ←
flutter: │ │ FocusScope ← PrimaryScrollController ← _ActionsScope ← Actions
flutter: │ │ ← Builder ← PageStorage ← Offstage ← _ModalScopeStatus ←
flutter: │ │ UnmanagedRestorationScope ← ⋯
flutter: │ │ engine layer: OffsetEngineLayer#1768d
flutter: │ │ handles: 2
flutter: │ │ offset: Offset(0.0, 0.0)
flutter: │ │
flutter: │ ├─child 1: PictureLayer#dd023
flutter: │ │ handles: 1
flutter: │ │ paint bounds: Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
flutter: │ │ picture: _NativePicture#36f94
flutter: │ │ raster cache hints: isComplex = false, willChange = false
flutter: │ │
flutter: │ └─child 2: OffsetLayer#4cfc8
flutter: │ │ creator: RepaintBoundary-[GlobalKey#bd5d9] ← IgnorePointer ←
flutter: │ │ AnimatedBuilder ← Stack ←
flutter: │ │ _CupertinoBackGestureDetector<dynamic> ← DecoratedBox ←
flutter: │ │ DecoratedBoxTransition ← FractionalTranslation ←
flutter: │ │ SlideTransition ← FractionalTranslation ← SlideTransition ←
flutter: │ │ CupertinoPageTransition ← ⋯
flutter: │ │ engine layer: OffsetEngineLayer#a1676
flutter: │ │ handles: 2
flutter: │ │ offset: Offset(0.0, 0.0)
flutter: │ │
flutter: │ └─child 1: PictureLayer#aee55
flutter: │ handles: 1
flutter: │ paint bounds: Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
flutter: │ picture: _NativePicture#e732d
flutter: │ raster cache hints: isComplex = false, willChange = false
flutter: │
flutter: └─child 2: PictureLayer#b16e5
flutter: handles: 1
flutter: paint bounds: Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
flutter: picture: _NativePicture#eef0a
flutter: raster cache hints: isComplex = false, willChange = false
flutter:
RepaintBoundary 小部件创建
-
渲染树中的
RenderRepaintBoundaryRenderObject,如 示例 5 的结果所示。╎ └─child: RenderRepaintBoundary#f8f28 ╎ │ needs compositing ╎ │ creator: RepaintBoundary ← _FocusInheritedScope ← Semantics ← ╎ │ FocusScope ← PrimaryScrollController ← _ActionsScope ← Actions ╎ │ ← Builder ← PageStorage ← Offstage ← _ModalScopeStatus ← ╎ │ UnmanagedRestorationScope ← ⋯ ╎ │ parentData: <none> (can use size) ╎ │ constraints: BoxConstraints(w=800.0, h=600.0) ╎ │ layer: OffsetLayer#e73b7 ╎ │ size: Size(800.0, 600.0) ╎ │ metrics: 66.7% useful (1 bad vs 2 good) ╎ │ diagnosis: insufficient data to draw conclusion (less than five ╎ │ repaints) -
层树中的新层,如 示例 6 的结果所示。
├─child 1: OffsetLayer#0f766 │ │ creator: RepaintBoundary ← _FocusInheritedScope ← Semantics ← │ │ FocusScope ← PrimaryScrollController ← _ActionsScope ← Actions │ │ ← Builder ← PageStorage ← Offstage ← _ModalScopeStatus ← │ │ UnmanagedRestorationScope ← ⋯ │ │ engine layer: OffsetEngineLayer#1768d │ │ handles: 2 │ │ offset: Offset(0.0, 0.0)
这减少了需要重新绘制的内容。
打印焦点树
#要调试焦点或快捷键问题,请使用 debugDumpFocusTree() 函数转储焦点树。
debugDumpFocusTree() 方法返回应用的焦点树。
焦点树以以下方式标记节点
- 聚焦的节点标记为
PRIMARY FOCUS。 - 焦点节点的祖先标记为
IN FOCUS PATH。
如果你的应用使用 Focus 小部件,请使用 debugLabel 属性简化在树中找到其焦点节点。
你还可以使用 debugFocusChanges 布尔属性启用在焦点更改时进行广泛的日志记录。
示例 7:调用 debugDumpFocusTree()
#
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: AppHome()));
}
class AppHome extends StatelessWidget {
const AppHome({super.key});
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: TextButton(
onPressed: () {
debugDumpFocusTree();
},
child: const Text('Dump Focus Tree'),
),
),
);
}
}
展开以查看示例 7 的焦点树
flutter: FocusManager#9d096
flutter: │ primaryFocus: FocusScopeNode#926dc(_ModalScopeState<dynamic>
flutter: │ Focus Scope [PRIMARY FOCUS])
flutter: │ primaryFocusCreator: FocusScope ← PrimaryScrollController ←
flutter: │ _ActionsScope ← Actions ← Builder ← PageStorage ← Offstage ←
flutter: │ _ModalScopeStatus ← UnmanagedRestorationScope ←
flutter: │ RestorationScope ← AnimatedBuilder ←
flutter: │ _ModalScope<dynamic>-[LabeledGlobalKey<_ModalScopeState<dynamic>>#bd53e]
flutter: │ ← Semantics ← _RenderTheaterMarker ← _EffectiveTickerMode ←
flutter: │ TickerMode ←
flutter: │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#89dd7]
flutter: │ ← _Theater ← Overlay-[LabeledGlobalKey<OverlayState>#52f82] ←
flutter: │ UnmanagedRestorationScope ← ⋯
flutter: │
flutter: └─rootScope: FocusScopeNode#f4205(Root Focus Scope [IN FOCUS PATH])
flutter: │ IN FOCUS PATH
flutter: │ focusedChildren: FocusScopeNode#a0d10(Navigator Scope [IN FOCUS
flutter: │ PATH])
flutter: │
flutter: └─Child 1: FocusNode#088ec([IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ NOT FOCUSABLE
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: FocusNode#85f70(Shortcuts [IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ NOT FOCUSABLE
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: FocusNode#f0c18(Shortcuts [IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ NOT FOCUSABLE
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: FocusNode#0749f(Shortcuts [IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ NOT FOCUSABLE
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: _FocusTraversalGroupNode#28990(FocusTraversalGroup [IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ NOT FOCUSABLE
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: FocusNode#5b515(Shortcuts [IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ NOT FOCUSABLE
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: FocusScopeNode#a0d10(Navigator Scope [IN FOCUS PATH])
flutter: │ context: FocusScope
flutter: │ IN FOCUS PATH
flutter: │ focusedChildren: FocusScopeNode#926dc(_ModalScopeState<dynamic>
flutter: │ Focus Scope [PRIMARY FOCUS])
flutter: │
flutter: └─Child 1: _FocusTraversalGroupNode#72c8a(FocusTraversalGroup [IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ NOT FOCUSABLE
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: FocusNode#eb709(Navigator [IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: FocusScopeNode#926dc(_ModalScopeState<dynamic> Focus Scope [PRIMARY FOCUS])
flutter: │ context: FocusScope
flutter: │ PRIMARY FOCUS
flutter: │
flutter: └─Child 1: FocusNode#a6b74
flutter: context: Focus
flutter:
打印语义树
#debugDumpSemanticsTree() 函数打印应用的语义树。
语义树呈现给系统辅助功能 API。要获取语义树的转储
- 使用系统辅助功能工具或
SemanticsDebugger启用辅助功能 - 使用
debugDumpSemanticsTree()函数。
示例 8:调用 debugDumpSemanticsTree()
#
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(const MaterialApp(home: AppHome()));
}
class AppHome extends StatelessWidget {
const AppHome({super.key});
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Semantics(
button: true,
enabled: true,
label: 'Clickable text here!',
child: GestureDetector(
onTap: () {
debugDumpSemanticsTree();
if (kDebugMode) {
print('Clicked!');
}
},
child: const Text('Click Me!', style: TextStyle(fontSize: 56)),
),
),
),
);
}
}
展开以查看示例 8 的语义树
flutter: SemanticsNode#0
flutter: │ Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
flutter: │
flutter: └─SemanticsNode#1
flutter: │ Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
flutter: │ textDirection: ltr
flutter: │
flutter: └─SemanticsNode#2
flutter: │ Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
flutter: │ sortKey: OrdinalSortKey#824a2(order: 0.0)
flutter: │
flutter: └─SemanticsNode#3
flutter: │ Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
flutter: │ flags: scopesRoute
flutter: │
flutter: └─SemanticsNode#4
flutter: Rect.fromLTRB(278.0, 267.0, 522.0, 333.0)
flutter: actions: tap
flutter: flags: isButton, hasEnabledState, isEnabled
flutter: label:
flutter: "Clickable text here!
flutter: Click Me!"
flutter: textDirection: ltr
flutter:
flutter: Clicked!
打印事件时间
#如果你想知道你的事件相对于帧的开始和结束发生的时间,你可以设置打印语句来记录这些事件。要将帧的开始和结束打印到控制台,请切换 debugPrintBeginFrameBanner 和 debugPrintEndFrameBanner。
示例 1 的打印帧横幅日志
I/flutter : ▄▄▄▄▄▄▄▄ Frame 12 30s 437.086ms ▄▄▄▄▄▄▄▄
I/flutter : Debug print: Am I performing this work more than once per frame?
I/flutter : Debug print: Am I performing this work more than once per frame?
I/flutter : ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
要打印导致当前帧被调度的调用堆栈,请使用 debugPrintScheduleFrameStacks 标志。
调试布局问题
#要使用 GUI 调试布局问题,请将 debugPaintSizeEnabled 设置为 true。此标志位于 rendering 库中。你可以在任何时间启用它,并且在 true 时会影响所有绘制。考虑将其添加到你的 void main() 入口点的顶部。
示例 9
#请参阅以下代码中的示例
// Add import to the Flutter rendering library.
import 'package:flutter/rendering.dart';
void main() {
debugPaintSizeEnabled = true;
runApp(const MyApp());
}
启用后,Flutter 会在你的应用中显示以下更改
- 以亮青色边框显示所有框。
- 将所有填充显示为带有褪色蓝色填充和蓝色边框的框,围绕子小部件。
- 以黄色箭头显示所有对齐定位。
- 当它们没有子项时,以灰色显示所有间距。
debugPaintBaselinesEnabled 标志对具有基线的对象执行类似操作。该应用以亮绿色显示字母字符的基线,以橙色显示表意文字字符的基线。字母字符“位于”字母基线上,但该基线“穿过”CJK 字符的底部。Flutter 将表意文字基线定位在文本行的最底部。
debugPaintPointersEnabled 标志开启一种特殊模式,以青色突出显示您点击的任何对象。这可以帮助您确定对象是否未能命中测试。如果对象落在其父级的边界之外,则可能发生这种情况,因此一开始未将其视为命中测试的对象。
如果您正在尝试调试合成层,请考虑使用以下标志。
-
使用
debugPaintLayerBordersEnabled标志查找每个层的边界。此标志导致用橙色勾勒出每个层的边界。 -
使用
debugRepaintRainbowEnabled标志显示重新绘制的层。每当一层重新绘制时,它都会覆盖一层旋转的颜色集。
Flutter 框架中以 debug... 开头的任何函数或方法仅在 调试模式下工作。
调试动画问题
#将 timeDilation 变量(来自 scheduler 库)设置为大于 1.0 的数字,例如 50.0。最好仅在应用启动时设置一次。如果您在动画运行时更改它,尤其是如果降低它,则框架可能会观察到时间倒流,这可能会导致断言并通常干扰您的工作。
调试性能问题
#Flutter 提供了各种顶级属性和函数,以帮助您在开发周期的各个阶段调试应用。要使用这些功能,请以调试模式编译您的应用。
以下列表突出显示了来自 rendering 库的一些标志和一个函数,用于调试性能问题。
-
debugDumpRenderTree() -
要在控制台中转储渲染树,请在非布局或重新绘制阶段调用此函数。
要设置这些标志,请
- 编辑框架代码。
- 导入模块,在您的
main()函数中设置值,然后热重载。
-
debugPaintLayerBordersEnabled -
要显示每个层的边界,请将此属性设置为
true。设置后,每个层会在其边界周围绘制一个框。 -
debugRepaintRainbowEnabled -
要显示围绕每个小部件的彩色边框,请将此属性设置为
true。这些边框会随着应用用户的滚动而改变颜色。要设置此标志,请将debugRepaintRainbowEnabled = true;添加为应用中的顶级属性。如果设置此标志后任何静态小部件旋转颜色,请考虑向这些区域添加重新绘制边界。 -
debugPrintMarkNeedsLayoutStacks -
要确定您的应用是否创建了比预期更多的布局,请将此属性设置为
true。此布局问题可能发生在时间轴上、配置文件中或布局方法内的print语句中。设置后,框架会将堆栈跟踪输出到控制台,以解释您的应用为何将每个渲染对象标记为需要布局。 -
debugPrintMarkNeedsPaintStacks -
要确定您的应用是否绘制了比预期更多的布局,请将此属性设置为
true。
您还可以按需生成堆栈跟踪。要打印您自己的堆栈跟踪,请将 debugPrintStack() 函数添加到您的应用中。
跟踪 Dart 代码性能
#要执行自定义性能跟踪并测量 Dart 代码的任意片段的墙面时间或 CPU 时间,请使用 dart:developer Timeline 工具。
打开您的源代码。
-
使用
Timeline方法包装您想要度量的代码。dartimport 'dart:developer'; void main() { Timeline.startSync('interesting function'); // iWonderHowLongThisTakes(); Timeline.finishSync(); } -
在连接到您的应用时,打开 DevTools 的 时间轴事件选项卡。
-
在 性能设置中选择 Dart 记录选项。
执行您想要度量的函数。
为了确保运行时性能特征与最终产品密切匹配,请以 profile 模式运行您的应用。
添加性能叠加层
#要在您的代码中启用 PerformanceOverlay 小部件,请将 showPerformanceOverlay 属性设置为 true,在 MaterialApp、CupertinoApp 或 WidgetsApp 构造函数中。
示例 10
#import 'package:flutter/material.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
showPerformanceOverlay: true,
title: 'My Awesome App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: const MyHomePage(title: 'My Awesome App'),
);
}
}
(如果您没有使用 MaterialApp、CupertinoApp 或 WidgetsApp,则可以通过将您的应用包装在堆栈中并使用通过调用 PerformanceOverlay.allEnabled() 创建的小部件放置在堆栈上,获得相同效果。)
要了解如何解释叠加层中的图形,请查看 The performance overlay 在 Profiling Flutter performance 中。
添加小部件对齐网格
#要向您的应用添加一个 Material Design 基线网格 叠加层以帮助验证对齐方式,请在 MaterialApp 构造函数中添加 debugShowMaterialGrid 参数。
要向非 Material 应用添加叠加层,请添加一个 GridPaper 小部件。