Dart 分析器
在運行(xíng)應用程序前,請(qǐng)運行(xíng)flutter analyze測試你的代碼。這(zhè)個工(gōng)具(它是dartanalyzer工(gōng)具的一(yī)個包裝)将分析你的代碼并幫助你發現可(kě)能(néng)的錯誤。 如(rú)果你使用IntelliJ的Flutter插件,那(nà)麽已經自(zì)動啓用了(le)。
Dart分析器大量使用了(le)代碼中的類型注釋來幫助追蹤問(wèn)題。我們鼓勵您在任何地(dì)方使用它們(避免var、無類型的參數(shù)、無類型的列表文字等),因為(wèi)這(zhè)是追蹤問(wèn)題的最快(kuài)的方式。
Dart Observatory (語句級的單步調試和(hé)分析器)
如(rú)果您使用flutter run啓動應用程序,那(nà)麽當它運行(xíng)時(shí),您可(kě)以打開(kāi)Observatory URL的Web頁面(例如(rú)Observatory監聽http://127.0.0.1:8100/), 直接使用語句級單步調試器連接到您的應用程序。如(rú)果您使用的是IntelliJ,則還可(kě)以使用其內(nèi)置的調試器來調試您的應用程序。
Observatory 同時(shí)支持分析、檢查堆等。有關Observatory的更多信息請(qǐng)參考Observatory 文檔.
如(rú)果您使用Observatory進行(xíng)分析,請(qǐng)确保通(tōng)過--profile選項來運行(xíng)flutter run命令來運行(xíng)應用程序。 否則,配置文件中将出現的主要(yào)問(wèn)題将是調試斷言,以驗證框架的各種不變量(請(qǐng)參閱下(xià)面的“調試模式斷言”)。
window() 聲明(míng)
當使用Dart Observatory(或另一(yī)個Dart調試器,例如(rú)IntelliJ IDE中的調試器)時(shí),可(kě)以使用該window()語句插入編程式斷點。要(yào)使用這(zhè)個,你必須添加import 'dart:developer';到相關文件頂部。
window()語句采用一(yī)個可(kě)選when參數(shù),您可(kě)以指定該參數(shù)僅在特定條件為(wèi)真時(shí)中斷,如(rú)下(xià)所示:
void someFunction(double offset) {
window(when: offset > 30.0);
// ...
}
print、debugPrint、flutter logs
Dart print()功能(néng)将輸出到系統控制台,您可(kě)以使用flutter logs了(le)查看(kàn)它(基本上(shàng)是一(yī)個包裝adb logcat)。
如(rú)果你一(yī)次輸出太多,那(nà)麽Android有時(shí)會丢棄一(yī)些日志行(xíng)。為(wèi)了(le)避免這(zhè)種情況,您可(kě)以使用Flutter的foundation庫中的debugPrint()。 這(zhè)是一(yī)個封裝print,它将輸出限制在一(yī)個級别,避免被Android內(nèi)核丢棄。
Flutter框架中的許多類都(dōu)有toString實現。按照慣例,這(zhè)些輸出通(tōng)常包括對象的runtimeType單行(xíng)輸出,通(tōng)常在表單中ClassName(more information about this instance…)。 樹(shù)中使用的一(yī)些類也具有toStringDeep,從(cóng)該點返回整個子樹(shù)的多行(xíng)描述。已一(yī)些具有詳細信息toString的類會實現一(yī)個toStringShort,它隻返回對象的類型或其他(tā)非常簡短的(一(yī)個或兩個單詞)描述。
調試模式斷言
在開(kāi)發過程中,強烈建議(yì)您使用Flutter的“調試”模式,有時(shí)也稱為(wèi)“checked”模式(譯者語:Dart2.0後“checked”被廢除,可(kě)以使用“strong” mode)。 如(rú)果您使用flutter run運行(xíng)程序。在這(zhè)種模式下(xià),Dart assert語句被啓用,并且Flutter框架使用它來執行(xíng)許多運行(xíng)時(shí)檢查來驗證是否違反一(yī)些不可(kě)變的規則。
當一(yī)個不可(kě)變的規則被違反時(shí),它被報告給控制台,并帶有一(yī)些上(shàng)下(xià)文信息來幫助追蹤問(wèn)題的根源。
要(yào)關閉調試模式并使用發布模式,請(qǐng)使用flutter run --release運行(xíng)您的應用程序。 這(zhè)也關閉了(le)Observatory調試器。一(yī)個中間(jiān)模式可(kě)以關閉除Observatory之外(wài)所有調試輔助工(gōng)具的,稱為(wèi)“profile mode”,用--profile替代--release即可(kě)。
調試應用程序層
Flutter框架的每一(yī)層都(dōu)提供了(le)将其當前狀态或事件轉儲(dump)到控制台(使用debugPrint)的功能(néng)。
Widget 層
要(yào)轉儲Widgets庫的狀态,請(qǐng)調用debugDumpApp()。 隻要(yào)應用程序已經構建了(le)至少(shǎo)一(yī)次(即在調用build()之後的任何時(shí)間(jiān)),您可(kě)以在應用程序未處于構建階段(即,不在build()方法內(nèi)調用 )的任何時(shí)間(jiān)調用此方法(在調用runApp()之後)。
如(rú), 這(zhè)個應用程序:
import 'package:flutter/material.dart';
void main() {
runApp(
new MaterialApp(
home: new AppHome(),
),
);
}
class AppHome extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Material(
child: new Center(
child: new FlatButton(
onPressed: () {
debugDumpApp();
},
child: new Text('Dump App'),
),
),
);
}
}
…會輸出這(zhè)樣的內(nèi)容(精确的細節會根據框架的版本、設備的大小等等而變化):
I/flutter ( 6559): WidgetsFlutterBinding - CHECKED MODE
I/flutter ( 6559): RenderObjectToWidgetAdapter
I/flutter ( 6559): └MaterialApp(state: _MaterialAppState(1009803148))
I/flutter ( 6559): └ScrollConfiguration()
I/flutter ( 6559): └AnimatedTheme(duration: 200ms; state: _AnimatedThemeState(543295893; ticker inactive; ThemeDataTween(ThemeData(Brightness.light Color(0xff2196f3) etc...) → null)))
I/flutter ( 6559): └Theme(ThemeData(Brightness.light Color(0xff2196f3) etc...))
I/flutter ( 6559): └WidgetsApp([GlobalObjectKey _MaterialAppState(1009803148)]; state: _WidgetsAppState(552902158))
I/flutter ( 6559): └CheckedModeBanner()
I/flutter ( 6559): └Banner()
I/flutter ( 6559): └CustomPaint(renderObject: RenderCustomPaint)
I/flutter ( 6559): └DefaultTextStyle(inherit: true; color: Color(0xd0ff0000); family: "monospace"; size: 48.0; weight: 900; decoration: double Color(0xffffff00) TextDecoration.underline)
I/flutter ( 6559): └MediaQuery(MediaQueryData(size: Size(411.4, 683.4), devicePixelRatio: 2.625, textScaleFactor: 1.0, padding: EdgeInsets(0.0, 24.0, 0.0, 0.0)))
I/flutter ( 6559): └LocaleQuery(null)
I/flutter ( 6559): └Title(color: Color(0xff2196f3))
I/flutter ( 6559): └Navigator([GlobalObjectKey
I/flutter ( 6559): └Listener(listeners: down, up, cancel; behavior: defer-to-child; renderObject: RenderPointerListener)
I/flutter ( 6559): └AbsorbPointer(renderObject: RenderAbsorbPointer)
I/flutter ( 6559): └Focus([GlobalKey 489139594]; state: _FocusState(739584448))
I/flutter ( 6559): └Semantics(container: true; renderObject: RenderSemanticsAnnotations)
I/flutter ( 6559): └_FocusScope(this scope has focus; focused subscope: [GlobalObjectKey MaterialPageRoute
I/flutter ( 6559): └Overlay([GlobalKey 199833992]; state: OverlayState(619367313; entries: [OverlayEntry@248818791(opaque: false; maintainState: false), OverlayEntry@837336156(opaque: false; maintainState: true)]))
I/flutter ( 6559): └_Theatre(renderObject: _RenderTheatre)
I/flutter ( 6559): └Stack(renderObject: RenderStack)
I/flutter ( 6559): ├_OverlayEntry([GlobalKey 612888877]; state: _OverlayEntryState(739137453))
I/flutter ( 6559): │└IgnorePointer(ignoring: false; renderObject: RenderIgnorePointer)
I/flutter ( 6559): │ └ModalBarrier()
I/flutter ( 6559): │ └Semantics(container: true; renderObject: RenderSemanticsAnnotations)
I/flutter ( 6559): │ └GestureDetector()
I/flutter ( 6559): │ └RawGestureDetector(state: RawGestureDetectorState(39068508; gestures: tap; behavior: opaque))
I/flutter ( 6559): │ └_GestureSemantics(renderObject: RenderSemanticsGestureHandler)
I/flutter ( 6559): │ └Listener(listeners: down; behavior: opaque; renderObject: RenderPointerListener)
I/flutter ( 6559): │ └ConstrainedBox(BoxConstraints(biggest); renderObject: RenderConstrainedBox)
I/flutter ( 6559): └_OverlayEntry([GlobalKey 727622716]; state: _OverlayEntryState(279971240))
I/flutter ( 6559): └_ModalScope([GlobalKey 816151164]; state: _ModalScopeState(875510645))
I/flutter ( 6559): └Focus([GlobalObjectKey MaterialPageRoute
I/flutter ( 6559): └Semantics(container: true; renderObject: RenderSemanticsAnnotations)
I/flutter ( 6559): └_FocusScope(this scope has focus)
I/flutter ( 6559): └Offstage(offstage: false; renderObject: RenderOffstage)
I/flutter ( 6559): └IgnorePointer(ignoring: false; renderObject: RenderIgnorePointer)
I/flutter ( 6559): └_MountainViewPageTransition(animation: AnimationController(⏭ 1.000; paused; for MaterialPageRoute
I/flutter ( 6559): └SlideTransition(animation: AnimationController(⏭ 1.000; paused; for MaterialPageRoute
I/flutter ( 6559): └FractionalTranslation(renderObject: RenderFractionalTranslation)
I/flutter ( 6559): └RepaintBoundary(renderObject: RenderRepaintBoundary)
I/flutter ( 6559): └PageStorage([GlobalKey 619728754])
I/flutter ( 6559): └_ModalScopeStatus(active)
I/flutter ( 6559): └AppHome()
I/flutter ( 6559): └Material(MaterialType.canvas; elevation: 0; state: _MaterialState(780114997))
I/flutter ( 6559): └AnimatedContainer(duration: 200ms; has background; state: _AnimatedContainerState(616063822; ticker inactive; has background))
I/flutter ( 6559): └Container(bg: BoxDecoration())
I/flutter ( 6559): └DecoratedBox(renderObject: RenderDecoratedBox)
I/flutter ( 6559): └Container(bg: BoxDecoration(backgroundColor: Color(0xfffafafa)))
I/flutter ( 6559): └DecoratedBox(renderObject: RenderDecoratedBox)
I/flutter ( 6559): └NotificationListener
I/flutter ( 6559): └_InkFeature([GlobalKey ink renderer]; renderObject: _RenderInkFeatures)
I/flutter ( 6559): └AnimatedDefaultTextStyle(duration: 200ms; inherit: false; color: Color(0xdd000000); family: "Roboto"; size: 14.0; weight: 400; baseline: alphabetic; state: _AnimatedDefaultTextStyleState(427742350; ticker inactive))
I/flutter ( 6559): └DefaultTextStyle(inherit: false; color: Color(0xdd000000); family: "Roboto"; size: 14.0; weight: 400; baseline: alphabetic)
I/flutter ( 6559): └Center(alignment: Alignment.center; renderObject: RenderPositionedBox)
I/flutter ( 6559): └FlatButton()
I/flutter ( 6559): └MaterialButton(state: _MaterialButtonState(398724090))
I/flutter ( 6559): └ConstrainedBox(BoxConstraints(88.0<=w<=Infinity, h=36.0); renderObject: RenderConstrainedBox relayoutBoundary=up1)
I/flutter ( 6559): └AnimatedDefaultTextStyle(duration: 200ms; inherit: false; color: Color(0xdd000000); family: "Roboto"; size: 14.0; weight: 500; baseline: alphabetic; state: _AnimatedDefaultTextStyleState(315134664; ticker inactive))
I/flutter ( 6559): └DefaultTextStyle(inherit: false; color: Color(0xdd000000); family: "Roboto"; size: 14.0; weight: 500; baseline: alphabetic)
I/flutter ( 6559): └IconTheme(color: Color(0xdd000000))
I/flutter ( 6559): └InkWell(state: _InkResponseState
I/flutter ( 6559): └GestureDetector()
I/flutter ( 6559): └RawGestureDetector(state: RawGestureDetectorState(175370983; gestures: tap; behavior: opaque))
I/flutter ( 6559): └_GestureSemantics(renderObject: RenderSemanticsGestureHandler relayoutBoundary=up2)
I/flutter ( 6559): └Listener(listeners: down; behavior: opaque; renderObject: RenderPointerListener relayoutBoundary=up3)
I/flutter ( 6559): └Container(padding: EdgeInsets(16.0, 0.0, 16.0, 0.0))
I/flutter ( 6559): └Padding(renderObject: RenderPadding relayoutBoundary=up4)
I/flutter ( 6559): └Center(alignment: Alignment.center; widthFactor: 1.0; renderObject: RenderPositionedBox relayoutBoundary=up5)
I/flutter ( 6559): └Text("Dump App")
I/flutter ( 6559): └RichText(renderObject: RenderParagraph relayoutBoundary=up6)
這(zhè)是一(yī)個“扁平化”的樹(shù),顯示了(le)通(tōng)過各種構建函數(shù)投影的所有widget(如(rú)果你在widget樹(shù)的根中調用toStringDeepwidget,這(zhè)是你獲得的樹(shù))。 你會看(kàn)到很(hěn)多在你的應用源代碼中沒有出現的widget,因為(wèi)它們被框架的widget的build()函數(shù)插入的。例如(rú),InkFeature是Material widget的一(yī)個實現細節 。
由于debugDumpApp()當按鈕從(cóng)被按下(xià)變為(wèi)被釋放時(shí)被調用,FlatButton對象同時(shí)調用setState(),所以并因此将自(zì)己标記為(wèi)髒。 這(zhè)就是為(wèi)什麽如(rú)果你看(kàn)轉儲,你會看(kàn)到特定的對象标記為(wèi)“dirty”。您還可(kě)以查看(kàn)已注冊了(le)哪些手勢監聽器; 在這(zhè)種情況下(xià),一(yī)個單一(yī)的GestureDetector被列出,并且監聽“tap”手勢(“tap”是TapGestureDetector的toStringShort函數(shù)輸出的)
如(rú)果您編寫自(zì)己的widget,則可(kě)以通(tōng)過覆蓋debugFillProperties()來添加信息。 将DiagnosticsProperty對象作(zuò)為(wèi)方法參數(shù),并調用父類方法。 該函數(shù)是該toString方法用來填充小部件描述信息的。
渲染層
如(rú)果您嘗試調試布局問(wèn)題,那(nà)麽Widgets層的樹(shù)可(kě)能(néng)不夠詳細。在這(zhè)種情況下(xià),您可(kě)以通(tōng)過調用debugDumpRenderTree()轉儲渲染樹(shù)。 正如(rú)debugDumpApp(),除布局或繪制階段外(wài),您可(kě)以随時(shí)調用此函數(shù)。作(zuò)為(wèi)一(yī)般規則,從(cóng)frame 回調 或事件處理器中調用它是最佳解決方案。
要(yào)調用debugDumpRenderTree(),您需要(yào)添加import'package:flutter/rendering.dart';到您的源文件。
上(shàng)面這(zhè)個小例子的輸出結果如(rú)下(xià)所示:
I/flutter ( 6559): RenderView
I/flutter ( 6559): │ debug mode enabled - android
I/flutter ( 6559): │ window size: Size(1080.0, 1794.0) (in physical pixels)
I/flutter ( 6559): │ device pixel ratio: 2.625 (physical pixels per logical pixel)
I/flutter ( 6559): │ configuration: Size(411.4, 683.4) at 2.625x (in logical pixels)
I/flutter ( 6559): │
I/flutter ( 6559): └─child: RenderCustomPaint
I/flutter ( 6559): │ creator: CustomPaint ← Banner ← CheckedModeBanner ←
I/flutter ( 6559): │ WidgetsApp-[GlobalObjectKey _MaterialAppState(1009803148)] ←
I/flutter ( 6559): │ Theme ← AnimatedTheme ← ScrollConfiguration ← MaterialApp ←
I/flutter ( 6559): │ [root]
I/flutter ( 6559): │ parentData:
I/flutter ( 6559): │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): │ size: Size(411.4, 683.4)
I/flutter ( 6559): │
I/flutter ( 6559): └─child: RenderPointerListener
I/flutter ( 6559): │ creator: Listener ← Navigator-[GlobalObjectKey
I/flutter ( 6559): │ _WidgetsAppState(552902158)] ← Title ← LocaleQuery ← MediaQuery
I/flutter ( 6559): │ ← DefaultTextStyle ← CustomPaint ← Banner ← CheckedModeBanner ←
I/flutter ( 6559): │ WidgetsApp-[GlobalObjectKey _MaterialAppState(1009803148)] ←
I/flutter ( 6559): │ Theme ← AnimatedTheme ← ⋯
I/flutter ( 6559): │ parentData:
I/flutter ( 6559): │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): │ size: Size(411.4, 683.4)
I/flutter ( 6559): │ behavior: defer-to-child
I/flutter ( 6559): │ listeners: down, up, cancel
I/flutter ( 6559): │
I/flutter ( 6559): └─child: RenderAbsorbPointer
I/flutter ( 6559): │ creator: AbsorbPointer ← Listener ←
I/flutter ( 6559): │ Navigator-[GlobalObjectKey
I/flutter ( 6559): │ _WidgetsAppState(552902158)] ← Title ← LocaleQuery ← MediaQuery
I/flutter ( 6559): │ ← DefaultTextStyle ← CustomPaint ← Banner ← CheckedModeBanner ←
I/flutter ( 6559): │ WidgetsApp-[GlobalObjectKey _MaterialAppState(1009803148)] ←
I/flutter ( 6559): │ Theme ← ⋯
I/flutter ( 6559): │ parentData:
I/flutter ( 6559): │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): │ size: Size(411.4, 683.4)
I/flutter ( 6559): │ absorbing: false
I/flutter ( 6559): │
I/flutter ( 6559): └─child: RenderSemanticsAnnotations
I/flutter ( 6559): │ creator: Semantics ← Focus-[GlobalKey 489139594] ← AbsorbPointer
I/flutter ( 6559): │ ← Listener ← Navigator-[GlobalObjectKey
I/flutter ( 6559): │ _WidgetsAppState(552902158)] ← Title ← LocaleQuery ← MediaQuery
I/flutter ( 6559): │ ← DefaultTextStyle ← CustomPaint ← Banner ← CheckedModeBanner ←
I/flutter ( 6559): │ ⋯
I/flutter ( 6559): │ parentData:
I/flutter ( 6559): │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): │ size: Size(411.4, 683.4)
I/flutter ( 6559): │
I/flutter ( 6559): └─child: _RenderTheatre
I/flutter ( 6559): │ creator: _Theatre ← Overlay-[GlobalKey 199833992] ← _FocusScope ←
I/flutter ( 6559): │ Semantics ← Focus-[GlobalKey 489139594] ← AbsorbPointer ←
I/flutter ( 6559): │ Listener ← Navigator-[GlobalObjectKey
I/flutter ( 6559): │ _WidgetsAppState(552902158)] ← Title ← LocaleQuery ← MediaQuery
I/flutter ( 6559): │ ← DefaultTextStyle ← ⋯
I/flutter ( 6559): │ parentData:
I/flutter ( 6559): │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): │ size: Size(411.4, 683.4)
I/flutter ( 6559): │
I/flutter ( 6559): ├─onstage: RenderStack
I/flutter ( 6559): ╎ │ creator: Stack ← _Theatre ← Overlay-[GlobalKey 199833992] ←
I/flutter ( 6559): ╎ │ _FocusScope ← Semantics ← Focus-[GlobalKey 489139594] ←
I/flutter ( 6559): ╎ │ AbsorbPointer ← Listener ←
I/flutter ( 6559): ╎ │ Navigator-[GlobalObjectKey
I/flutter ( 6559): ╎ │ _WidgetsAppState(552902158)] ← Title ← LocaleQuery ← MediaQuery
I/flutter ( 6559): ╎ │ ← ⋯
I/flutter ( 6559): ╎ │ parentData: not positioned; offset=Offset(0.0, 0.0)
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ ├─child 1: RenderIgnorePointer
I/flutter ( 6559): ╎ │ │ creator: IgnorePointer ← _OverlayEntry-[GlobalKey 612888877] ←
I/flutter ( 6559): ╎ │ │ Stack ← _Theatre ← Overlay-[GlobalKey 199833992] ← _FocusScope
I/flutter ( 6559): ╎ │ │ ← Semantics ← Focus-[GlobalKey 489139594] ← AbsorbPointer ←
I/flutter ( 6559): ╎ │ │ Listener ← Navigator-[GlobalObjectKey
I/flutter ( 6559): ╎ │ │ _WidgetsAppState(552902158)] ← Title ← ⋯
I/flutter ( 6559): ╎ │ │ parentData: not positioned; offset=Offset(0.0, 0.0)
I/flutter ( 6559): ╎ │ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ │ ignoring: false
I/flutter ( 6559): ╎ │ │ ignoringSemantics: implicitly false
I/flutter ( 6559): ╎ │ │
I/flutter ( 6559): ╎ │ └─child: RenderSemanticsAnnotations
I/flutter ( 6559): ╎ │ │ creator: Semantics ← ModalBarrier ← IgnorePointer ←
I/flutter ( 6559): ╎ │ │ _OverlayEntry-[GlobalKey 612888877] ← Stack ← _Theatre ←
I/flutter ( 6559): ╎ │ │ Overlay-[GlobalKey 199833992] ← _FocusScope ← Semantics ←
I/flutter ( 6559): ╎ │ │ Focus-[GlobalKey 489139594] ← AbsorbPointer ← Listener ← ⋯
I/flutter ( 6559): ╎ │ │ parentData:
I/flutter ( 6559): ╎ │ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ │
I/flutter ( 6559): ╎ │ └─child: RenderSemanticsGestureHandler
I/flutter ( 6559): ╎ │ │ creator: _GestureSemantics ← RawGestureDetector ← GestureDetector
I/flutter ( 6559): ╎ │ │ ← Semantics ← ModalBarrier ← IgnorePointer ←
I/flutter ( 6559): ╎ │ │ _OverlayEntry-[GlobalKey 612888877] ← Stack ← _Theatre ←
I/flutter ( 6559): ╎ │ │ Overlay-[GlobalKey 199833992] ← _FocusScope ← Semantics ← ⋯
I/flutter ( 6559): ╎ │ │ parentData:
I/flutter ( 6559): ╎ │ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ │
I/flutter ( 6559): ╎ │ └─child: RenderPointerListener
I/flutter ( 6559): ╎ │ │ creator: Listener ← _GestureSemantics ← RawGestureDetector ←
I/flutter ( 6559): ╎ │ │ GestureDetector ← Semantics ← ModalBarrier ← IgnorePointer ←
I/flutter ( 6559): ╎ │ │ _OverlayEntry-[GlobalKey 612888877] ← Stack ← _Theatre ←
I/flutter ( 6559): ╎ │ │ Overlay-[GlobalKey 199833992] ← _FocusScope ← ⋯
I/flutter ( 6559): ╎ │ │ parentData:
I/flutter ( 6559): ╎ │ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ │ behavior: opaque
I/flutter ( 6559): ╎ │ │ listeners: down
I/flutter ( 6559): ╎ │ │
I/flutter ( 6559): ╎ │ └─child: RenderConstrainedBox
I/flutter ( 6559): ╎ │ creator: ConstrainedBox ← Listener ← _GestureSemantics ←
I/flutter ( 6559): ╎ │ RawGestureDetector ← GestureDetector ← Semantics ← ModalBarrier
I/flutter ( 6559): ╎ │ ← IgnorePointer ← _OverlayEntry-[GlobalKey 612888877] ← Stack ←
I/flutter ( 6559): ╎ │ _Theatre ← Overlay-[GlobalKey 199833992] ← ⋯
I/flutter ( 6559): ╎ │ parentData:
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ additionalConstraints: BoxConstraints(biggest)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child 2: RenderSemanticsAnnotations
I/flutter ( 6559): ╎ │ creator: Semantics ← Focus-[GlobalObjectKey
I/flutter ( 6559): ╎ │ MaterialPageRoute
I/flutter ( 6559): ╎ │ 816151164] ← _OverlayEntry-[GlobalKey 727622716] ← Stack ←
I/flutter ( 6559): ╎ │ _Theatre ← Overlay-[GlobalKey 199833992] ← _FocusScope ←
I/flutter ( 6559): ╎ │ Semantics ← Focus-[GlobalKey 489139594] ← AbsorbPointer ←
I/flutter ( 6559): ╎ │ Listener ← ⋯
I/flutter ( 6559): ╎ │ parentData: not positioned; offset=Offset(0.0, 0.0)
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderOffstage
I/flutter ( 6559): ╎ │ creator: Offstage ← _FocusScope ← Semantics ←
I/flutter ( 6559): ╎ │ Focus-[GlobalObjectKey MaterialPageRoute
I/flutter ( 6559): ╎ │ _ModalScope-[GlobalKey 816151164] ← _OverlayEntry-[GlobalKey
I/flutter ( 6559): ╎ │ 727622716] ← Stack ← _Theatre ← Overlay-[GlobalKey 199833992] ←
I/flutter ( 6559): ╎ │ _FocusScope ← Semantics ← Focus-[GlobalKey 489139594] ← ⋯
I/flutter ( 6559): ╎ │ parentData:
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ offstage: false
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderIgnorePointer
I/flutter ( 6559): ╎ │ creator: IgnorePointer ← Offstage ← _FocusScope ← Semantics ←
I/flutter ( 6559): ╎ │ Focus-[GlobalObjectKey MaterialPageRoute
I/flutter ( 6559): ╎ │ _ModalScope-[GlobalKey 816151164] ← _OverlayEntry-[GlobalKey
I/flutter ( 6559): ╎ │ 727622716] ← Stack ← _Theatre ← Overlay-[GlobalKey 199833992] ←
I/flutter ( 6559): ╎ │ _FocusScope ← Semantics ← ⋯
I/flutter ( 6559): ╎ │ parentData:
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ ignoring: false
I/flutter ( 6559): ╎ │ ignoringSemantics: implicitly false
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderFractionalTranslation
I/flutter ( 6559): ╎ │ creator: FractionalTranslation ← SlideTransition ←
I/flutter ( 6559): ╎ │ _MountainViewPageTransition ← IgnorePointer ← Offstage ←
I/flutter ( 6559): ╎ │ _FocusScope ← Semantics ← Focus-[GlobalObjectKey
I/flutter ( 6559): ╎ │ MaterialPageRoute
I/flutter ( 6559): ╎ │ 816151164] ← _OverlayEntry-[GlobalKey 727622716] ← Stack ←
I/flutter ( 6559): ╎ │ _Theatre ← ⋯
I/flutter ( 6559): ╎ │ parentData:
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ translation: Offset(0.0, 0.0)
I/flutter ( 6559): ╎ │ transformHitTests: true
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderRepaintBoundary
I/flutter ( 6559): ╎ │ creator: RepaintBoundary ← FractionalTranslation ←
I/flutter ( 6559): ╎ │ SlideTransition ← _MountainViewPageTransition ← IgnorePointer ←
I/flutter ( 6559): ╎ │ Offstage ← _FocusScope ← Semantics ← Focus-[GlobalObjectKey
I/flutter ( 6559): ╎ │ MaterialPageRoute
I/flutter ( 6559): ╎ │ 816151164] ← _OverlayEntry-[GlobalKey 727622716] ← Stack ← ⋯
I/flutter ( 6559): ╎ │ parentData:
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ metrics: 83.3% useful (1 bad vs 5 good)
I/flutter ( 6559): ╎ │ diagnosis: this is a useful repaint boundary and should be kept
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderDecoratedBox
I/flutter ( 6559): ╎ │ creator: DecoratedBox ← Container ← AnimatedContainer ← Material
I/flutter ( 6559): ╎ │ ← AppHome ← _ModalScopeStatus ← PageStorage-[GlobalKey
I/flutter ( 6559): ╎ │ 619728754] ← RepaintBoundary ← FractionalTranslation ←
I/flutter ( 6559): ╎ │ SlideTransition ← _MountainViewPageTransition ← IgnorePointer ←
I/flutter ( 6559): ╎ │ ⋯
I/flutter ( 6559): ╎ │ parentData:
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ decoration:
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ │ configuration: ImageConfiguration(bundle:
I/flutter ( 6559): ╎ │ PlatformAssetBundle@367106502(), devicePixelRatio: 2.625,
I/flutter ( 6559): ╎ │ platform: android)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderDecoratedBox
I/flutter ( 6559): ╎ │ creator: DecoratedBox ← Container ← DecoratedBox ← Container ←
I/flutter ( 6559): ╎ │ AnimatedContainer ← Material ← AppHome ← _ModalScopeStatus ←
I/flutter ( 6559): ╎ │ PageStorage-[GlobalKey 619728754] ← RepaintBoundary ←
I/flutter ( 6559): ╎ │ FractionalTranslation ← SlideTransition ← ⋯
I/flutter ( 6559): ╎ │ parentData:
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ decoration:
I/flutter ( 6559): ╎ │ backgroundColor: Color(0xfffafafa)
I/flutter ( 6559): ╎ │ configuration: ImageConfiguration(bundle:
I/flutter ( 6559): ╎ │ PlatformAssetBundle@367106502(), devicePixelRatio: 2.625,
I/flutter ( 6559): ╎ │ platform: android)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: _RenderInkFeatures
I/flutter ( 6559): ╎ │ creator: _InkFeature-[GlobalKey ink renderer] ←
I/flutter ( 6559): ╎ │ NotificationListener
I/flutter ( 6559): ╎ │ ← Container ← DecoratedBox ← Container ← AnimatedContainer ←
I/flutter ( 6559): ╎ │ Material ← AppHome ← _ModalScopeStatus ← PageStorage-[GlobalKey
I/flutter ( 6559): ╎ │ 619728754] ← RepaintBoundary ← ⋯
I/flutter ( 6559): ╎ │ parentData:
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderPositionedBox
I/flutter ( 6559): ╎ │ creator: Center ← DefaultTextStyle ← AnimatedDefaultTextStyle ←
I/flutter ( 6559): ╎ │ _InkFeature-[GlobalKey ink renderer] ←
I/flutter ( 6559): ╎ │ NotificationListener
I/flutter ( 6559): ╎ │ ← Container ← DecoratedBox ← Container ← AnimatedContainer ←
I/flutter ( 6559): ╎ │ Material ← AppHome ← ⋯
I/flutter ( 6559): ╎ │ parentData:
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(w=411.4, h=683.4)
I/flutter ( 6559): ╎ │ size: Size(411.4, 683.4)
I/flutter ( 6559): ╎ │ alignment: Alignment.center
I/flutter ( 6559): ╎ │ widthFactor: expand
I/flutter ( 6559): ╎ │ heightFactor: expand
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderConstrainedBox relayoutBoundary=up1
I/flutter ( 6559): ╎ │ creator: ConstrainedBox ← MaterialButton ← FlatButton ← Center ←
I/flutter ( 6559): ╎ │ DefaultTextStyle ← AnimatedDefaultTextStyle ←
I/flutter ( 6559): ╎ │ _InkFeature-[GlobalKey ink renderer] ←
I/flutter ( 6559): ╎ │ NotificationListener
I/flutter ( 6559): ╎ │ ← Container ← DecoratedBox ← Container ← ⋯
I/flutter ( 6559): ╎ │ parentData: offset=Offset(156.7, 323.7)
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=683.4)
I/flutter ( 6559): ╎ │ size: Size(98.0, 36.0)
I/flutter ( 6559): ╎ │ additionalConstraints: BoxConstraints(88.0<=w<=Infinity, h=36.0)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderSemanticsGestureHandler relayoutBoundary=up2
I/flutter ( 6559): ╎ │ creator: _GestureSemantics ← RawGestureDetector ← GestureDetector
I/flutter ( 6559): ╎ │ ← InkWell ← IconTheme ← DefaultTextStyle ←
I/flutter ( 6559): ╎ │ AnimatedDefaultTextStyle ← ConstrainedBox ← MaterialButton ←
I/flutter ( 6559): ╎ │ FlatButton ← Center ← DefaultTextStyle ← ⋯
I/flutter ( 6559): ╎ │ parentData:
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(88.0<=w<=411.4, h=36.0)
I/flutter ( 6559): ╎ │ size: Size(98.0, 36.0)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderPointerListener relayoutBoundary=up3
I/flutter ( 6559): ╎ │ creator: Listener ← _GestureSemantics ← RawGestureDetector ←
I/flutter ( 6559): ╎ │ GestureDetector ← InkWell ← IconTheme ← DefaultTextStyle ←
I/flutter ( 6559): ╎ │ AnimatedDefaultTextStyle ← ConstrainedBox ← MaterialButton ←
I/flutter ( 6559): ╎ │ FlatButton ← Center ← ⋯
I/flutter ( 6559): ╎ │ parentData:
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(88.0<=w<=411.4, h=36.0)
I/flutter ( 6559): ╎ │ size: Size(98.0, 36.0)
I/flutter ( 6559): ╎ │ behavior: opaque
I/flutter ( 6559): ╎ │ listeners: down
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderPadding relayoutBoundary=up4
I/flutter ( 6559): ╎ │ creator: Padding ← Container ← Listener ← _GestureSemantics ←
I/flutter ( 6559): ╎ │ RawGestureDetector ← GestureDetector ← InkWell ← IconTheme ←
I/flutter ( 6559): ╎ │ DefaultTextStyle ← AnimatedDefaultTextStyle ← ConstrainedBox ←
I/flutter ( 6559): ╎ │ MaterialButton ← ⋯
I/flutter ( 6559): ╎ │ parentData:
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(88.0<=w<=411.4, h=36.0)
I/flutter ( 6559): ╎ │ size: Size(98.0, 36.0)
I/flutter ( 6559): ╎ │ padding: EdgeInsets(16.0, 0.0, 16.0, 0.0)
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderPositionedBox relayoutBoundary=up5
I/flutter ( 6559): ╎ │ creator: Center ← Padding ← Container ← Listener ←
I/flutter ( 6559): ╎ │ _GestureSemantics ← RawGestureDetector ← GestureDetector ←
I/flutter ( 6559): ╎ │ InkWell ← IconTheme ← DefaultTextStyle ←
I/flutter ( 6559): ╎ │ AnimatedDefaultTextStyle ← ConstrainedBox ← ⋯
I/flutter ( 6559): ╎ │ parentData: offset=Offset(16.0, 0.0)
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(56.0<=w<=379.4, h=36.0)
I/flutter ( 6559): ╎ │ size: Size(66.0, 36.0)
I/flutter ( 6559): ╎ │ alignment: Alignment.center
I/flutter ( 6559): ╎ │ widthFactor: 1.0
I/flutter ( 6559): ╎ │ heightFactor: expand
I/flutter ( 6559): ╎ │
I/flutter ( 6559): ╎ └─child: RenderParagraph relayoutBoundary=up6
I/flutter ( 6559): ╎ │ creator: RichText ← Text ← Center ← Padding ← Container ←
I/flutter ( 6559): ╎ │ Listener ← _GestureSemantics ← RawGestureDetector ←
I/flutter ( 6559): ╎ │ GestureDetector ← InkWell ← IconTheme ← DefaultTextStyle ← ⋯
I/flutter ( 6559): ╎ │ parentData: offset=Offset(0.0, 10.0)
I/flutter ( 6559): ╎ │ constraints: BoxConstraints(0.0<=w<=379.4, 0.0<=h<=36.0)
I/flutter ( 6559): ╎ │ size: Size(66.0, 16.0)
I/flutter ( 6559): ╎ ╘═╦══ text ═══
I/flutter ( 6559): ╎ ║ TextSpan:
I/flutter ( 6559): ╎ ║ inherit: false
I/flutter ( 6559): ╎ ║ color: Color(0xdd000000)
I/flutter ( 6559): ╎ ║ family: "Roboto"
I/flutter ( 6559): ╎ ║ size: 14.0
I/flutter ( 6559): ╎ ║ weight: 500
I/flutter ( 6559): ╎ ║ baseline: alphabetic
I/flutter ( 6559): ╎ ║ "Dump App"
I/flutter ( 6559): ╎ ╚═══════════
I/flutter ( 6559): ╎
I/flutter ( 6559): └╌no offstage children
這(zhè)是根RenderObject對象的toStringDeep函數(shù)的輸出。
當調試布局問(wèn)題時(shí),關鍵要(yào)看(kàn)的是size和(hé)constraints字段。約束沿着樹(shù)向下(xià)傳遞,尺寸向上(shàng)傳遞。
例如(rú),在上(shàng)面的轉儲中,您可(kě)以看(kàn)到窗口大小,Size(411.4, 683.4),它用于強制RenderPositionedBox下(xià)的所有渲染框到屏幕的大小, 約束條件為(wèi) BoxConstraints(w=411.4, h=683.4)。從(cóng)RenderPositionedBox的轉儲中看(kàn)到是由Center widget創建的(如(rú)creator字段所描述的), 設置其孩子的約束為(wèi):BoxConstraints(0.0<=w<=411.4,0.0<=h<=683.4)。一(yī)個子widget RenderPadding進一(yī)步插入這(zhè)些約束以添加填充空間(jiān),padding值為(wèi)EdgeInsets(16.0, 0.0, 16.0, 0.0),因此RenderConstrainedBox具有約束BoxConstraints(0.0<=w<=395.4, 0.0<=h<=667.4)。該creator字段告訴我們的這(zhè)個對象可(kě)能(néng)是其FlatButton定義的一(yī)部分,它在其內(nèi)容上(shàng)設置最小寬度為(wèi)88像素,并且設置高度為(wèi)36.0像素(這(zhè)是Material Design設計規範中FlatButton類的尺寸标準)。
最內(nèi)部RenderPositionedBox再次松開(kāi)約束,這(zhè)次是将按鈕中的文本居中。 在RenderParagraph中基于它的內(nèi)容來決定其大小。 如(rú)果您現在按照size鏈繼續往下(xià)查看(kàn),您會看(kàn)到文本的大小是如(rú)何影響其按鈕的框的寬度的,它們都(dōu)是根據孩子的尺寸自(zì)行(xíng)調整大小。
另一(yī)種需要(yào)注意的是每個盒子描述的”relayoutSubtreeRoot”部分,它告訴你有多少(shǎo)祖先以某種方式依賴于這(zhè)個元素的大小。 因此,RenderParagraph有一(yī)個relayoutSubtreeRoot=up8,這(zhè)意味着當它RenderParagraph被标及為(wèi)”dirty”時(shí),它的八個祖先也必須被标記為(wèi)”dirty”,因為(wèi)它們可(kě)能(néng)受到新尺寸的影響。
如(rú)果您編寫自(zì)己的渲染對象,則可(kě)以通(tōng)過覆蓋debugFillProperties()将信息添加到轉儲。 将DiagnosticsProperty對象作(zuò)為(wèi)方法的參數(shù),并調用父類方法。
層
如(rú)果您嘗試調試合成問(wèn)題,則可(kě)以使用debugDumpLayerTree()。對于上(shàng)面的例子,它會輸出:
I/flutter : TransformLayer
I/flutter : │ creator: [root]
I/flutter : │ offset: Offset(0.0, 0.0)
I/flutter : │ transform:
I/flutter : │ [0] 3.5,0.0,0.0,0.0
I/flutter : │ [1] 0.0,3.5,0.0,0.0
I/flutter : │ [2] 0.0,0.0,1.0,0.0
I/flutter : │ [3] 0.0,0.0,0.0,1.0
I/flutter : │
I/flutter : ├─child 1: OffsetLayer
I/flutter : │ │ creator: RepaintBoundary ← _FocusScope ← Semantics ← Focus-[GlobalObjectKey MaterialPageRoute(560156430)] ← _ModalScope-[GlobalKey 328026813] ← _OverlayEntry-[GlobalKey 388965355] ← Stack ← Overlay-[GlobalKey 625702218] ← Navigator-[GlobalObjectKey _MaterialAppState(859106034)] ← Title ← ⋯
I/flutter : │ │ offset: Offset(0.0, 0.0)
I/flutter : │ │
I/flutter : │ └─child 1: PictureLayer
I/flutter : │
I/flutter : └─child 2: PictureLayer
這(zhè)是根Layer的toStringDeep輸出的。
根部的變換是應用設備像素比的變換; 在這(zhè)種情況下(xià),每個邏輯像素代表3.5個設備像素。
RepaintBoundary widget在渲染樹(shù)的層中創建了(le)一(yī)個RenderRepaintBoundary。這(zhè)用于減少(shǎo)需要(yào)重繪的需求量。
語義
您還可(kě)以調用debugDumpSemanticsTree()獲取語義樹(shù)(呈現給系統可(kě)訪問(wèn)性API的樹(shù))的轉儲。 要(yào)使用此功能(néng),必須首先啓用輔助功能(néng),例如(rú)啓用系統輔助工(gōng)具或Semanticswindow (下(xià)面讨論)。
對于上(shàng)面的例子,它會輸出:
I/flutter : SemanticsNode(0; Rect.fromLTRB(0.0, 0.0, 411.4, 683.4))
I/flutter : ├SemanticsNode(1; Rect.fromLTRB(0.0, 0.0, 411.4, 683.4))
I/flutter : │ └SemanticsNode(2; Rect.fromLTRB(0.0, 0.0, 411.4, 683.4); canBeTapped)
I/flutter : └SemanticsNode(3; Rect.fromLTRB(0.0, 0.0, 411.4, 683.4))
I/flutter : └SemanticsNode(4; Rect.fromLTRB(0.0, 0.0, 82.0, 36.0); canBeTapped; "Dump App")
調度
要(yào)找出相對于幀的開(kāi)始/結束事件發生的位置,可(kě)以切換debugPrintBeginFrameBanner和(hé)debugPrintEndFrameBanner布爾值以将幀的開(kāi)始和(hé)結束打印到控制台。
例如(rú):
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還可(kě)以用來打印導緻當前幀被調度的調用堆棧。
可(kě)視(shì)化調試
您也可(kě)以通(tōng)過設置debugPaintSizeEnabled為(wèi)true以可(kě)視(shì)方式調試布局問(wèn)題。 這(zhè)是來自(zì)rendering庫的布爾值。它可(kě)以在任何時(shí)候啓用,并在為(wèi)true時(shí)影響繪制。 設置它的最簡單方法是在void main()的頂部設置。
當它被啓用時(shí),所有的盒子都(dōu)會得到一(yī)個明(míng)亮的深青色邊框,padding(來自(zì)widget如(rú)Padding)顯示為(wèi)淺藍(lán)色,子widget周圍有一(yī)個深藍(lán)色框, 對齊方式(來自(zì)widget如(rú)Center和(hé)Align)顯示為(wèi)黃(huáng)色箭頭. 空白(如(rú)沒有任何子節點的Container)以灰色顯示。
debugPaintBaselinesEnabled做(zuò)了(le)類似的事情,但(dàn)對于具有基線的對象,文字基線以綠(lǜ)色顯示,表意(ideographic)基線以橙色顯示。
debugPaintPointersEnabled标志打開(kāi)一(yī)個特殊模式,任何正在點擊的對象都(dōu)會以深青色突出顯示。 這(zhè)可(kě)以幫助您确定某個對象是否以某種不正确地(dì)方式進行(xíng)hit測試(Flutter檢測點擊的位置是否有能(néng)響應用戶操作(zuò)的widget),例如(rú),如(rú)果它實際上(shàng)超出了(le)其父項的範圍,首先不會考慮通(tōng)過hit測試。
如(rú)果您嘗試調試合成圖層,例如(rú)以确定是否以及在何處添加RepaintBoundary widget,則可(kě)以使用debugPaintLayerBordersEnabled 标志, 該标志用橙色或輪廓線标出每個層的邊界,或者使用debugRepaintRainbowEnabled标志, 隻要(yào)他(tā)們重繪時(shí),這(zhè)會使該層被一(yī)組旋轉色所覆蓋。
所有這(zhè)些标志隻能(néng)在調試模式下(xià)工(gōng)作(zuò)。通(tōng)常,Flutter框架中以“debug...” 開(kāi)頭的任何內(nèi)容都(dōu)隻能(néng)在調試模式下(xià)工(gōng)作(zuò)。
調試動畫(huà)
調試動畫(huà)最簡單的方法是減慢(màn)它們的速度。為(wèi)此,請(qǐng)将timeDilation變量(在scheduler庫中)設置為(wèi)大于1.0的數(shù)字,例如(rú)50.0。 最好在應用程序啓動時(shí)隻設置一(yī)次。如(rú)果您在運行(xíng)中更改它,尤其是在動畫(huà)運行(xíng)時(shí)将其值減小,則框架的觀察時(shí)可(kě)能(néng)會倒退,這(zhè)可(kě)能(néng)會導緻斷言并且通(tōng)常會幹擾您的工(gōng)作(zuò)。
調試性能(néng)問(wèn)題
要(yào)了(le)解您的應用程序導緻重新布局或重新繪制的原因,您可(kě)以分别設置debugPrintMarkNeedsLayoutStacks和(hé) debugPrintMarkNeedsPaintStacks标志。 每當渲染盒被要(yào)求重新布局和(hé)重新繪制時(shí),這(zhè)些都(dōu)會将堆棧跟蹤記錄到控制台。如(rú)果這(zhè)種方法對您有用,您可(kě)以使用services庫中的debugPrintStack()方法按需打印堆棧痕迹。
衡量應用啓動時(shí)間(jiān)
要(yào)收集有關Flutter應用程序啓動所需時(shí)間(jiān)的詳細信息,可(kě)以在運行(xíng)flutter run時(shí)使用trace-startup和(hé)profile選項。
$ flutter run --trace-startup --profile
跟蹤輸出保存為(wèi)start_up_info.json,在Flutter工(gōng)程目錄在build目錄下(xià)。輸出列出了(le)從(cóng)應用程序啓動到這(zhè)些跟蹤事件(以微(wēi)秒捕獲)所用的時(shí)間(jiān):
進入Flutter引擎時(shí).
展示應用第一(yī)幀時(shí).
初始化Flutter框架時(shí).
完成Flutter框架初始化時(shí).
如(rú) :
{
"engineEnterTimestampMicros": 96025565262,
"timeToFirstFrameMicros": 2171978,
"timeToFrameworkInitMicros": 514585,
"timeAfterFrameworkInitMicros": 1657393
}
跟蹤Dart代碼性能(néng)
要(yào)執行(xíng)自(zì)定義性能(néng)跟蹤和(hé)測量Dart任意代碼段的wall/CPU時(shí)間(jiān)(類似于在Android上(shàng)使用systrace)。 使用dart:developer的Timeline工(gōng)具來包含你想測試的代碼塊,例如(rú):
Timeline.startSync('interesting function');
// iWonderHowLongThisTakes();
Timeline.finishSync();
然後打開(kāi)你應用程序的Observatory timeline頁面,在”Recorded Streams”中選擇’Dart’複選框,并執行(xíng)你想測量的功能(néng)。
刷新頁面将在Chrome的跟蹤工(gōng)具中顯示應用按時(shí)間(jiān)順序排列的timeline記錄。
請(qǐng)确保運行(xíng)flutter run時(shí)帶有--profile标志,以确保運行(xíng)時(shí)性能(néng)特征與您的最終産品差異最小。
Performance Overlay
要(yào)獲得應用程序性能(néng)圖,請(qǐng)将MaterialApp構造函數(shù)的showPerformanceOverlay參數(shù)設置為(wèi)true。 WidgetsApp構造函數(shù)也有類似的參數(shù)(如(rú)果你沒有使用MaterialApp或者WidgetsApp,你可(kě)以通(tōng)過将你的應用程序包裝在一(yī)個stack中, 并将一(yī)個widget放在通(tōng)過new PerformanceOverlay.allEnabled()創建的stack上(shàng)來獲得相同的效果)。
這(zhè)将顯示兩個圖表。第一(yī)個是GPU線程花費(fèi)的時(shí)間(jiān),最後一(yī)個是CPU線程花費(fèi)的時(shí)間(jiān)。 圖中的白線以16ms增量沿縱軸顯示; 如(rú)果圖中超過這(zhè)三條線之一(yī),那(nà)麽您的運行(xíng)頻(pín)率低(dī)于60Hz。橫軸代表幀。 該圖僅在應用程序繪制時(shí)更新,因此如(rú)果它處于空閑狀态,該圖将停止移動。
這(zhè)應該始終在發布模式(release mode)下(xià)測試,因為(wèi)在調試模式下(xià),故意犧牲性能(néng)來換取有助于開(kāi)發調試的功能(néng),如(rú)assert聲明(míng),這(zhè)些都(dōu)是非常耗時(shí)的,因此結果将會産生誤導。
Material grid
在開(kāi)發實現Material Design的應用程序時(shí), 将Material Design基線網格覆蓋在應用程序上(shàng)可(kě)能(néng)有助于驗證對齊。 為(wèi)此,MaterialApp 構造函數(shù) 有一(yī)個debugShowMaterialGrid參數(shù), 當在調試模式設置為(wèi)true時(shí),它将覆蓋這(zhè)樣一(yī)個網格。
您也可(kě)以直接使用GridPaperwidget将這(zhè)種網格覆蓋在非Material應用程序上(shàng) 。
網站建設開(kāi)發|APP設計開(kāi)發|小程序建設開(kāi)發