Widget Tree — ay isang hierarchical na istraktura ng mga widget sa Flutter na tumutukoy sa komposisyon ng user interface. Ang bawat elemento ng interface, mula sa isang button hanggang sa buong screen, ay kinakatawan ng isang hiwalay na widget na naka-nest sa isang parent container. Ina-update ng Flutter ang Widget Tree sa bawat pagbabago ng estado — inihahambing ng framework ang bago at lumang puno at naglalapat ng mga minimal na pagbabago. Ayon sa Flutter Team, 2025, ang mahusay na istraktura ng puno ay direktang nakakaapekto sa kinis ng mga animation at bilis ng pagtugon ng interface.
Mga pangunahing punto
Widget Tree — ay isang deklaratibong paglalarawan ng user interface sa Flutter, na binuo bilang isang puno ng mga naka-nest na widget. Ang bawat widget ay tumutukoy sa isang bahagi ng UI: configuration nito, mga parameter ng display, at pag-uugali sa pakikipag-ugnayan. Inilalarawan ng developer kung paano dapat magmukhang ang interface sa kasalukuyang estado ng application, at ang Flutter ang responsable para sa pag-convert ng paglalarawang ito sa mga pixel sa screen.
Hindi tulad ng mga imperative framework kung saan direktang minamanipula ng developer ang mga elemento ng interface, ang Flutter ay gumagamit ng deklaratibong diskarte. Sa pagbabago ng estado ng application, isang bagong Widget Tree ang nilikha at kinakalkula ng framework ang pagkakaiba sa pagitan ng luma at bagong puno. Pinapaliit nito ang bilang ng mga operasyon sa pagguhit at ginagawang mas predictable ang code.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("Widget Tree")),
body: Center(
child: Column(
children: [
Text("Kumusta, Flutter"),
ElevatedButton(
onPressed: () {},
child: Text("Pindutin ako"),
),
],
),
),
),
);
}
}
Sa halimbawang ito, ang Widget Tree ay binubuo ng MaterialApp, Scaffold, AppBar, Center, Column, Text, at ElevatedButton. Ang bawat isa sa mga widget na ito ay isang node ng puno. Kapag nagbago ang estado ng application, muling tinatawag ng Flutter ang build method at inihahambing ang resulta sa nakaraang puno.
Widget Tree ay nagsisimula sa root widget na ipinapasa sa method na runApp. Ang root widget ay karaniwang MaterialApp, CupertinoApp, o WidgetsApp — nagtatakda ng mga global na setting ng application. Mula sa root, ang puno ay sumasanga sa mga child widget, na ang bawat isa ay maaaring maglaman ng sarili nitong mga inapo.
Ang mga widget sa Flutter ay nahahati sa single-child (tumanggap ng isang anak sa pamamagitan ng child parameter) at multi-child (tumanggap ng listahan ng mga anak sa pamamagitan ng children). Mga halimbawa ng single-child: Center, Padding, SizedBox, Container. Multi-child: Column, Row, Stack, ListView, GridView. Ang pagkakaibang ito ay nakakaapekto sa istraktura ng Widget Tree: ang mga multi-child widget ay lumilikha ng mas malalawak na puno, habang ang single-child ay lumilikha ng mas malalalim na puno.
BuildContext — ay ang lokasyon ng widget sa Widget Tree. Ang bawat widget ay may sariling BuildContext, na ipinapasa sa build method at ginagamit para sa pag-access sa mga parent widget, tema, MediaQuery, at iba pang InheritedWidget. Ang BuildContext ay ang tulay sa pagitan ng widget at ng elemento nito sa Element Tree.
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final mediaQuery = MediaQuery.of(context);
return Container(
color: theme.colorScheme.primary,
child: Text(
"Lapad ng screen: ${mediaQuery.size.width}"
),
);
}
}
Sa halimbawang ito, ang BuildContext ay ginagamit upang makuha ang tema at mga sukat ng screen. Ang Flutter ay umaakyat sa Widget Tree patungo sa pinakamalapit na Theme at MediaQuery, na mga InheritedWidget. Ipinapakita nito kung paano ikinonekta ng konteksto ang widget sa posisyon nito sa hierarchy.
Sa pagsisimula ng Flutter application, ang function na runApp ay tinatawag, na tumatanggap ng root widget at nagsisimula sa pagbuo ng Widget Tree. Ang proseso ay may kasamang tatlong yugto: paglikha ng configuration ng widget, pagbuo ng Element Tree, at pagtatayo ng RenderObject Tree para sa aktwal na pagguhit.
Ang function na runApp ay lumilikha ng root element sa pamamagitan ng WidgetsFlutterBinding, na nag-uugnay sa framework sa graphics engine. Ang root widget ay inilalagay sa puno at tinatawag ng Flutter ang build method upang punan ito ng mga child widget. Ang bawat tawag sa build ay bumubuo ng isang bagong subgraph ng Widget Tree.
Pagkatapos buuin ang Widget Tree, isinasagawa ng Flutter ang paunang layout — pagkalkula ng mga sukat at posisyon ng lahat ng widget. Ang prosesong ito ay nagsisimula mula sa root at kumakalat pababa sa puno. Ang bawat widget ay tumatanggap ng mga constraint mula sa parent at ibinabalik ang kinakalkulang laki. Kung hindi magkatugma ang mga sukat, bubuo ang Flutter ng error sa layout.
Pagkatapos makumpleto ang layout, sinisimulan ng Flutter ang pagguhit ng bawat widget. Ginagawang graphic commands ng RenderObject ang paglalarawan ng interface na isinasagawa ng GPU sa pamamagitan ng Skia o Impeller. Ang buong proseso — mula sa Widget Tree hanggang sa mga pixel — ay paulit-ulit sa bawat pag-update ng estado na may dalas na hanggang 120 frame bawat segundo.
StatelessWidget — ay isang widget na walang panloob na nababagong estado. Ang hitsura nito ay ganap na tinutukoy ng mga input parameter na ipinasa sa pamamagitan ng constructor. Kung hindi nagbago ang mga parameter, ang StatelessWidget ay hindi itinatayong muli. Ginagawa nitong magaan mula sa pananaw ng performance.
Gamitin ang StatelessWidget para sa mga static na elemento ng interface: mga icon, text label, decorative separator, at simpleng button na walang panloob na logic. Ayon sa Flutter documentation, humigit-kumulang 70% ng mga widget sa isang tipikal na application ay maaaring StatelessWidget, na nagpapababa ng load sa garbage collector at nagpapabilis ng rebuild.
StatefulWidget ay lumilikha ng isang State object na pinapanatili sa pagitan ng mga muling pagtatayo ng widget. Kapag nagbago ang estado (sa pamamagitan ng setState call), minamarkahan ng Flutter ang widget bilang “marumi” at sa susunod na frame ay itinatayo itong muli. Pinapayagan ng StatefulWidget ang pagpapatupad ng mga interactive na elemento: input field, animation, timer, at dynamic na listahan.
class CounterWidget extends StatefulWidget {
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text("Bilang: $_count"),
ElevatedButton(
onPressed: () {
setState(() => _count++);
},
child: Text("Dagdagan"),
),
],
);
}
}
Sa halimbawang ito, ang StatefulWidget ay gumagamit ng setState upang baguhin ang counter. Kapag na-update ang estado, itinatayong muli ng Flutter ang bahagi lamang ng Widget Tree na nagbago — ang CounterWidget widget at mga inapo nito. Ang mga parent widget ay hindi itinatayong muli, na isang pangunahing bentahe ng deklaratibong modelo ng Flutter.
Widget Tree ay ang configuration layer, at ang Element Tree ay ang intermediate na link sa pagitan ng mga widget at aktwal na pagguhit. Ang bawat widget sa Widget Tree ay lumilikha ng isang elemento sa Element Tree na nag-iimbak ng reference sa widget at namamahala sa lifecycle. Ang arkitekturang ito ay nagpapahintulot sa Flutter na mahusay na iproseso ang mga pagbabago.
Kapag unang nakatagpo ng Flutter ang isang widget, tinatawag nito ang method na createElement na lumilikha ng kaukulang elemento. Para sa StatelessWidget, isang StatelessElement ang nilikha; para sa StatefulWidget, isang StatefulElement na lumilikha din ng State object. Ang elemento ay pinapanatili sa pagitan ng mga rebuild cycle, kahit na ang widget ay muling nilikha.
Key — ay isang identifier na tumutulong sa Flutter na itugma ang mga widget mula sa luma at bagong Widget Tree. Kung ang isang widget ay may Key, ginagamit ito ng Flutter upang mahanap ang kaukulang elemento, hindi ang posisyon sa puno. Ang mga key ay kinakailangan kapag nagtatrabaho sa mga dynamic na listahan kung saan maaaring magbago ang pagkakasunud-sunod ng mga elemento.
ListView(
children: items.map((item) => ListItem(
key: ValueKey(item.id),
data: item,
)).toList(),
)
Kung walang Key, itinutugma ng Flutter ang mga elemento ayon sa posisyon, na maaaring humantong sa hindi tamang pagpapanatili ng estado kapag nagbago ang pagkakasunud-sunod. Ang ValueKey na may natatanging identifier ay ginagarantiyahan na ang bawat elemento ay nagpapanatili ng estado nito anuman ang posisyon sa listahan.
Ang istraktura ng Widget Tree ay direktang nakakaapekto sa performance ng Flutter application. Ang malalalim na puno na may maraming naka-nest na widget ay nangangailangan ng mas maraming oras para sa layout phase at nagpapataas ng konsumo ng memorya. Ang Flutter DevTools ay nagbibigay ng mga tool para sa pagsusuri ng Widget Tree at pagtukoy ng mga bottleneck.
Ang bawat antas ng nesting ay nagdaragdag ng karagdagang pag-compute sa layout at paint. Sa halip na malalim na chain nesting, gumamit ng mas flat na mga istraktura. Halimbawa, ang Row na may Expanded ay maaaring palitan ang ilang naka-nest na Container na may Align. Ayon sa Flutter Team, ang pag-optimize ng puno ay maaaring mabawasan ang oras ng layout ng hanggang 40%.
Flutter DevTools ay nagbibigay ng “Widget Inspector” widget na nagpapakita ng kasalukuyang Widget Tree sa real-time. Maaaring pumili ang developer ng anumang widget sa screen at tingnan ang lugar nito sa puno, mga parameter, at mga constraint ng layout. Nakakatulong ito na matukoy ang hindi inaasahang nesting, hindi kinakailangang rebuild, at mga problema sa laki.
RepaintBoundary — ay isang widget na naghihiwalay ng bahagi ng Widget Tree para sa malayang pagguhit. Kung magbago ang nilalaman ng RepaintBoundary, tanging ang lugar nito ang muling iguguhit, hindi ang buong screen. Gamitin ang RepaintBoundary para sa mga animation, listahan, at iba pang madalas na na-update na elemento.
RepaintBoundary(
child: CustomPaint(
painter: MyPainter(),
child: SizedBox(
width: 200,
height: 200,
),
),
)
Sa halimbawang ito, ang RepaintBoundary ay naghihiwalay ng CustomPaint sa isang hiwalay na lugar ng pagguhit. Kapag nag-a-update ng animation sa loob ng lugar na ito, tanging ang CustomPaint widget ang muling iginuguhit, ang natitirang screen ay nananatiling hindi nagbabago. Ito ay lalong kapaki-pakinabang sa mga kumplikadong interface na may maraming animated na elemento.
Mga madalas itanong
Widget Tree — ay isang deklaratibong paglalarawan ng interface na muling nililikha sa bawat rebuild. Ang Element Tree ay pinapanatili sa pagitan ng mga update at namamahala sa lifecycle, estado, at pagtutugma ng mga widget sa aktwal na RenderObject.
Walang limitasyon sa bilang ng mga widget, ngunit sa praktika ang isang puno na may libu-libong widget ay maaaring makapagpabagal sa layout phase. Ang Flutter ay na-optimize para sa mga puno hanggang ilang libong node; sa mas maraming bilang, inirerekomenda ang virtualization sa pamamagitan ng ListView.builder.
Gamitin ang Flutter DevTools — ang tab na “Widget Inspector”. Patakbuhin ang application sa debug mode, buksan ang DevTools sa browser, at pumili ng anumang widget sa screen upang makita ang lugar nito sa Widget Tree.
Rebuild — ay ang proseso ng muling paglikha ng configuration ng widget kapag nagbago ang estado. Muling tinatawag ng Flutter ang build method para sa mga binagong widget, inihahambing ang bagong Widget Tree sa nauna, at naglalapat ng mga minimal na pagbabago sa Element Tree.
Bawasan ang lalim ng nesting, gumamit ng const widget para sa mga static na elemento, ilapat ang RepaintBoundary para ihiwalay ang mga animation, at iwasan ang hindi kinakailangang StatefulWidget kung saan sapat na ang StatelessWidget.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din