跳至主要內容

從程式碼偵錯 Flutter 應用程式

本指南說明您可以在程式碼中啟用的偵錯功能。如需偵錯和效能分析工具的完整清單,請參閱偵錯頁面。

將日誌新增至您的應用程式

#

您有兩種應用程式記錄的選項。

  1. 使用 print() 陳述式列印至 stdoutstderr

  2. 匯入 dart:io 並在 stderrstdout 上叫用方法。例如

    dart
    stderr.writeln('print me');

如果您一次輸出太多內容,Android 可能會捨棄一些日誌行。為了避免這種結果,請使用 Flutter 的 foundation 程式庫中的 debugPrint()。此 print 的包裝函式會限制輸出,以避免 Android 核心捨棄輸出。

您也可以使用 dart:developer log() 函式記錄您的應用程式。這可讓您在日誌輸出中包含更大的精細度和更多資訊。

範例 1

#
dart
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

#
dart
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 的內建除錯器中設定中斷點。

若要設定程式中斷點

  1. dart:developer 套件匯入相關檔案。

  2. 使用 debugger() 陳述式插入程式中斷點。此陳述式採用可選的 when 引數。此布林引數會在給定條件解析為 true 時設定中斷。

    範例 3說明了這一點。

範例 3

#
dart
import 'dart:developer';

void someFunction(double offset) {
  debugger(when: offset > 30);
  // ...
}

使用旗標偵錯應用程式圖層

#

Flutter 架構的每個圖層都提供一個函式,可使用 debugPrint 屬性將其目前狀態或事件轉儲到主控台。

#

若要轉儲 Widgets 程式庫的狀態,請呼叫 debugDumpApp() 函式。

  1. 開啟您的原始程式碼檔案。
  2. 匯入 package:flutter/rendering.dart
  3. runApp() 函式內呼叫 debugDumpApp() 函式。您需要處於除錯模式的應用程式。當應用程式正在建置時,您無法在 build() 方法內呼叫此函式。
  4. 如果您尚未啟動應用程式,請使用 IDE 進行除錯。
  5. 如果您已啟動應用程式,請儲存您的原始程式碼檔案。熱重載會重新渲染您的應用程式。

範例 4:呼叫 debugDumpApp()

#
dart
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 圖層的樹狀結構可能缺少詳細資訊。下一個偵錯層級可能需要渲染樹狀結構。若要轉儲渲染樹狀結構

  1. 開啟您的原始程式碼檔案。
  2. 呼叫 debugDumpRenderTree() 函式。除了版面配置或繪製階段之外,您可以隨時呼叫此函式。請考慮從框架回呼或事件處理常式呼叫它。
  3. 如果您尚未啟動應用程式,請使用 IDE 進行除錯。
  4. 如果您已啟動應用程式,請儲存您的原始程式碼檔案。熱重載會重新渲染您的應用程式。

範例 5:呼叫 debugDumpRenderTree()

#
dart
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'),
        ),
      ),
    );
  }
}

在偵錯版面配置問題時,請查看 sizeconstraints 欄位。約束條件會沿著樹狀結構向下流動,而大小會向上流動。

展開以檢視範例 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 設定 EdgeInsets(8.0, 0.0, 8.0, 0.0)padding 值。這會為此渲染物件的所有後續子項設定 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()

#
dart
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 小工具會建立

  1. 範例 5 結果中所示的渲染樹狀結構中的 RenderRepaintBoundary RenderObject。

    ╎     └─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)
  2. 範例 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()

#
dart
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。若要取得語意樹狀結構的傾印

  1. 使用系統輔助功能工具或 SemanticsDebugger 啟用輔助功能
  2. 使用 debugDumpSemanticsTree() 函式。

範例 8:呼叫 debugDumpSemanticsTree()

#
dart
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!
#

如果你想了解事件在影格開始和結束時的相對位置,你可以設定列印來記錄這些事件。若要將影格的開始和結束列印到主控台,請切換 debugPrintBeginFrameBannerdebugPrintEndFrameBanner

範例 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

#

請參閱以下程式碼中的範例

dart
// Add import to the Flutter rendering library.
import 'package:flutter/rendering.dart';

void main() {
  debugPaintSizeEnabled = true;
  runApp(const MyApp());
}

啟用後,Flutter 會在你的應用程式中顯示以下變更

  • 以亮青色邊框顯示所有方塊。
  • 以淡藍色填充和子小工具周圍的藍色邊框顯示所有邊距。
  • 以黃色箭頭顯示所有對齊定位。
  • 在沒有子項時,以灰色顯示所有間隔器。

debugPaintBaselinesEnabled 旗標的作用類似,但適用於具有基準線的物件。應用程式會以亮綠色顯示字母字元的基準線,並以橘色顯示表意字元的基準線。字母字元「坐」在字母基準線上,但該基準線會「切穿」CJK 字元的底部。Flutter 會將表意基準線放置在文字行的最底部。

debugPaintPointersEnabled 旗標會開啟一種特殊模式,該模式會以青色醒目提示你點擊的任何物件。這可以幫助你判斷物件是否無法命中測試。如果物件超出其父項的界限,因而一開始就不會被考慮進行命中測試,則可能會發生這種情況。

如果你嘗試偵錯合成器圖層,請考慮使用以下旗標。

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 時間(如同 Android 使用 systrace),請使用 dart:developer Timeline 公用程式。

  1. 開啟你的原始碼。

  2. 將你想測量的程式碼包裝在 Timeline 方法中。

    dart
    import 'dart:developer';
    
    void main() {
      Timeline.startSync('interesting function');
      // iWonderHowLongThisTakes();
      Timeline.finishSync();
    }
  3. 在連線到你的應用程式時,開啟 DevTools 的時間軸事件索引標籤

  4. 效能設定中選取 Dart 錄製選項。

  5. 執行你想測量的函式。

為了確保執行階段效能特性與你最終產品的效能特性密切匹配,請在效能分析模式下執行你的應用程式。

新增效能覆蓋圖

#

若要在你的程式碼中啟用 PerformanceOverlay 小工具,請在 MaterialAppCupertinoAppWidgetsApp 建構函式上將 showPerformanceOverlay 屬性設定為 true

範例 10

#
dart
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'),
    );
  }
}

(如果你沒有使用 MaterialAppCupertinoAppWidgetsApp,你可以透過將你的應用程式包裝在堆疊中,並將呼叫 PerformanceOverlay.allEnabled() 所建立的小工具放置在你的堆疊上來獲得相同的效果。)

若要了解如何解讀疊加中的圖表,請查看效能疊加中的 分析 Flutter 效能

新增小工具對齊格線

#

若要將疊加新增至應用程式上的Material Design 基準格線,以協助驗證對齊方式,請在 MaterialApp 建構函式中新增 debugShowMaterialGrid 引數。

若要將疊加新增至非 Material 應用程式,請新增 GridPaper 小工具。