從程式碼除錯 Flutter 應用
如何從你的程式碼和命令列啟用各種除錯工具。
本指南介紹了可以在程式碼中啟用的除錯功能。有關完整的除錯和分析工具列表,請檢視 除錯 頁面。
在你的應用程式中新增日誌記錄
#以下列表包含一些可用於記錄應用程式行為的語句。你可以在 DevTools 的 日誌檢視 或系統控制檯中檢視你的日誌。
-
print():列印一個stdout(標準輸出)訊息。是dart:io庫的一部分。 -
stderr.method_to_invoke():列印一個stderr(標準錯誤)訊息。將method_to_invoke()替換為stderr屬性支援的方法,例如writeln()或write()。通常在try...catch塊中使用。是dart:io庫的一部分。dartstderr.writeln('print me'); -
log():包含更精細的粒度和更多資訊在日誌輸出中。是dart:developer庫的一部分。 -
debugPrint():如果過多的輸出導致日誌行被丟棄,請使用此方法來保留這些行。除非是除錯模式檢查或斷言的一部分,否則將在釋出模式下列印訊息。是foundations庫的一部分。
示例 1
#import 'dart:developer' as developer;
void main() {
developer.log('log me', name: 'my.app.category');
developer.log('log me 1', name: 'my.other.category');
developer.log('log me 2', name: 'my.other.category');
}
你還可以將應用程式資料傳遞給日誌呼叫。為此的約定是在 log() 呼叫中使用 error: 命名引數,將要傳送的物件 JSON 編碼,並將編碼後的字串傳遞給 error 引數。
示例 2
#import 'dart:convert';
import 'dart:developer' as developer;
void main() {
var myCustomObject = MyCustomObject();
developer.log(
'log me',
name: 'my.app.category',
error: jsonEncode(myCustomObject),
);
}
DevTool 的日誌檢視將 JSON 編碼的 error 引數解釋為資料物件。DevTool 在該日誌條目的詳細資訊檢視中進行渲染。
設定斷點
#你可以在 DevTools 的 偵錯程式 或 IDE 的內建偵錯程式中設定斷點。
要設定程式化斷點
將
dart:developer包匯入到相關檔案中。-
使用
debugger()語句插入程式化斷點。該語句接受一個可選的when引數。此布林引數在給定的條件解析為 true 時設定斷點。示例 3 說明了這一點。
示例 3
#import 'dart:developer';
void someFunction(double offset) {
debugger(when: offset > 30);
// ...
}
使用標誌除錯應用層
#Flutter 框架的每一層都提供了一個函式,用於使用 debugPrint 屬性將當前狀態或事件轉儲到控制檯。
列印小部件樹
#要轉儲 Widgets 庫的狀態,請呼叫 debugDumpApp() 函式。
- 開啟你的原始檔。
- 匯入
package:flutter/rendering.dart。 - 從
runApp()函式中呼叫debugDumpApp()函式。你需要將你的應用置於除錯模式下。你不能在應用構建時在build()方法中呼叫此函式。 - 如果你尚未啟動你的應用,請使用你的 IDE 進行除錯。
- 如果你已經啟動了你的應用,請儲存你的原始檔。熱過載會重新渲染你的應用。
示例 4:呼叫 debugDumpApp()
#
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: AppHome()));
}
class AppHome extends StatelessWidget {
const AppHome({super.key});
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: TextButton(
onPressed: () {
debugDumpApp();
},
child: const Text('Dump Widget Tree'),
),
),
);
}
}
此函式從小部件樹的根開始遞迴呼叫 toStringDeep() 方法。它返回一個“扁平化”的樹。
示例 4 生成以下小部件樹。它包括
透過各種構建函式投影的所有小部件。
-
許多未出現在你的應用原始碼中的小部件。框架的小部件的構建函式在構建期間插入它們。
以下樹,例如,顯示了
_InkFeatures。該類實現了Material小部件的一部分。它未出現在 示例 4 中的任何程式碼中。
展開以檢視示例 4 的小部件樹
flutter: WidgetsFlutterBinding - DEBUG MODE
flutter: [root](renderObject: RenderView#06beb)
flutter: └View-[GlobalObjectKey FlutterView#7971c]
flutter: └_ViewScope
flutter: └_MediaQueryFromView(state: _MediaQueryFromViewState#d790c)
flutter: └MediaQuery(MediaQueryData(size: Size(800.0, 600.0), devicePixelRatio: 1.0, textScaleFactor: 1.0, platformBrightness: Brightness.dark, padding: EdgeInsets.zero, viewPadding: EdgeInsets.zero, viewInsets: EdgeInsets.zero, systemGestureInsets: EdgeInsets.zero, alwaysUse24HourFormat: false, accessibleNavigation: false, highContrast: false, disableAnimations: false, invertColors: false, boldText: false, navigationMode: traditional, gestureSettings: DeviceGestureSettings(touchSlop: null), displayFeatures: []))
flutter: └MaterialApp(state: _MaterialAppState#27fa9)
flutter: └ScrollConfiguration(behavior: MaterialScrollBehavior)
flutter: └HeroControllerScope
flutter: └Focus(state: _FocusState#d7f97)
flutter: └_FocusInheritedScope
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#a6464)
flutter: └WidgetsApp-[GlobalObjectKey _MaterialAppState#27fa9](state: _WidgetsAppState#b5b17)
flutter: └RootRestorationScope(state: _RootRestorationScopeState#6b028)
flutter: └UnmanagedRestorationScope
flutter: └RestorationScope(dependencies: [UnmanagedRestorationScope], state: _RestorationScopeState#d1369)
flutter: └UnmanagedRestorationScope
flutter: └SharedAppData(state: _SharedAppDataState#95e82)
flutter: └_SharedAppModel
flutter: └Shortcuts(shortcuts: <Default WidgetsApp Shortcuts>, state: _ShortcutsState#272dc)
flutter: └Focus(debugLabel: "Shortcuts", dependencies: [_FocusInheritedScope], state: _FocusState#a3300)
flutter: └_FocusInheritedScope
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#db110)
flutter: └DefaultTextEditingShortcuts
flutter: └Shortcuts(shortcuts: <Default Text Editing Shortcuts>, state: _ShortcutsState#1d796)
flutter: └Focus(debugLabel: "Shortcuts", dependencies: [_FocusInheritedScope], state: _FocusState#0081b)
flutter: └_FocusInheritedScope
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#0d70e)
flutter: └Shortcuts(shortcuts: <Web Disabling Text Editing Shortcuts>, state: _ShortcutsState#56bac)
flutter: └Focus(debugLabel: "Shortcuts", dependencies: [_FocusInheritedScope], state: _FocusState#3152e)
flutter: └_FocusInheritedScope
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#b7eaf)
flutter: └Actions(dispatcher: null, actions: {DoNothingIntent: DoNothingAction#0fda1, DoNothingAndStopPropagationIntent: DoNothingAction#17f30, RequestFocusIntent: RequestFocusAction#10bd0, NextFocusIntent: NextFocusAction#60317, PreviousFocusIntent: PreviousFocusAction#2a933, DirectionalFocusIntent: DirectionalFocusAction#a6922, ScrollIntent: _OverridableContextAction<ScrollIntent>#964fe(defaultAction: ScrollAction#ffb50), PrioritizedIntents: PrioritizedAction#be0e2, VoidCallbackIntent: VoidCallbackAction#805fa}, state: _ActionsState#bbd25)
flutter: └_ActionsScope
flutter: └FocusTraversalGroup(policy: ReadingOrderTraversalPolicy#f1e76, state: _FocusTraversalGroupState#0c200)
flutter: └Focus(debugLabel: "FocusTraversalGroup", focusNode: _FocusTraversalGroupNode#ffcad(FocusTraversalGroup [IN FOCUS PATH]), dependencies: [_FocusInheritedScope], state: _FocusState#c7dc2)
flutter: └_FocusInheritedScope
flutter: └TapRegionSurface(renderObject: RenderTapRegionSurface#17aba)
flutter: └ShortcutRegistrar(state: _ShortcutRegistrarState#44954)
flutter: └_ShortcutRegistrarScope
flutter: └Shortcuts(manager: ShortcutManager#eb38c(shortcuts: {}), shortcuts: {}, state: _ShortcutsState#f85ac)
flutter: └Focus(debugLabel: "Shortcuts", dependencies: [_FocusInheritedScope], state: _FocusState#8c1a7)
flutter: └_FocusInheritedScope
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#1fc98)
flutter: └Localizations(locale: en_US, delegates: [DefaultMaterialLocalizations.delegate(en_US), DefaultCupertinoLocalizations.delegate(en_US), DefaultWidgetsLocalizations.delegate(en_US)], state: _LocalizationsState#ae3a0)
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, textDirection: ltr, renderObject: RenderSemanticsAnnotations#8776e)
flutter: └_LocalizationsScope-[GlobalKey#61ca6]
flutter: └Directionality(textDirection: ltr)
flutter: └Title(color: Color(0xff2196f3))
flutter: └CheckedModeBanner("DEBUG")
flutter: └Banner("DEBUG", textDirection: ltr, location: topEnd, Color(0xa0b71c1c), text inherit: true, text color: Color(0xffffffff), text size: 10.2, text weight: 900, text height: 1.0x, dependencies: [Directionality])
flutter: └CustomPaint(renderObject: RenderCustomPaint#c014d)
flutter: └DefaultTextStyle(debugLabel: fallback style; consider putting your text in a Material, inherit: true, color: Color(0xd0ff0000), family: monospace, size: 48.0, weight: 900, decoration: double Color(0xffffff00) TextDecoration.underline, softWrap: wrapping at box width, overflow: clip)
flutter: └Builder(dependencies: [MediaQuery])
flutter: └ScaffoldMessenger(dependencies: [MediaQuery], state: ScaffoldMessengerState#5b36e)
flutter: └_ScaffoldMessengerScope
flutter: └DefaultSelectionStyle
flutter: └AnimatedTheme(duration: 200ms, state: _AnimatedThemeState#cd149(ticker inactive, ThemeDataTween(ThemeData#ef3b2 → ThemeData#ef3b2)))
flutter: └Theme(ThemeData#ef3b2, dependencies: [DefaultSelectionStyle])
flutter: └_InheritedTheme
flutter: └CupertinoTheme(brightness: light, primaryColor: MaterialColor(primary value: Color(0xff2196f3)), primaryContrastingColor: Color(0xffffffff), scaffoldBackgroundColor: Color(0xfffafafa), actionTextStyle: TextStyle(inherit: false, color: MaterialColor(primary value: Color(0xff2196f3)), family: .SF Pro Text, size: 17.0, letterSpacing: -0.4, decoration: TextDecoration.none), navActionTextStyle: TextStyle(inherit: false, color: MaterialColor(primary value: Color(0xff2196f3)), family: .SF Pro Text, size: 17.0, letterSpacing: -0.4, decoration: TextDecoration.none))
flutter: └_InheritedCupertinoTheme
flutter: └IconTheme(color: MaterialColor(primary value: Color(0xff2196f3)))
flutter: └IconTheme(color: Color(0xdd000000))
flutter: └DefaultSelectionStyle
flutter: └FocusScope(debugLabel: "Navigator Scope", AUTOFOCUS, dependencies: [_FocusInheritedScope], state: _FocusScopeState#acbd8)
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#ab3f0)
flutter: └_FocusInheritedScope
flutter: └Navigator-[GlobalObjectKey<NavigatorState> _WidgetsAppState#b5b17](dependencies: [HeroControllerScope, UnmanagedRestorationScope], state: NavigatorState#1395a(tickers: tracking 1 ticker))
flutter: └HeroControllerScope
flutter: └Listener(listeners: [down, up, cancel], behavior: deferToChild, renderObject: RenderPointerListener#34172)
flutter: └AbsorbPointer(absorbing: false, renderObject: RenderAbsorbPointer#f8711)
flutter: └FocusTraversalGroup(policy: ReadingOrderTraversalPolicy#f1e76, state: _FocusTraversalGroupState#8d61a)
flutter: └Focus(debugLabel: "FocusTraversalGroup", focusNode: _FocusTraversalGroupNode#dd2b1(FocusTraversalGroup [IN FOCUS PATH]), dependencies: [_FocusInheritedScope], state: _FocusState#0bb03)
flutter: └_FocusInheritedScope
flutter: └Focus(debugLabel: "Navigator", AUTOFOCUS, focusNode: FocusNode#a3309(Navigator [IN FOCUS PATH]), dependencies: [_FocusInheritedScope], state: _FocusState#d3d07)
flutter: └_FocusInheritedScope
flutter: └UnmanagedRestorationScope
flutter: └Overlay-[LabeledGlobalKey<OverlayState>#5485a](state: OverlayState#5bd52(entries: [OverlayEntry#fc947(opaque: true; maintainState: false), OverlayEntry#05a32(opaque: false; maintainState: true)]))
flutter: └_Theater(skipCount: 0, dependencies: [Directionality], renderObject: _RenderTheater#e86c3)
flutter: ├_OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#1b37e](state: _OverlayEntryWidgetState#06ab0)
flutter: │└TickerMode(state: _TickerModeState#0b4ac(requested mode: enabled))
flutter: │ └_EffectiveTickerMode(effective mode: enabled)
flutter: │ └_RenderTheaterMarker
flutter: │ └IgnorePointer(ignoring: false, renderObject: RenderIgnorePointer#34c66)
flutter: │ └ModalBarrier
flutter: │ └BlockSemantics(blocking: true, renderObject: RenderBlockSemantics#97799)
flutter: │ └ExcludeSemantics(excluding: true, renderObject: RenderExcludeSemantics#8c4ce)
flutter: │ └_ModalBarrierGestureDetector
flutter: │ └RawGestureDetector(state: RawGestureDetectorState#556f6(gestures: [any tap], behavior: opaque))
flutter: │ └_GestureSemantics(renderObject: RenderSemanticsGestureHandler#616f1)
flutter: │ └Listener(listeners: [down, panZoomStart], behavior: opaque, renderObject: RenderPointerListener#c2b89)
flutter: │ └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#c3b31)
flutter: │ └MouseRegion(listeners: <none>, cursor: SystemMouseCursor(basic), renderObject: RenderMouseRegion#53cdb)
flutter: │ └ConstrainedBox(BoxConstraints(biggest), renderObject: RenderConstrainedBox#faa51)
flutter: └_OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#bc0aa](state: _OverlayEntryWidgetState#cbf35)
flutter: └TickerMode(state: _TickerModeState#23e73(requested mode: enabled))
flutter: └_EffectiveTickerMode(effective mode: enabled)
flutter: └_RenderTheaterMarker
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, sortKey: OrdinalSortKey#135f4(order: 0.0), renderObject: RenderSemanticsAnnotations#5565e)
flutter: └_ModalScope<dynamic>-[LabeledGlobalKey<_ModalScopeState<dynamic>>#4fe82](state: _ModalScopeState<dynamic>#4da7d)
flutter: └AnimatedBuilder(listenable: ValueNotifier<String?>#d87c6(null), state: _AnimatedState#dde81)
flutter: └RestorationScope(dependencies: [UnmanagedRestorationScope], state: _RestorationScopeState#78c51)
flutter: └UnmanagedRestorationScope
flutter: └_ModalScopeStatus(active)
flutter: └Offstage(offstage: false, renderObject: RenderOffstage#5e498)
flutter: └PageStorage
flutter: └Builder
flutter: └Actions(dispatcher: null, actions: {DismissIntent: _DismissModalAction#6279e}, state: _ActionsState#48019)
flutter: └_ActionsScope
flutter: └PrimaryScrollController(ScrollController#6a546(no clients))
flutter: └FocusScope(debugLabel: "_ModalScopeState<dynamic> Focus Scope", focusNode: FocusScopeNode#0e2af(_ModalScopeState<dynamic> Focus Scope [PRIMARY FOCUS]), dependencies: [_FocusInheritedScope], state: _FocusScopeState#0bac4)
flutter: └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#44b4e)
flutter: └_FocusInheritedScope
flutter: └RepaintBoundary(renderObject: RenderRepaintBoundary#38f41)
flutter: └AnimatedBuilder(listenable: Listenable.merge([AnimationController#9d623(⏭ 1.000; paused; for MaterialPageRoute<dynamic>(/))➩ProxyAnimation, kAlwaysDismissedAnimation➩ProxyAnimation➩ProxyAnimation]), dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#61ca6]], state: _AnimatedState#47725)
flutter: └CupertinoPageTransition(dependencies: [Directionality])
flutter: └SlideTransition(listenable: kAlwaysDismissedAnimation➩ProxyAnimation➩ProxyAnimation➩Cubic(0.35, 0.91, 0.33, 0.97)ₒₙ/Cubic(0.67, 0.03, 0.65, 0.09)➩Tween<Offset>(Offset(0.0, 0.0) → Offset(-0.3, 0.0))➩Offset(0.0, 0.0), state: _AnimatedState#b6162)
flutter: └FractionalTranslation(renderObject: RenderFractionalTranslation#fb461)
flutter: └SlideTransition(listenable: AnimationController#9d623(⏭ 1.000; paused; for MaterialPageRoute<dynamic>(/))➩ProxyAnimation➩ThreePointCubic ₒₙ/FlippedCurve(ThreePointCubic )➩Tween<Offset>(Offset(1.0, 0.0) → Offset(0.0, 0.0))➩Offset(0.0, 0.0), state: _AnimatedState#834bf)
flutter: └FractionalTranslation(renderObject: RenderFractionalTranslation#73ea4)
flutter: └DecoratedBoxTransition(listenable: AnimationController#9d623(⏭ 1.000; paused; for MaterialPageRoute<dynamic>(/))➩ProxyAnimation➩Cubic(0.35, 0.91, 0.33, 0.97)➩DecorationTween(_CupertinoEdgeShadowDecoration(colors: null) → _CupertinoEdgeShadowDecoration(colors: [Color(0x04000000), Color(0x00000000)]))➩_CupertinoEdgeShadowDecoration(colors: [Color(0x04000000), Color(0x00000000)]), state: _AnimatedState#a7fca)
flutter: └DecoratedBox(bg: _CupertinoEdgeShadowDecoration(colors: [Color(0x04000000), Color(0x00000000)]), dependencies: [Directionality, MediaQuery, _LocalizationsScope-[GlobalKey#61ca6]], renderObject: RenderDecoratedBox#9965c)
flutter: └_CupertinoBackGestureDetector<dynamic>(dependencies: [Directionality, MediaQuery], state: _CupertinoBackGestureDetectorState<dynamic>#ab8cd)
flutter: └Stack(alignment: AlignmentDirectional.topStart, fit: passthrough, dependencies: [Directionality], renderObject: RenderStack#b2b7c)
flutter: ├AnimatedBuilder(listenable: ValueNotifier<bool>#1a88e(false), state: _AnimatedState#6e33c)
flutter: │└IgnorePointer(ignoring: false, renderObject: RenderIgnorePointer#2b763)
flutter: │ └RepaintBoundary-[GlobalKey#628f4](renderObject: RenderRepaintBoundary#5a53b)
flutter: │ └Builder
flutter: │ └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#f8795)
flutter: │ └AppHome
flutter: │ └Material(type: canvas, dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#61ca6]], state: _MaterialState#7d183)
flutter: │ └AnimatedPhysicalModel(duration: 200ms, shape: rectangle, borderRadius: BorderRadius.zero, elevation: 0.0, color: Color(0xfffafafa), animateColor: false, shadowColor: Color(0xff000000), animateShadowColor: true, state: _AnimatedPhysicalModelState#d479e(ticker inactive))
flutter: │ └PhysicalModel(shape: rectangle, borderRadius: BorderRadius.zero, elevation: 0.0, color: Color(0xfffafafa), shadowColor: Color(0xff000000), renderObject: RenderPhysicalModel#c60b5)
flutter: │ └NotificationListener<LayoutChangedNotification>
flutter: │ └_InkFeatures-[GlobalKey#e9da0 ink renderer](renderObject: _RenderInkFeatures#d8e6d)
flutter: │ └AnimatedDefaultTextStyle(duration: 200ms, debugLabel: (englishLike bodyMedium 2014).merge(blackRedwoodCity bodyMedium), inherit: false, color: Color(0xdd000000), family: .AppleSystemUIFont, size: 14.0, weight: 400, baseline: alphabetic, decoration: TextDecoration.none, softWrap: wrapping at box width, overflow: clip, state: _AnimatedDefaultTextStyleState#12f43(ticker inactive))
flutter: │ └DefaultTextStyle(debugLabel: (englishLike bodyMedium 2014).merge(blackRedwoodCity bodyMedium), inherit: false, color: Color(0xdd000000), family: .AppleSystemUIFont, size: 14.0, weight: 400, baseline: alphabetic, decoration: TextDecoration.none, softWrap: wrapping at box width, overflow: clip)
flutter: │ └Center(alignment: Alignment.center, dependencies: [Directionality], renderObject: RenderPositionedBox#b088f)
flutter: │ └TextButton(dirty, dependencies: [MediaQuery, _InheritedTheme, _LocalizationsScope-[GlobalKey#61ca6]], state: _ButtonStyleState#687c9)
flutter: │ └Semantics(container: true, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#ca411 relayoutBoundary=up1)
flutter: │ └_InputPadding(renderObject: _RenderInputPadding#60ede relayoutBoundary=up2)
flutter: │ └ConstrainedBox(BoxConstraints(56.0<=w<=Infinity, 28.0<=h<=Infinity), renderObject: RenderConstrainedBox#34800 relayoutBoundary=up3)
flutter: │ └Material(type: button, color: Color(0x00000000), shadowColor: Color(0xff000000), textStyle.debugLabel: ((englishLike labelLarge 2014).merge(blackRedwoodCity labelLarge)).copyWith, textStyle.inherit: false, textStyle.color: MaterialColor(primary value: Color(0xff2196f3)), textStyle.family: .AppleSystemUIFont, textStyle.size: 14.0, textStyle.weight: 500, textStyle.baseline: alphabetic, textStyle.decoration: TextDecoration.none, shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(4.0)), dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#61ca6]], state: _MaterialState#50a4d(tickers: tracking 5 tickers))
flutter: │ └_MaterialInterior(duration: 200ms, shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(4.0)), elevation: 0.0, color: Color(0x00000000), shadowColor: Color(0xff000000), dependencies: [Directionality, _InheritedTheme, _LocalizationsScope-[GlobalKey#61ca6]], state: _MaterialInteriorState#d296d(ticker inactive))
flutter: │ └PhysicalShape(clipper: ShapeBorderClipper, elevation: 0.0, color: Color(0x00000000), shadowColor: Color(0xff000000), renderObject: RenderPhysicalShape#43df6 relayoutBoundary=up4)
flutter: │ └_ShapeBorderPaint(dependencies: [Directionality])
flutter: │ └CustomPaint(renderObject: RenderCustomPaint#c1a3c relayoutBoundary=up5)
flutter: │ └NotificationListener<LayoutChangedNotification>
flutter: │ └_InkFeatures-[GlobalKey#625bc ink renderer](renderObject: _RenderInkFeatures#54439 relayoutBoundary=up6)
flutter: │ └AnimatedDefaultTextStyle(duration: 200ms, debugLabel: ((englishLike labelLarge 2014).merge(blackRedwoodCity labelLarge)).copyWith, inherit: false, color: MaterialColor(primary value: Color(0xff2196f3)), family: .AppleSystemUIFont, size: 14.0, weight: 500, baseline: alphabetic, decoration: TextDecoration.none, softWrap: wrapping at box width, overflow: clip, state: _AnimatedDefaultTextStyleState#2f29d(ticker inactive))
flutter: │ └DefaultTextStyle(debugLabel: ((englishLike labelLarge 2014).merge(blackRedwoodCity labelLarge)).copyWith, inherit: false, color: MaterialColor(primary value: Color(0xff2196f3)), family: .AppleSystemUIFont, size: 14.0, weight: 500, baseline: alphabetic, decoration: TextDecoration.none, softWrap: wrapping at box width, overflow: clip)
flutter: │ └InkWell
flutter: │ └_InkResponseStateWidget(gestures: [tap], mouseCursor: ButtonStyleButton_MouseCursor, clipped to BoxShape.rectangle, dirty, dependencies: [Directionality, MediaQuery, _InheritedTheme, _LocalizationsScope-[GlobalKey#61ca6]], state: _InkResponseState#0b11d)
flutter: │ └_ParentInkResponseProvider
flutter: │ └Actions(dispatcher: null, actions: {ActivateIntent: CallbackAction<ActivateIntent>#018db, ButtonActivateIntent: CallbackAction<ButtonActivateIntent>#ef87a}, state: _ActionsState#a5eab)
flutter: │ └_ActionsScope
flutter: │ └Focus(dependencies: [_FocusInheritedScope], state: _FocusState#5a9de)
flutter: │ └_FocusInheritedScope
flutter: │ └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#8ac3e relayoutBoundary=up7)
flutter: │ └MouseRegion(listeners: [enter, exit], cursor: SystemMouseCursor(click), renderObject: RenderMouseRegion#13d4e relayoutBoundary=up8)
flutter: │ └Builder(dependencies: [DefaultSelectionStyle])
flutter: │ └DefaultSelectionStyle
flutter: │ └Semantics(container: false, properties: SemanticsProperties, tooltip: null, renderObject: RenderSemanticsAnnotations#d99cc relayoutBoundary=up9)
flutter: │ └GestureDetector(startBehavior: start, dependencies: [MediaQuery])
flutter: │ └RawGestureDetector(state: RawGestureDetectorState#b8d93(gestures: [tap], excludeFromSemantics: true, behavior: opaque))
flutter: │ └Listener(listeners: [down, panZoomStart], behavior: opaque, renderObject: RenderPointerListener#a4c3b relayoutBoundary=up10)
flutter: │ └Builder(dependencies: [IconTheme])
flutter: │ └IconTheme(color: MaterialColor(primary value: Color(0xff2196f3)))
flutter: │ └Padding(padding: EdgeInsets(8.0, 0.0, 8.0, 0.0), dependencies: [Directionality], renderObject: RenderPadding#18a87 relayoutBoundary=up11)
flutter: │ └Align(alignment: Alignment.center, widthFactor: 1.0, heightFactor: 1.0, dependencies: [Directionality], renderObject: RenderPositionedBox#fb8a8 relayoutBoundary=up12)
flutter: │ └Text("Dump Widget Tree", dependencies: [DefaultSelectionStyle, DefaultTextStyle, MediaQuery])
flutter: │ └RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "Dump Widget Tree", dependencies: [Directionality, _LocalizationsScope-[GlobalKey#61ca6]], renderObject: RenderParagraph#d15aa relayoutBoundary=up13)
flutter: └PositionedDirectional(dependencies: [Directionality])
flutter: └Positioned(left: 0.0, top: 0.0, bottom: 0.0, width: 20.0)
flutter: └Listener(listeners: [down], behavior: translucent, renderObject: RenderPointerListener#d884c)
flutter:
flutter:
當按鈕從按下狀態變為釋放狀態時,這將呼叫 debugDumpApp() 函式。它也與 TextButton 物件呼叫 setState() 從而將其標記為髒狀態相吻合。這就是 Flutter 標記特定物件為“髒”的原因。當你在檢視小部件樹時,查詢類似於以下內容的行
└TextButton(dirty, dependencies: [MediaQuery, _InheritedTheme, _LocalizationsScope-[GlobalKey#5880d]], state: _ButtonStyleState#ab76e)
如果你編寫自己的小部件,請重寫 debugFillProperties() 方法以新增資訊。將 DiagnosticsProperty 物件新增到該方法的引數,然後呼叫超類方法。toString 方法使用此函式來填充小部件的描述。
列印渲染樹
#當除錯佈局問題時,Widgets 層的樹可能缺乏細節。接下來的除錯級別可能需要渲染樹。要轉儲渲染樹
- 開啟你的原始檔。
- 呼叫
debugDumpRenderTree()函式。你可以在任何時間呼叫它,但不要在佈局或繪製階段呼叫。考慮從 幀回撥 或事件處理程式呼叫它。 - 如果你尚未啟動你的應用,請使用你的 IDE 進行除錯。
- 如果你已經啟動了你的應用,請儲存你的原始檔。熱過載會重新渲染你的應用。
示例 5:呼叫 debugDumpRenderTree()
#
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: AppHome()));
}
class AppHome extends StatelessWidget {
const AppHome({super.key});
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: TextButton(
onPressed: () {
debugDumpRenderTree();
},
child: const Text('Dump Render Tree'),
),
),
);
}
}
在除錯佈局問題時,檢視 size 和 constraints 欄位。約束從樹向下流動,大小從樹向上流動。
展開以檢視示例 5 的渲染樹
flutter: RenderView#02c80
flutter: │ debug mode enabled - macos
flutter: │ view size: Size(800.0, 600.0) (in physical pixels)
flutter: │ device pixel ratio: 1.0 (physical pixels per logical pixel)
flutter: │ configuration: Size(800.0, 600.0) at 1.0x (in logical pixels)
flutter: │
flutter: └─child: RenderSemanticsAnnotations#fe6b5
flutter: │ needs compositing
flutter: │ creator: Semantics ← _FocusInheritedScope ← Focus ←
flutter: │ HeroControllerScope ← ScrollConfiguration ← MaterialApp ←
flutter: │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←
flutter: │ View-[GlobalObjectKey FlutterView#6cffa] ← [root]
flutter: │ parentData: <none>
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │
flutter: └─child: RenderSemanticsAnnotations#6edef
flutter: │ needs compositing
flutter: │ creator: Semantics ← _FocusInheritedScope ← Focus ← Shortcuts ←
flutter: │ _SharedAppModel ← SharedAppData ← UnmanagedRestorationScope ←
flutter: │ RestorationScope ← UnmanagedRestorationScope ←
flutter: │ RootRestorationScope ← WidgetsApp-[GlobalObjectKey
flutter: │ _MaterialAppState#5c303] ← Semantics ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │
flutter: └─child: RenderSemanticsAnnotations#e8ce8
flutter: │ needs compositing
flutter: │ creator: Semantics ← _FocusInheritedScope ← Focus ← Shortcuts ←
flutter: │ DefaultTextEditingShortcuts ← Semantics ← _FocusInheritedScope
flutter: │ ← Focus ← Shortcuts ← _SharedAppModel ← SharedAppData ←
flutter: │ UnmanagedRestorationScope ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │
flutter: └─child: RenderSemanticsAnnotations#fc545
flutter: │ needs compositing
flutter: │ creator: Semantics ← _FocusInheritedScope ← Focus ← Shortcuts ←
flutter: │ Semantics ← _FocusInheritedScope ← Focus ← Shortcuts ←
flutter: │ DefaultTextEditingShortcuts ← Semantics ← _FocusInheritedScope
flutter: │ ← Focus ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │
flutter: └─child: RenderTapRegionSurface#ff857
flutter: │ needs compositing
flutter: │ creator: TapRegionSurface ← _FocusInheritedScope ← Focus ←
flutter: │ FocusTraversalGroup ← _ActionsScope ← Actions ← Semantics ←
flutter: │ _FocusInheritedScope ← Focus ← Shortcuts ← Semantics ←
flutter: │ _FocusInheritedScope ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │ behavior: deferToChild
flutter: │
flutter: └─child: RenderSemanticsAnnotations#fe316
flutter: │ needs compositing
flutter: │ creator: Semantics ← _FocusInheritedScope ← Focus ← Shortcuts ←
flutter: │ _ShortcutRegistrarScope ← ShortcutRegistrar ← TapRegionSurface
flutter: │ ← _FocusInheritedScope ← Focus ← FocusTraversalGroup ←
flutter: │ _ActionsScope ← Actions ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │
flutter: └─child: RenderSemanticsAnnotations#fa55c
flutter: │ needs compositing
flutter: │ creator: Semantics ← Localizations ← Semantics ←
flutter: │ _FocusInheritedScope ← Focus ← Shortcuts ←
flutter: │ _ShortcutRegistrarScope ← ShortcutRegistrar ← TapRegionSurface
flutter: │ ← _FocusInheritedScope ← Focus ← FocusTraversalGroup ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │
flutter: └─child: RenderCustomPaint#4b256
flutter: │ needs compositing
flutter: │ creator: CustomPaint ← Banner ← CheckedModeBanner ← Title ←
flutter: │ Directionality ← _LocalizationsScope-[GlobalKey#4a3aa] ←
flutter: │ Semantics ← Localizations ← Semantics ← _FocusInheritedScope ←
flutter: │ Focus ← Shortcuts ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │ painter: null
flutter: │ foregroundPainter: BannerPainter#1bfd7(Instance of
flutter: │ '_SystemFontsNotifier')
flutter: │
flutter: └─child: RenderSemanticsAnnotations#f470f
flutter: │ needs compositing
flutter: │ creator: Semantics ← FocusScope ← DefaultSelectionStyle ←
flutter: │ IconTheme ← IconTheme ← _InheritedCupertinoTheme ←
flutter: │ CupertinoTheme ← _InheritedTheme ← Theme ← AnimatedTheme ←
flutter: │ DefaultSelectionStyle ← _ScaffoldMessengerScope ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │
flutter: └─child: RenderPointerListener#f59c8
flutter: │ needs compositing
flutter: │ creator: Listener ← HeroControllerScope ←
flutter: │ Navigator-[GlobalObjectKey<NavigatorState>
flutter: │ _WidgetsAppState#0d73a] ← _FocusInheritedScope ← Semantics ←
flutter: │ FocusScope ← DefaultSelectionStyle ← IconTheme ← IconTheme ←
flutter: │ _InheritedCupertinoTheme ← CupertinoTheme ← _InheritedTheme ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │ behavior: deferToChild
flutter: │ listeners: down, up, cancel
flutter: │
flutter: └─child: RenderAbsorbPointer#c91bd
flutter: │ needs compositing
flutter: │ creator: AbsorbPointer ← Listener ← HeroControllerScope ←
flutter: │ Navigator-[GlobalObjectKey<NavigatorState>
flutter: │ _WidgetsAppState#0d73a] ← _FocusInheritedScope ← Semantics ←
flutter: │ FocusScope ← DefaultSelectionStyle ← IconTheme ← IconTheme ←
flutter: │ _InheritedCupertinoTheme ← CupertinoTheme ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │ absorbing: false
flutter: │ ignoringSemantics: null
flutter: │
flutter: └─child: _RenderTheater#07897
flutter: │ needs compositing
flutter: │ creator: _Theater ←
flutter: │ Overlay-[LabeledGlobalKey<OverlayState>#49a93] ←
flutter: │ UnmanagedRestorationScope ← _FocusInheritedScope ← Focus ←
flutter: │ _FocusInheritedScope ← Focus ← FocusTraversalGroup ←
flutter: │ AbsorbPointer ← Listener ← HeroControllerScope ←
flutter: │ Navigator-[GlobalObjectKey<NavigatorState>
flutter: │ _WidgetsAppState#0d73a] ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │ skipCount: 0
flutter: │ textDirection: ltr
flutter: │
flutter: ├─onstage 1: RenderIgnorePointer#3b659
flutter: │ │ creator: IgnorePointer ← _RenderTheaterMarker ←
flutter: │ │ _EffectiveTickerMode ← TickerMode ←
flutter: │ │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#a47f4]
flutter: │ │ ← _Theater ← Overlay-[LabeledGlobalKey<OverlayState>#49a93] ←
flutter: │ │ UnmanagedRestorationScope ← _FocusInheritedScope ← Focus ←
flutter: │ │ _FocusInheritedScope ← Focus ← ⋯
flutter: │ │ parentData: not positioned; offset=Offset(0.0, 0.0) (can use
flutter: │ │ size)
flutter: │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ │ size: Size(800.0, 600.0)
flutter: │ │ ignoring: false
flutter: │ │ ignoringSemantics: null
flutter: │ │
flutter: │ └─child: RenderBlockSemantics#7586c
flutter: │ │ creator: BlockSemantics ← ModalBarrier ← IgnorePointer ←
flutter: │ │ _RenderTheaterMarker ← _EffectiveTickerMode ← TickerMode ←
flutter: │ │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#a47f4]
flutter: │ │ ← _Theater ← Overlay-[LabeledGlobalKey<OverlayState>#49a93] ←
flutter: │ │ UnmanagedRestorationScope ← _FocusInheritedScope ← Focus ← ⋯
flutter: │ │ parentData: <none> (can use size)
flutter: │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ │ blocks semantics of earlier render objects below the common
flutter: │ │ boundary
flutter: │ │ size: Size(800.0, 600.0)
flutter: │ │ blocking: true
flutter: │ │
flutter: │ └─child: RenderExcludeSemantics#c1d3f
flutter: │ │ creator: ExcludeSemantics ← BlockSemantics ← ModalBarrier ←
flutter: │ │ IgnorePointer ← _RenderTheaterMarker ← _EffectiveTickerMode ←
flutter: │ │ TickerMode ←
flutter: │ │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#a47f4]
flutter: │ │ ← _Theater ← Overlay-[LabeledGlobalKey<OverlayState>#49a93] ←
flutter: │ │ UnmanagedRestorationScope ← _FocusInheritedScope ← ⋯
flutter: │ │ parentData: <none> (can use size)
flutter: │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ │ size: Size(800.0, 600.0)
flutter: │ │ excluding: true
flutter: │ │
flutter: │ └─child: RenderSemanticsGestureHandler#70b16
flutter: │ │ creator: _GestureSemantics ← RawGestureDetector ←
flutter: │ │ _ModalBarrierGestureDetector ← ExcludeSemantics ←
flutter: │ │ BlockSemantics ← ModalBarrier ← IgnorePointer ←
flutter: │ │ _RenderTheaterMarker ← _EffectiveTickerMode ← TickerMode ←
flutter: │ │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#a47f4]
flutter: │ │ ← _Theater ← ⋯
flutter: │ │ parentData: <none> (can use size)
flutter: │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ │ size: Size(800.0, 600.0)
flutter: │ │ behavior: opaque
flutter: │ │ gestures: <none>
flutter: │ │
flutter: │ └─child: RenderPointerListener#1f34a
flutter: │ │ creator: Listener ← _GestureSemantics ← RawGestureDetector ←
flutter: │ │ _ModalBarrierGestureDetector ← ExcludeSemantics ←
flutter: │ │ BlockSemantics ← ModalBarrier ← IgnorePointer ←
flutter: │ │ _RenderTheaterMarker ← _EffectiveTickerMode ← TickerMode ←
flutter: │ │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#a47f4]
flutter: │ │ ← ⋯
flutter: │ │ parentData: <none> (can use size)
flutter: │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ │ size: Size(800.0, 600.0)
flutter: │ │ behavior: opaque
flutter: │ │ listeners: down, panZoomStart
flutter: │ │
flutter: │ └─child: RenderSemanticsAnnotations#73467
flutter: │ │ creator: Semantics ← Listener ← _GestureSemantics ←
flutter: │ │ RawGestureDetector ← _ModalBarrierGestureDetector ←
flutter: │ │ ExcludeSemantics ← BlockSemantics ← ModalBarrier ←
flutter: │ │ IgnorePointer ← _RenderTheaterMarker ← _EffectiveTickerMode ←
flutter: │ │ TickerMode ← ⋯
flutter: │ │ parentData: <none> (can use size)
flutter: │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ │ size: Size(800.0, 600.0)
flutter: │ │
flutter: │ └─child: RenderMouseRegion#560dc
flutter: │ │ creator: MouseRegion ← Semantics ← Listener ← _GestureSemantics ←
flutter: │ │ RawGestureDetector ← _ModalBarrierGestureDetector ←
flutter: │ │ ExcludeSemantics ← BlockSemantics ← ModalBarrier ←
flutter: │ │ IgnorePointer ← _RenderTheaterMarker ← _EffectiveTickerMode ← ⋯
flutter: │ │ parentData: <none> (can use size)
flutter: │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ │ size: Size(800.0, 600.0)
flutter: │ │ behavior: opaque
flutter: │ │ listeners: <none>
flutter: │ │ cursor: SystemMouseCursor(basic)
flutter: │ │
flutter: │ └─child: RenderConstrainedBox#01e8c
flutter: │ creator: ConstrainedBox ← MouseRegion ← Semantics ← Listener ←
flutter: │ _GestureSemantics ← RawGestureDetector ←
flutter: │ _ModalBarrierGestureDetector ← ExcludeSemantics ←
flutter: │ BlockSemantics ← ModalBarrier ← IgnorePointer ←
flutter: │ _RenderTheaterMarker ← ⋯
flutter: │ parentData: <none> (can use size)
flutter: │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: │ size: Size(800.0, 600.0)
flutter: │ additionalConstraints: BoxConstraints(biggest)
flutter: │
flutter: ├─onstage 2: RenderSemanticsAnnotations#8187b
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: Semantics ← _RenderTheaterMarker ← _EffectiveTickerMode
flutter: ╎ │ ← TickerMode ←
flutter: ╎ │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#8cd54]
flutter: ╎ │ ← _Theater ← Overlay-[LabeledGlobalKey<OverlayState>#49a93] ←
flutter: ╎ │ UnmanagedRestorationScope ← _FocusInheritedScope ← Focus ←
flutter: ╎ │ _FocusInheritedScope ← Focus ← ⋯
flutter: ╎ │ parentData: not positioned; offset=Offset(0.0, 0.0) (can use
flutter: ╎ │ size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │
flutter: ╎ └─child: RenderOffstage#f211d
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: Offstage ← _ModalScopeStatus ← UnmanagedRestorationScope
flutter: ╎ │ ← RestorationScope ← AnimatedBuilder ←
flutter: ╎ │ _ModalScope<dynamic>-[LabeledGlobalKey<_ModalScopeState<dynamic>>#db401]
flutter: ╎ │ ← Semantics ← _RenderTheaterMarker ← _EffectiveTickerMode ←
flutter: ╎ │ TickerMode ←
flutter: ╎ │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#8cd54]
flutter: ╎ │ ← _Theater ← ⋯
flutter: ╎ │ parentData: <none> (can use size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │ offstage: false
flutter: ╎ │
flutter: ╎ └─child: RenderSemanticsAnnotations#9436c
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: Semantics ← FocusScope ← PrimaryScrollController ←
flutter: ╎ │ _ActionsScope ← Actions ← Builder ← PageStorage ← Offstage ←
flutter: ╎ │ _ModalScopeStatus ← UnmanagedRestorationScope ←
flutter: ╎ │ RestorationScope ← AnimatedBuilder ← ⋯
flutter: ╎ │ parentData: <none> (can use size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │
flutter: ╎ └─child: RenderRepaintBoundary#f8f28
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: RepaintBoundary ← _FocusInheritedScope ← Semantics ←
flutter: ╎ │ FocusScope ← PrimaryScrollController ← _ActionsScope ← Actions
flutter: ╎ │ ← Builder ← PageStorage ← Offstage ← _ModalScopeStatus ←
flutter: ╎ │ UnmanagedRestorationScope ← ⋯
flutter: ╎ │ parentData: <none> (can use size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ layer: OffsetLayer#e73b7
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │ metrics: 66.7% useful (1 bad vs 2 good)
flutter: ╎ │ diagnosis: insufficient data to draw conclusion (less than five
flutter: ╎ │ repaints)
flutter: ╎ │
flutter: ╎ └─child: RenderFractionalTranslation#c3a54
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: FractionalTranslation ← SlideTransition ←
flutter: ╎ │ CupertinoPageTransition ← AnimatedBuilder ← RepaintBoundary ←
flutter: ╎ │ _FocusInheritedScope ← Semantics ← FocusScope ←
flutter: ╎ │ PrimaryScrollController ← _ActionsScope ← Actions ← Builder ← ⋯
flutter: ╎ │ parentData: <none> (can use size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │ translation: Offset(0.0, 0.0)
flutter: ╎ │ transformHitTests: false
flutter: ╎ │
flutter: ╎ └─child: RenderFractionalTranslation#7fcf2
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: FractionalTranslation ← SlideTransition ←
flutter: ╎ │ FractionalTranslation ← SlideTransition ←
flutter: ╎ │ CupertinoPageTransition ← AnimatedBuilder ← RepaintBoundary ←
flutter: ╎ │ _FocusInheritedScope ← Semantics ← FocusScope ←
flutter: ╎ │ PrimaryScrollController ← _ActionsScope ← ⋯
flutter: ╎ │ parentData: <none> (can use size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │ translation: Offset(0.0, 0.0)
flutter: ╎ │ transformHitTests: true
flutter: ╎ │
flutter: ╎ └─child: RenderDecoratedBox#713ec
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: DecoratedBox ← DecoratedBoxTransition ←
flutter: ╎ │ FractionalTranslation ← SlideTransition ← FractionalTranslation
flutter: ╎ │ ← SlideTransition ← CupertinoPageTransition ← AnimatedBuilder ←
flutter: ╎ │ RepaintBoundary ← _FocusInheritedScope ← Semantics ← FocusScope
flutter: ╎ │ ← ⋯
flutter: ╎ │ parentData: <none> (can use size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │ ├─decoration: _CupertinoEdgeShadowDecoration
flutter: ╎ │ colors: Color(0x04000000), Color(0x00000000)
flutter: ╎ │
flutter: ╎ │ configuration: ImageConfiguration(bundle:
flutter: ╎ │ PlatformAssetBundle#164ca(), devicePixelRatio: 1.0, locale:
flutter: ╎ │ en_US, textDirection: TextDirection.ltr, platform: macOS)
flutter: ╎ │
flutter: ╎ └─child: RenderStack#83b13
flutter: ╎ │ needs compositing
flutter: ╎ │ creator: Stack ← _CupertinoBackGestureDetector<dynamic> ←
flutter: ╎ │ DecoratedBox ← DecoratedBoxTransition ← FractionalTranslation ←
flutter: ╎ │ SlideTransition ← FractionalTranslation ← SlideTransition ←
flutter: ╎ │ CupertinoPageTransition ← AnimatedBuilder ← RepaintBoundary ←
flutter: ╎ │ _FocusInheritedScope ← ⋯
flutter: ╎ │ parentData: <none> (can use size)
flutter: ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ size: Size(800.0, 600.0)
flutter: ╎ │ alignment: AlignmentDirectional.topStart
flutter: ╎ │ textDirection: ltr
flutter: ╎ │ fit: passthrough
flutter: ╎ │
flutter: ╎ ├─child 1: RenderIgnorePointer#ad50f
flutter: ╎ │ │ needs compositing
flutter: ╎ │ │ creator: IgnorePointer ← AnimatedBuilder ← Stack ←
flutter: ╎ │ │ _CupertinoBackGestureDetector<dynamic> ← DecoratedBox ←
flutter: ╎ │ │ DecoratedBoxTransition ← FractionalTranslation ←
flutter: ╎ │ │ SlideTransition ← FractionalTranslation ← SlideTransition ←
flutter: ╎ │ │ CupertinoPageTransition ← AnimatedBuilder ← ⋯
flutter: ╎ │ │ parentData: not positioned; offset=Offset(0.0, 0.0) (can use
flutter: ╎ │ │ size)
flutter: ╎ │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ │ size: Size(800.0, 600.0)
flutter: ╎ │ │ ignoring: false
flutter: ╎ │ │ ignoringSemantics: null
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderRepaintBoundary#29754
flutter: ╎ │ │ needs compositing
flutter: ╎ │ │ creator: RepaintBoundary-[GlobalKey#75409] ← IgnorePointer ←
flutter: ╎ │ │ AnimatedBuilder ← Stack ←
flutter: ╎ │ │ _CupertinoBackGestureDetector<dynamic> ← DecoratedBox ←
flutter: ╎ │ │ DecoratedBoxTransition ← FractionalTranslation ←
flutter: ╎ │ │ SlideTransition ← FractionalTranslation ← SlideTransition ←
flutter: ╎ │ │ CupertinoPageTransition ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ │ layer: OffsetLayer#fa835
flutter: ╎ │ │ size: Size(800.0, 600.0)
flutter: ╎ │ │ metrics: 90.9% useful (1 bad vs 10 good)
flutter: ╎ │ │ diagnosis: this is an outstandingly useful repaint boundary and
flutter: ╎ │ │ should definitely be kept
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderSemanticsAnnotations#95566
flutter: ╎ │ │ creator: Semantics ← Builder ← RepaintBoundary-[GlobalKey#75409]
flutter: ╎ │ │ ← IgnorePointer ← AnimatedBuilder ← Stack ←
flutter: ╎ │ │ _CupertinoBackGestureDetector<dynamic> ← DecoratedBox ←
flutter: ╎ │ │ DecoratedBoxTransition ← FractionalTranslation ←
flutter: ╎ │ │ SlideTransition ← FractionalTranslation ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ │ size: Size(800.0, 600.0)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderPhysicalModel#bc9d7
flutter: ╎ │ │ creator: PhysicalModel ← AnimatedPhysicalModel ← Material ←
flutter: ╎ │ │ AppHome ← Semantics ← Builder ←
flutter: ╎ │ │ RepaintBoundary-[GlobalKey#75409] ← IgnorePointer ←
flutter: ╎ │ │ AnimatedBuilder ← Stack ←
flutter: ╎ │ │ _CupertinoBackGestureDetector<dynamic> ← DecoratedBox ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ │ size: Size(800.0, 600.0)
flutter: ╎ │ │ elevation: 0.0
flutter: ╎ │ │ color: Color(0xfffafafa)
flutter: ╎ │ │ shadowColor: Color(0xfffafafa)
flutter: ╎ │ │ shape: BoxShape.rectangle
flutter: ╎ │ │ borderRadius: BorderRadius.zero
flutter: ╎ │ │
flutter: ╎ │ └─child: _RenderInkFeatures#ac819
flutter: ╎ │ │ creator: _InkFeatures-[GlobalKey#d721e ink renderer] ←
flutter: ╎ │ │ NotificationListener<LayoutChangedNotification> ← PhysicalModel
flutter: ╎ │ │ ← AnimatedPhysicalModel ← Material ← AppHome ← Semantics ←
flutter: ╎ │ │ Builder ← RepaintBoundary-[GlobalKey#75409] ← IgnorePointer ←
flutter: ╎ │ │ AnimatedBuilder ← Stack ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ │ size: Size(800.0, 600.0)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderPositionedBox#dc1df
flutter: ╎ │ │ creator: Center ← DefaultTextStyle ← AnimatedDefaultTextStyle ←
flutter: ╎ │ │ _InkFeatures-[GlobalKey#d721e ink renderer] ←
flutter: ╎ │ │ NotificationListener<LayoutChangedNotification> ← PhysicalModel
flutter: ╎ │ │ ← AnimatedPhysicalModel ← Material ← AppHome ← Semantics ←
flutter: ╎ │ │ Builder ← RepaintBoundary-[GlobalKey#75409] ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(w=800.0, h=600.0)
flutter: ╎ │ │ size: Size(800.0, 600.0)
flutter: ╎ │ │ alignment: Alignment.center
flutter: ╎ │ │ textDirection: ltr
flutter: ╎ │ │ widthFactor: expand
flutter: ╎ │ │ heightFactor: expand
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderSemanticsAnnotations#a0a4b relayoutBoundary=up1
flutter: ╎ │ │ creator: Semantics ← TextButton ← Center ← DefaultTextStyle ←
flutter: ╎ │ │ AnimatedDefaultTextStyle ← _InkFeatures-[GlobalKey#d721e ink
flutter: ╎ │ │ renderer] ← NotificationListener<LayoutChangedNotification> ←
flutter: ╎ │ │ PhysicalModel ← AnimatedPhysicalModel ← Material ← AppHome ←
flutter: ╎ │ │ Semantics ← ⋯
flutter: ╎ │ │ parentData: offset=Offset(329.0, 286.0) (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)
flutter: ╎ │ │ semantic boundary
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │
flutter: ╎ │ └─child: _RenderInputPadding#4672f relayoutBoundary=up2
flutter: ╎ │ │ creator: _InputPadding ← Semantics ← TextButton ← Center ←
flutter: ╎ │ │ DefaultTextStyle ← AnimatedDefaultTextStyle ←
flutter: ╎ │ │ _InkFeatures-[GlobalKey#d721e ink renderer] ←
flutter: ╎ │ │ NotificationListener<LayoutChangedNotification> ← PhysicalModel
flutter: ╎ │ │ ← AnimatedPhysicalModel ← Material ← AppHome ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderConstrainedBox#425d6 relayoutBoundary=up3
flutter: ╎ │ │ creator: ConstrainedBox ← _InputPadding ← Semantics ← TextButton
flutter: ╎ │ │ ← Center ← DefaultTextStyle ← AnimatedDefaultTextStyle ←
flutter: ╎ │ │ _InkFeatures-[GlobalKey#d721e ink renderer] ←
flutter: ╎ │ │ NotificationListener<LayoutChangedNotification> ← PhysicalModel
flutter: ╎ │ │ ← AnimatedPhysicalModel ← Material ← ⋯
flutter: ╎ │ │ parentData: offset=Offset(0.0, 0.0) (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │ additionalConstraints: BoxConstraints(56.0<=w<=Infinity,
flutter: ╎ │ │ 28.0<=h<=Infinity)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderPhysicalShape#8e171 relayoutBoundary=up4
flutter: ╎ │ │ creator: PhysicalShape ← _MaterialInterior ← Material ←
flutter: ╎ │ │ ConstrainedBox ← _InputPadding ← Semantics ← TextButton ←
flutter: ╎ │ │ Center ← DefaultTextStyle ← AnimatedDefaultTextStyle ←
flutter: ╎ │ │ _InkFeatures-[GlobalKey#d721e ink renderer] ←
flutter: ╎ │ │ NotificationListener<LayoutChangedNotification> ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │ elevation: 0.0
flutter: ╎ │ │ color: Color(0x00000000)
flutter: ╎ │ │ shadowColor: Color(0x00000000)
flutter: ╎ │ │ clipper: ShapeBorderClipper
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderCustomPaint#eea46 relayoutBoundary=up5
flutter: ╎ │ │ creator: CustomPaint ← _ShapeBorderPaint ← PhysicalShape ←
flutter: ╎ │ │ _MaterialInterior ← Material ← ConstrainedBox ← _InputPadding ←
flutter: ╎ │ │ Semantics ← TextButton ← Center ← DefaultTextStyle ←
flutter: ╎ │ │ AnimatedDefaultTextStyle ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │ painter: null
flutter: ╎ │ │ foregroundPainter: _ShapeBorderPainter#ac724()
flutter: ╎ │ │
flutter: ╎ │ └─child: _RenderInkFeatures#b19a7 relayoutBoundary=up6
flutter: ╎ │ │ creator: _InkFeatures-[GlobalKey#87971 ink renderer] ←
flutter: ╎ │ │ NotificationListener<LayoutChangedNotification> ← CustomPaint ←
flutter: ╎ │ │ _ShapeBorderPaint ← PhysicalShape ← _MaterialInterior ←
flutter: ╎ │ │ Material ← ConstrainedBox ← _InputPadding ← Semantics ←
flutter: ╎ │ │ TextButton ← Center ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderSemanticsAnnotations#4d1b3 relayoutBoundary=up7
flutter: ╎ │ │ creator: Semantics ← _FocusInheritedScope ← Focus ← _ActionsScope
flutter: ╎ │ │ ← Actions ← _ParentInkResponseProvider ←
flutter: ╎ │ │ _InkResponseStateWidget ← InkWell ← DefaultTextStyle ←
flutter: ╎ │ │ AnimatedDefaultTextStyle ← _InkFeatures-[GlobalKey#87971 ink
flutter: ╎ │ │ renderer] ← NotificationListener<LayoutChangedNotification> ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderMouseRegion#e5b3f relayoutBoundary=up8
flutter: ╎ │ │ creator: MouseRegion ← Semantics ← _FocusInheritedScope ← Focus ←
flutter: ╎ │ │ _ActionsScope ← Actions ← _ParentInkResponseProvider ←
flutter: ╎ │ │ _InkResponseStateWidget ← InkWell ← DefaultTextStyle ←
flutter: ╎ │ │ AnimatedDefaultTextStyle ← _InkFeatures-[GlobalKey#87971 ink
flutter: ╎ │ │ renderer] ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │ behavior: opaque
flutter: ╎ │ │ listeners: enter, exit
flutter: ╎ │ │ cursor: SystemMouseCursor(click)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderSemanticsAnnotations#deb9b relayoutBoundary=up9
flutter: ╎ │ │ creator: Semantics ← DefaultSelectionStyle ← Builder ←
flutter: ╎ │ │ MouseRegion ← Semantics ← _FocusInheritedScope ← Focus ←
flutter: ╎ │ │ _ActionsScope ← Actions ← _ParentInkResponseProvider ←
flutter: ╎ │ │ _InkResponseStateWidget ← InkWell ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderPointerListener#2017a relayoutBoundary=up10
flutter: ╎ │ │ creator: Listener ← RawGestureDetector ← GestureDetector ←
flutter: ╎ │ │ Semantics ← DefaultSelectionStyle ← Builder ← MouseRegion ←
flutter: ╎ │ │ Semantics ← _FocusInheritedScope ← Focus ← _ActionsScope ←
flutter: ╎ │ │ Actions ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │ behavior: opaque
flutter: ╎ │ │ listeners: down, panZoomStart
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderPadding#8455f relayoutBoundary=up11
flutter: ╎ │ │ creator: Padding ← IconTheme ← Builder ← Listener ←
flutter: ╎ │ │ RawGestureDetector ← GestureDetector ← Semantics ←
flutter: ╎ │ │ DefaultSelectionStyle ← Builder ← MouseRegion ← Semantics ←
flutter: ╎ │ │ _FocusInheritedScope ← ⋯
flutter: ╎ │ │ parentData: <none> (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(142.0, 28.0)
flutter: ╎ │ │ padding: EdgeInsets(8.0, 0.0, 8.0, 0.0)
flutter: ╎ │ │ textDirection: ltr
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderPositionedBox#80b8d relayoutBoundary=up12
flutter: ╎ │ │ creator: Align ← Padding ← IconTheme ← Builder ← Listener ←
flutter: ╎ │ │ RawGestureDetector ← GestureDetector ← Semantics ←
flutter: ╎ │ │ DefaultSelectionStyle ← Builder ← MouseRegion ← Semantics ← ⋯
flutter: ╎ │ │ parentData: offset=Offset(8.0, 0.0) (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(40.0<=w<=784.0, 28.0<=h<=600.0)
flutter: ╎ │ │ size: Size(126.0, 28.0)
flutter: ╎ │ │ alignment: Alignment.center
flutter: ╎ │ │ textDirection: ltr
flutter: ╎ │ │ widthFactor: 1.0
flutter: ╎ │ │ heightFactor: 1.0
flutter: ╎ │ │
flutter: ╎ │ └─child: RenderParagraph#59bc2 relayoutBoundary=up13
flutter: ╎ │ │ creator: RichText ← Text ← Align ← Padding ← IconTheme ← Builder
flutter: ╎ │ │ ← Listener ← RawGestureDetector ← GestureDetector ← Semantics ←
flutter: ╎ │ │ DefaultSelectionStyle ← Builder ← ⋯
flutter: ╎ │ │ parentData: offset=Offset(0.0, 6.0) (can use size)
flutter: ╎ │ │ constraints: BoxConstraints(0.0<=w<=784.0, 0.0<=h<=600.0)
flutter: ╎ │ │ size: Size(126.0, 16.0)
flutter: ╎ │ │ textAlign: start
flutter: ╎ │ │ textDirection: ltr
flutter: ╎ │ │ softWrap: wrapping at box width
flutter: ╎ │ │ overflow: clip
flutter: ╎ │ │ locale: en_US
flutter: ╎ │ │ maxLines: unlimited
flutter: ╎ │ ╘═╦══ text ═══
flutter: ╎ │ ║ TextSpan:
flutter: ╎ │ ║ debugLabel: ((englishLike labelLarge 2014).merge(blackRedwoodCity
flutter: ╎ │ ║ labelLarge)).copyWith
flutter: ╎ │ ║ inherit: false
flutter: ╎ │ ║ color: MaterialColor(primary value: Color(0xff2196f3))
flutter: ╎ │ ║ family: .AppleSystemUIFont
flutter: ╎ │ ║ size: 14.0
flutter: ╎ │ ║ weight: 500
flutter: ╎ │ ║ baseline: alphabetic
flutter: ╎ │ ║ decoration: TextDecoration.none
flutter: ╎ │ ║ "Dump Render Tree"
flutter: ╎ │ ╚═══════════
flutter: ╎ └─child 2: RenderPointerListener#db4b5
flutter: ╎ creator: Listener ← Positioned ← PositionedDirectional ← Stack ←
flutter: ╎ _CupertinoBackGestureDetector<dynamic> ← DecoratedBox ←
flutter: ╎ DecoratedBoxTransition ← FractionalTranslation ←
flutter: ╎ SlideTransition ← FractionalTranslation ← SlideTransition ←
flutter: ╎ CupertinoPageTransition ← ⋯
flutter: ╎ parentData: top=0.0; bottom=0.0; left=0.0; width=20.0;
flutter: ╎ offset=Offset(0.0, 0.0) (can use size)
flutter: ╎ constraints: BoxConstraints(w=20.0, h=600.0)
flutter: ╎ size: Size(20.0, 600.0)
flutter: ╎ behavior: translucent
flutter: ╎ listeners: down
flutter: ╎
flutter: └╌no offstage children
flutter:
在 示例 5 的渲染樹中
-
RenderView或視窗大小限制了高達包括RenderPositionedBox#dc1df渲染物件的所有渲染物件的大小為螢幕大小。此示例將大小設定為Size(800.0, 600.0) -
每個渲染物件的
constraints屬性限制了每個子物件的大小。此屬性將BoxConstraints渲染物件作為值。從RenderSemanticsAnnotations#fe6b5開始,約束等於BoxConstraints(w=800.0, h=600.0)。 -
Center小部件在RenderSemanticsAnnotations#8187b子樹下建立了RenderPositionedBox#dc1df渲染物件。 -
此渲染物件下的每個子物件都具有最小值和最大值均為
BoxConstraints。例如,RenderSemanticsAnnotations#a0a4b使用BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)。 -
所有
RenderPhysicalShape#8e171渲染物件的子物件都使用BoxConstraints(BoxConstraints(56.0<=w<=800.0, 28.0<=h<=600.0))。 -
子
RenderPadding#8455f設定padding值為EdgeInsets(8.0, 0.0, 8.0, 0.0)。這為所有後續的此渲染物件的子物件設定了左右填充 8。現在它們具有新的約束:BoxConstraints(40.0<=w<=784.0, 28.0<=h<=600.0)。
此物件,creator 欄位告訴我們它可能是 TextButton 的定義的一部分,在其內容上設定了最小寬度 88 畫素和特定高度 36.0。這是 TextButton 類實現 Material Design 關於按鈕尺寸的指南。
RenderPositionedBox#80b8d 渲染物件再次放寬了約束以將文字居中對齊在按鈕內。RenderParagraph#59bc2 渲染物件根據其內容選擇其大小。如果你將大小追溯到樹,你將看到文字的大小如何影響形成按鈕的所有框的寬度。所有父物件都採用其子物件的尺寸來確定自身大小。
另一種注意到這一點的方法是檢視每個框描述中的 relayoutBoundary 屬性。這會告訴你多少個祖先依賴於此元素的尺寸。
例如,最內層的 RenderPositionedBox 行具有 relayoutBoundary=up13。這意味著當 Flutter 將 RenderConstrainedBox 標記為髒時,它也會將框的 13 個祖先標記為髒,因為新的尺寸可能會影響這些祖先。
要向轉儲新增資訊,如果你編寫自己的渲染物件,請重寫 debugFillProperties()。將 DiagnosticsProperty 物件新增到該方法的引數,然後呼叫超類方法。
列印層樹
#要除錯合成問題,請使用 debugDumpLayerTree()。
示例 6:呼叫 debugDumpLayerTree()
#
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: AppHome()));
}
class AppHome extends StatelessWidget {
const AppHome({super.key});
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: TextButton(
onPressed: () {
debugDumpLayerTree();
},
child: const Text('Dump Layer Tree'),
),
),
);
}
}
展開以檢視示例 6 的層樹輸出
flutter: TransformLayer#214da
flutter: │ owner: RenderView#ebaaf
flutter: │ creator: [root]
flutter: │ engine layer: TransformEngineLayer#535de
flutter: │ handles: 1
flutter: │ offset: Offset(0.0, 0.0)
flutter: │ transform:
flutter: │ [0] 1.0,0.0,0.0,0.0
flutter: │ [1] 0.0,1.0,0.0,0.0
flutter: │ [2] 0.0,0.0,1.0,0.0
flutter: │ [3] 0.0,0.0,0.0,1.0
flutter: │
flutter: ├─child 1: OffsetLayer#0f766
flutter: │ │ creator: RepaintBoundary ← _FocusInheritedScope ← Semantics ←
flutter: │ │ FocusScope ← PrimaryScrollController ← _ActionsScope ← Actions
flutter: │ │ ← Builder ← PageStorage ← Offstage ← _ModalScopeStatus ←
flutter: │ │ UnmanagedRestorationScope ← ⋯
flutter: │ │ engine layer: OffsetEngineLayer#1768d
flutter: │ │ handles: 2
flutter: │ │ offset: Offset(0.0, 0.0)
flutter: │ │
flutter: │ ├─child 1: PictureLayer#dd023
flutter: │ │ handles: 1
flutter: │ │ paint bounds: Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
flutter: │ │ picture: _NativePicture#36f94
flutter: │ │ raster cache hints: isComplex = false, willChange = false
flutter: │ │
flutter: │ └─child 2: OffsetLayer#4cfc8
flutter: │ │ creator: RepaintBoundary-[GlobalKey#bd5d9] ← IgnorePointer ←
flutter: │ │ AnimatedBuilder ← Stack ←
flutter: │ │ _CupertinoBackGestureDetector<dynamic> ← DecoratedBox ←
flutter: │ │ DecoratedBoxTransition ← FractionalTranslation ←
flutter: │ │ SlideTransition ← FractionalTranslation ← SlideTransition ←
flutter: │ │ CupertinoPageTransition ← ⋯
flutter: │ │ engine layer: OffsetEngineLayer#a1676
flutter: │ │ handles: 2
flutter: │ │ offset: Offset(0.0, 0.0)
flutter: │ │
flutter: │ └─child 1: PictureLayer#aee55
flutter: │ handles: 1
flutter: │ paint bounds: Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
flutter: │ picture: _NativePicture#e732d
flutter: │ raster cache hints: isComplex = false, willChange = false
flutter: │
flutter: └─child 2: PictureLayer#b16e5
flutter: handles: 1
flutter: paint bounds: Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
flutter: picture: _NativePicture#eef0a
flutter: raster cache hints: isComplex = false, willChange = false
flutter:
RepaintBoundary 小部件建立
-
渲染樹中的
RenderRepaintBoundaryRenderObject,如 示例 5 的結果所示。╎ └─child: RenderRepaintBoundary#f8f28 ╎ │ needs compositing ╎ │ creator: RepaintBoundary ← _FocusInheritedScope ← Semantics ← ╎ │ FocusScope ← PrimaryScrollController ← _ActionsScope ← Actions ╎ │ ← Builder ← PageStorage ← Offstage ← _ModalScopeStatus ← ╎ │ UnmanagedRestorationScope ← ⋯ ╎ │ parentData: <none> (can use size) ╎ │ constraints: BoxConstraints(w=800.0, h=600.0) ╎ │ layer: OffsetLayer#e73b7 ╎ │ size: Size(800.0, 600.0) ╎ │ metrics: 66.7% useful (1 bad vs 2 good) ╎ │ diagnosis: insufficient data to draw conclusion (less than five ╎ │ repaints) -
層樹中的新層,如 示例 6 的結果所示。
├─child 1: OffsetLayer#0f766 │ │ creator: RepaintBoundary ← _FocusInheritedScope ← Semantics ← │ │ FocusScope ← PrimaryScrollController ← _ActionsScope ← Actions │ │ ← Builder ← PageStorage ← Offstage ← _ModalScopeStatus ← │ │ UnmanagedRestorationScope ← ⋯ │ │ engine layer: OffsetEngineLayer#1768d │ │ handles: 2 │ │ offset: Offset(0.0, 0.0)
這減少了需要重新繪製的內容。
列印焦點樹
#要除錯焦點或快捷鍵問題,請使用 debugDumpFocusTree() 函式轉儲焦點樹。
debugDumpFocusTree() 方法返回應用的焦點樹。
焦點樹以以下方式標記節點
- 聚焦的節點標記為
PRIMARY FOCUS。 - 焦點節點的祖先標記為
IN FOCUS PATH。
如果你的應用使用 Focus 小部件,請使用 debugLabel 屬性簡化在樹中找到其焦點節點。
你還可以使用 debugFocusChanges 布林屬性啟用在焦點更改時進行廣泛的日誌記錄。
示例 7:呼叫 debugDumpFocusTree()
#
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: AppHome()));
}
class AppHome extends StatelessWidget {
const AppHome({super.key});
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: TextButton(
onPressed: () {
debugDumpFocusTree();
},
child: const Text('Dump Focus Tree'),
),
),
);
}
}
展開以檢視示例 7 的焦點樹
flutter: FocusManager#9d096
flutter: │ primaryFocus: FocusScopeNode#926dc(_ModalScopeState<dynamic>
flutter: │ Focus Scope [PRIMARY FOCUS])
flutter: │ primaryFocusCreator: FocusScope ← PrimaryScrollController ←
flutter: │ _ActionsScope ← Actions ← Builder ← PageStorage ← Offstage ←
flutter: │ _ModalScopeStatus ← UnmanagedRestorationScope ←
flutter: │ RestorationScope ← AnimatedBuilder ←
flutter: │ _ModalScope<dynamic>-[LabeledGlobalKey<_ModalScopeState<dynamic>>#bd53e]
flutter: │ ← Semantics ← _RenderTheaterMarker ← _EffectiveTickerMode ←
flutter: │ TickerMode ←
flutter: │ _OverlayEntryWidget-[LabeledGlobalKey<_OverlayEntryWidgetState>#89dd7]
flutter: │ ← _Theater ← Overlay-[LabeledGlobalKey<OverlayState>#52f82] ←
flutter: │ UnmanagedRestorationScope ← ⋯
flutter: │
flutter: └─rootScope: FocusScopeNode#f4205(Root Focus Scope [IN FOCUS PATH])
flutter: │ IN FOCUS PATH
flutter: │ focusedChildren: FocusScopeNode#a0d10(Navigator Scope [IN FOCUS
flutter: │ PATH])
flutter: │
flutter: └─Child 1: FocusNode#088ec([IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ NOT FOCUSABLE
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: FocusNode#85f70(Shortcuts [IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ NOT FOCUSABLE
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: FocusNode#f0c18(Shortcuts [IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ NOT FOCUSABLE
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: FocusNode#0749f(Shortcuts [IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ NOT FOCUSABLE
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: _FocusTraversalGroupNode#28990(FocusTraversalGroup [IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ NOT FOCUSABLE
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: FocusNode#5b515(Shortcuts [IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ NOT FOCUSABLE
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: FocusScopeNode#a0d10(Navigator Scope [IN FOCUS PATH])
flutter: │ context: FocusScope
flutter: │ IN FOCUS PATH
flutter: │ focusedChildren: FocusScopeNode#926dc(_ModalScopeState<dynamic>
flutter: │ Focus Scope [PRIMARY FOCUS])
flutter: │
flutter: └─Child 1: _FocusTraversalGroupNode#72c8a(FocusTraversalGroup [IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ NOT FOCUSABLE
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: FocusNode#eb709(Navigator [IN FOCUS PATH])
flutter: │ context: Focus
flutter: │ IN FOCUS PATH
flutter: │
flutter: └─Child 1: FocusScopeNode#926dc(_ModalScopeState<dynamic> Focus Scope [PRIMARY FOCUS])
flutter: │ context: FocusScope
flutter: │ PRIMARY FOCUS
flutter: │
flutter: └─Child 1: FocusNode#a6b74
flutter: context: Focus
flutter:
列印語義樹
#debugDumpSemanticsTree() 函式列印應用的語義樹。
語義樹呈現給系統輔助功能 API。要獲取語義樹的轉儲
- 使用系統輔助功能工具或
SemanticsDebugger啟用輔助功能 - 使用
debugDumpSemanticsTree()函式。
示例 8:呼叫 debugDumpSemanticsTree()
#
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(const MaterialApp(home: AppHome()));
}
class AppHome extends StatelessWidget {
const AppHome({super.key});
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Semantics(
button: true,
enabled: true,
label: 'Clickable text here!',
child: GestureDetector(
onTap: () {
debugDumpSemanticsTree();
if (kDebugMode) {
print('Clicked!');
}
},
child: const Text('Click Me!', style: TextStyle(fontSize: 56)),
),
),
),
);
}
}
展開以檢視示例 8 的語義樹
flutter: SemanticsNode#0
flutter: │ Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
flutter: │
flutter: └─SemanticsNode#1
flutter: │ Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
flutter: │ textDirection: ltr
flutter: │
flutter: └─SemanticsNode#2
flutter: │ Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
flutter: │ sortKey: OrdinalSortKey#824a2(order: 0.0)
flutter: │
flutter: └─SemanticsNode#3
flutter: │ Rect.fromLTRB(0.0, 0.0, 800.0, 600.0)
flutter: │ flags: scopesRoute
flutter: │
flutter: └─SemanticsNode#4
flutter: Rect.fromLTRB(278.0, 267.0, 522.0, 333.0)
flutter: actions: tap
flutter: flags: isButton, hasEnabledState, isEnabled
flutter: label:
flutter: "Clickable text here!
flutter: Click Me!"
flutter: textDirection: ltr
flutter:
flutter: Clicked!
列印事件時間
#如果你想知道你的事件相對於幀的開始和結束髮生的時間,你可以設定列印語句來記錄這些事件。要將幀的開始和結束列印到控制檯,請切換 debugPrintBeginFrameBanner 和 debugPrintEndFrameBanner。
示例 1 的列印幀橫幅日誌
I/flutter : ▄▄▄▄▄▄▄▄ Frame 12 30s 437.086ms ▄▄▄▄▄▄▄▄
I/flutter : Debug print: Am I performing this work more than once per frame?
I/flutter : Debug print: Am I performing this work more than once per frame?
I/flutter : ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
要列印導致當前幀被排程的呼叫堆疊,請使用 debugPrintScheduleFrameStacks 標誌。
除錯佈局問題
#要使用 GUI 除錯佈局問題,請將 debugPaintSizeEnabled 設定為 true。此標誌位於 rendering 庫中。你可以在任何時間啟用它,並且在 true 時會影響所有繪製。考慮將其新增到你的 void main() 入口點的頂部。
示例 9
#請參閱以下程式碼中的示例
// Add import to the Flutter rendering library.
import 'package:flutter/rendering.dart';
void main() {
debugPaintSizeEnabled = true;
runApp(const MyApp());
}
啟用後,Flutter 會在你的應用中顯示以下更改
- 以亮青色邊框顯示所有框。
- 將所有填充顯示為帶有褪色藍色填充和藍色邊框的框,圍繞子小部件。
- 以黃色箭頭顯示所有對齊定位。
- 當它們沒有子項時,以灰色顯示所有間距。
debugPaintBaselinesEnabled 標誌對具有基線的物件執行類似操作。該應用以亮綠色顯示字母字元的基線,以橙色顯示錶意文字字元的基線。字母字元“位於”字母基線上,但該基線“穿過”CJK 字元的底部。Flutter 將表意文字基線定位在文字行的最底部。
debugPaintPointersEnabled 標誌開啟一種特殊模式,以青色突出顯示您點選的任何物件。這可以幫助您確定物件是否未能命中測試。如果物件落在其父級的邊界之外,則可能發生這種情況,因此一開始未將其視為命中測試的物件。
如果您正在嘗試除錯合成層,請考慮使用以下標誌。
-
使用
debugPaintLayerBordersEnabled標誌查詢每個層的邊界。此標誌導致用橙色勾勒出每個層的邊界。 -
使用
debugRepaintRainbowEnabled標誌顯示重新繪製的層。每當一層重新繪製時,它都會覆蓋一層旋轉的顏色集。
Flutter 框架中以 debug... 開頭的任何函式或方法僅在 除錯模式下工作。
除錯動畫問題
#將 timeDilation 變數(來自 scheduler 庫)設定為大於 1.0 的數字,例如 50.0。最好僅在應用啟動時設定一次。如果您在動畫執行時更改它,尤其是如果降低它,則框架可能會觀察到時間倒流,這可能會導致斷言並通常干擾您的工作。
除錯效能問題
#Flutter 提供了各種頂級屬性和函式,以幫助您在開發週期的各個階段除錯應用。要使用這些功能,請以除錯模式編譯您的應用。
以下列表突出顯示了來自 rendering 庫的一些標誌和一個函式,用於除錯效能問題。
-
debugDumpRenderTree() -
要在控制檯中轉儲渲染樹,請在非佈局或重新繪製階段呼叫此函式。
要設定這些標誌,請
- 編輯框架程式碼。
- 匯入模組,在您的
main()函式中設定值,然後熱過載。
-
debugPaintLayerBordersEnabled -
要顯示每個層的邊界,請將此屬性設定為
true。設定後,每個層會在其邊界周圍繪製一個框。 -
debugRepaintRainbowEnabled -
要顯示圍繞每個小部件的彩色邊框,請將此屬性設定為
true。這些邊框會隨著應用使用者的滾動而改變顏色。要設定此標誌,請將debugRepaintRainbowEnabled = true;新增為應用中的頂級屬性。如果設定此標誌後任何靜態小部件旋轉顏色,請考慮向這些區域新增重新繪製邊界。 -
debugPrintMarkNeedsLayoutStacks -
要確定您的應用是否建立了比預期更多的佈局,請將此屬性設定為
true。此佈局問題可能發生在時間軸上、配置檔案中或佈局方法內的print語句中。設定後,框架會將堆疊跟蹤輸出到控制檯,以解釋您的應用為何將每個渲染物件標記為需要佈局。 -
debugPrintMarkNeedsPaintStacks -
要確定您的應用是否繪製了比預期更多的佈局,請將此屬性設定為
true。
您還可以按需生成堆疊跟蹤。要列印您自己的堆疊跟蹤,請將 debugPrintStack() 函式新增到您的應用中。
跟蹤 Dart 程式碼效能
#要執行自定義效能跟蹤並測量 Dart 程式碼的任意片段的牆面時間或 CPU 時間,請使用 dart:developer Timeline 工具。
開啟您的原始碼。
-
使用
Timeline方法包裝您想要度量的程式碼。dartimport 'dart:developer'; void main() { Timeline.startSync('interesting function'); // iWonderHowLongThisTakes(); Timeline.finishSync(); } -
在連線到您的應用時,開啟 DevTools 的 時間軸事件選項卡。
-
在 效能設定中選擇 Dart 記錄選項。
執行您想要度量的函式。
為了確保執行時效能特徵與最終產品密切匹配,請以 profile 模式執行您的應用。
新增效能疊加層
#要在您的程式碼中啟用 PerformanceOverlay 小部件,請將 showPerformanceOverlay 屬性設定為 true,在 MaterialApp、CupertinoApp 或 WidgetsApp 建構函式中。
示例 10
#import 'package:flutter/material.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
showPerformanceOverlay: true,
title: 'My Awesome App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: const MyHomePage(title: 'My Awesome App'),
);
}
}
(如果您沒有使用 MaterialApp、CupertinoApp 或 WidgetsApp,則可以透過將您的應用包裝在堆疊中並使用透過呼叫 PerformanceOverlay.allEnabled() 建立的小部件放置在堆疊上,獲得相同效果。)
要了解如何解釋疊加層中的圖形,請檢視 The performance overlay 在 Profiling Flutter performance 中。
新增小部件對齊網格
#要向您的應用新增一個 Material Design 基線網格 疊加層以幫助驗證對齊方式,請在 MaterialApp 建構函式中新增 debugShowMaterialGrid 引數。
要向非 Material 應用新增疊加層,請新增一個 GridPaper 小部件。