Widget — ano ito, mga uri at komposisyon sa Flutter

May-akda: IT Sectr Nai-publish: 2026-06-30 Oras ng pagbabasa: 10 min

Widget — ay ang sentral na konsepto ng Flutter framework, na naglalarawan ng configuration ng isang elemento ng user interface. Ang bawat visual na bahagi, mula sa isang button hanggang sa isang kumplikadong animation, ay isang Widget. Hindi tulad ng ibang mga framework, kung saan ang UI ay inilalarawan sa pamamagitan ng hiwalay na mga XML file o iginuhit nang imperatively, ang Flutter ay bumubuo ng interface sa pamamagitan ng komposisyon ng Widget — pagsasama-sama ng maliliit na hindi mahahati na elemento sa isang hierarchical tree. Ayon sa Flutter Documentation (2025), ang Flutter SDK library ay may kasamang higit sa 260 built-in na Widget, na sumasaklaw sa Material Design, Cupertino at custom na mga estilo.

Mga Pangunahing Punto

  • Widget — pangunahing bloke ng gusali ng UI sa Flutter, na naglalarawan ng configuration ng elemento.
  • Komposisyon — ang UI ay binuo sa pamamagitan ng paglalagay ng Widget sa isa't isa, hindi sa pamamagitan ng inheritance.
  • StatelessWidget — widget na hindi nagbabago pagkatapos ng rendering (teksto, icon, spacing).
  • StatefulWidget — widget na may nababagong estado (mga form, animation, listahan ng data).
  • Element tree — ang Flutter ay nagpapanatili ng tatlong puno: Widget, Element at RenderObject.

Ano ang Widget sa Flutter

Widget sa Flutter ay isang hindi nababagong (immutable) paglalarawan ng isang bahagi ng user interface. Ang bawat Widget ay naglalaman ng mga property ng configuration: laki, kulay, posisyon, teksto, mga handler ng kaganapan at mga anak na Widget. Ang mga Widget mismo ay hindi direktang nire-render — ang mga ito ay mga recipe (blueprints) kung saan ang Flutter Engine ay lumilikha ng RenderObject — isang tunay na graphic object sa screen.

Sinasabi ng pilosopiya ng Flutter: “Everything is a Widget”. Nangangahulugan ito na hindi lamang ang mga nakikitang elemento (Text, Image, Button) ay Widget, kundi pati na rin ang mga structural block (Padding, Center, Column, Stack), behavioral block (GestureDetector, AnimatedBuilder), at maging ang application mismo (MaterialApp, CupertinoApp). Tinitiyak ng approach na ito ang pagkakapareho: anumang elemento ng screen ay maaaring pagsamahin sa anumang iba pa sa pamamagitan ng simpleng paglalagay.

Ayon sa data mula sa Google I/O 2024 — Flutter Widgets Deep Dive, ang karaniwang application sa Flutter ay naglalaman ng 200 hanggang 1500 Widget sa isang pagkakataon. Sa kabila ng bilang na ito, pinapanatili ng Flutter ang 60 FPS kahit sa mga budget device salamat sa mga optimization sa antas ng C++ Skia/Impeller engine. Ang Widget ay magaang na mga bagay (40–80 bytes bawat isa), kaya ang paglikha ng mga ito ay hindi bottleneck sa performance.

dart
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: Center(
          child: Text('Kumusta, Flutter!'),
        ),
      ),
    );
  }
}

Tatlong puno ng Flutter: Widget, Element at RenderObject

Upang maunawaan kung paano gumagana ang Widget, kailangan mong malaman ang arkitektura ng Flutter na binubuo ng tatlong magkakaugnay na puno. Una — Widget tree — naglalarawan ng configuration ng UI. Ito ay isang magaan na puno na maaaring ganap na muling itayo sa bawat frame (inaalis ng garbage collector ang mga lumang Widget at lumilikha ng mga bago). Ang Widget ay hindi nababago (immutable): kung nagbago ang kulay ng teksto — isang bagong Text Widget na may bagong kulay ang nalikha, ang luma ay itinatapon.

Pangalawang puno — Element tree — ang nag-uugnay sa pagitan ng Widget at RenderObject. Ang Element ay naglalaman ng reference sa Widget (configuration) at sa RenderObject (rendering). Kapag nagbago ang Widget, ikinukumpara ng Flutter ang bagong Widget sa lumang Element at nagpapasya: i-update ang umiiral na RenderObject (kung ang Widget ay pareho ng uri) o lumikha ng bago (kung nagbago ang uri ng Widget). Ang prosesong ito ay tinatawag na Reconciliation at ito ay katulad ng React Virtual DOM.

Pangatlong puno — RenderObject tree — responsable para sa aktwal na rendering sa screen. Ang RenderObject ay naglalaman ng mga konkretong sukat, posisyon at paint method. Ang Flutter Engine (C++ Skia o Impeller) ay dumadaan sa RenderObject tree at nire-render ang bawat node. Ang RenderObject tree ang pinakamabigat na puno, kaya pinapaliit ng Flutter ang mga pagbabago nito sa pamamagitan ng muling paggamit ng RenderObject kapag pinapalitan ang Widget ng parehong uri.

PunoLayuninImmutable?Ikot ng Buhay
WidgetConfiguration ng UI (recipe)OoMuling nilikha sa bawat build
ElementKoneksyon Widget ↔ RenderObjectHindiUmiiral habang ang widget ay nasa puno
RenderObjectRendering at layoutHindiMabigat, muling ginagamit kung posible

StatelessWidget vs StatefulWidget

Hinahati ng Flutter ang Widget sa dalawang pangunahing uri: StatelessWidget at StatefulWidget. Ang StatelessWidget ay isang widget na walang nababagong estado. Ang hitsura ng StatelessWidget ay ganap na tinutukoy ng constructor nito at hindi maaaring magbago pagkatapos ng rendering. Mga halimbawa: Text, Icon, Divider, Padding. Lahat ng property ng StatelessWidget ay idineklara bilang final sa constructor at read-only.

StatefulWidget ay isang widget na may nababagong estado. Binubuo ito ng dalawang klase: ang Widget mismo (hindi nababagong configuration, tulad ng StatelessWidget) at State (nababagong estado). Ang paghihiwalay ng Widget mula sa State ay isang mahalagang desisyon sa arkitektura ng Flutter. Ang Widget ay muling nilikha sa bawat build, ngunit ang State object ay nananatiling buhay sa buong ikot ng buhay ng widget sa puno, pinapanatili ang estado nito.

Kapag tinawag ang setState(), minamarkahan ng Flutter ang State bilang “marumi” at sa susunod na frame ay tinatawagan ang build() method para muling itayo ang sub-tree. Mahalaga: hindi muling nililikha ng setState() ang Widget mismo — ito ay nagti-trigger lamang ng build() call sa umiiral na State. Nangangahulugan ito na ang StatefulWidget ay maaaring mag-update ng UI nang hindi nawawala ang estado ng mga anak na Widget, hangga't ang mga susi (Key) ng mga anak na elemento ay nananatiling stable.

dart
// StatelessWidget — hitsura ay hindi nagbabago
class GreetingWidget extends StatelessWidget {
  const GreetingWidget({super.key, required this.name});
  final String name;

  @override
  Widget build(BuildContext context) {
    return Text('Kumusta, $name');
  }
}

// StatefulWidget — counter na may nababagong estado
class CounterWidget extends StatefulWidget {
  const CounterWidget({super.key});

  @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: const Text('Dagdagan'),
        ),
      ],
    );
  }
}

Mga uri ng Widget: layout, painting, interactive

Lahat ng Widget sa Flutter ay maaaring hatiin sa tatlong pangunahing kategorya batay sa functional na layunin. Layout Widget — responsable sa paglalagay ng mga anak na elemento sa screen. Ang Row at Column ay naglalagay ng mga anak sa isang linya, ang Stack ay naglalagay ng isa sa ibabaw ng isa, ang Expanded at Flexible ay namamahagi ng available na space. Ang Layout Widget ay walang sariling visual na representasyon — pinamamahalaan nila ang posisyon at laki ng mga anak na widget.

Painting Widget — responsable sa visual na hitsura. Pinagsasama ng Container ang mga dekorasyon (kulay, gradient, anino, border) sa mga layout property. Ang Padding ay nagdaragdag ng spacing, ang DecoratedBox ay gumuhit ng background, ang Transform ay nag-aapply ng mga pagbabago (rotation, scaling). Ang Painting Widget ay mga building block ng visual style at kadalasang ginagamit kasama ng layout Widget upang makamit ang ninanais na hitsura.

Interactive Widget — nagpoproseso ng input ng user. Ang GestureDetector ay nade-detect ng mga galaw (tap, swipe, pinch), ang InkWell ay nagdaragdag ng Material ripple effect, ang TextField ay tumatanggap ng text input, ang Slider at Switch ay nagbibigay ng standard controls. Ang Interactive Widget ay nagtataas ng mga event sa pamamagitan ng callback functions na ipinapasa sa constructor o hinahawakan sa pamamagitan ng state providers.

KategoryaMga Halimbawa ng WidgetLayunin
LayoutRow, Column, Stack, Expanded, Flexible, AlignPaglalagay at laki ng mga anak na elemento
PaintingContainer, Padding, DecoratedBox, RotatedBoxKulay, background, border, anino, transformasyon
InteractiveGestureDetector, InkWell, TextField, SliderPagproseso ng pagpindot, input, galaw
PlatformMaterialApp, CupertinoApp, Theme, MediaQueryIntegrasyon sa platform, tema, adaptasyon
AsyncFutureBuilder, StreamBuilder, ValueListenableBuilderReaktibong update mula sa asynchronous na data

Ayon sa data mula sa Flutter Widget of the Week (Google, 2025), aktibong ginagamit ng Flutter community ang kombinasyon ng layout + painting + interactive Widget upang bumuo ng halos anumang interface. Halimbawa, isang button: InkWell (interactive) + Container (painting) + Text (static) + Padding (layout). Ang ganitong modularidad ay nagbibigay-daan sa muling paggamit ng mga standard block sa iba't ibang konteksto nang walang pagdodoble ng code.

Komposisyon ng Widget at BuildContext

Komposisyon ng Widget ay ang proseso ng pagbuo ng UI sa pamamagitan ng paglalagay ng isang Widget sa loob ng isa pa. Hindi tulad ng classical inheritance (extends), kung saan ang anak na klase ay nagmamana ng pag-uugali ng magulang, ang Flutter ay gumagamit ng aggregation: bawat Widget ay naglalaman ng iba pang Widget sa pamamagitan ng parameter na child (para sa isa) o children (para sa marami). Ang approach na ito ay nagbibigay ng mas malaking flexibility at reusability.

BuildContext ay ang pangalawang pinakamahalagang konsepto pagkatapos ng Widget. Ang BuildContext ay isang descriptor ng posisyon ng Widget sa puno ng mga elemento. Sa pamamagitan ng BuildContext, ang Widget ay maaaring ma-access ang ancestor Widgets (Theme.of(context), MediaQuery.of(context), Navigator.of(context)). Ang BuildContext ay ipinapasa sa build() method at ginagamit para sa pakikipag-ugnayan sa parent at anak na mga elemento. Ang bawat Widget ay may eksaktong isang BuildContext na natatanging tumutukoy sa posisyon nito sa puno.

Ayon sa Flutter Architectural Overview (Google, 2025), ang BuildContext ay batayan para sa InheritedWidget — isang mekanismo na nagpapahintulot sa pagpapasa ng data pababa sa puno nang walang explicit na pagpapasa sa pamamagitan ng mga constructor. Ang Theme, MediaQuery, Navigator at Provider ay gumagamit ng InheritedWidget sa ilalim ng hood. Ang anumang malalim na nakalagay na Widget ay maaaring ma-access ang data ng ninuno sa pamamagitan ng BuildContext.dependOnInheritedWidgetOfExactType, na ginagawang susi ang BuildContext sa reactive architecture ng Flutter.

dart
// Komposisyon ng Widget sa pamamagitan ng paglalagay
Scaffold(
  appBar: AppBar(title: const Text('Aking App')),
  body: Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        const Text('Maligayang pagdating sa Flutter',
          style: TextStyle(fontSize: 24)),
        const SizedBox(height: 16),
        ElevatedButton(
          onPressed: () { /* nav */ },
          child: const Text('Magsimula'),
        ),
      ],
    ),
  ),
)

// Access sa mga tema sa pamamagitan ng BuildContext
Text(
  'Estiladong Teksto',
  style: Theme.of(context).textTheme.headlineMedium,
)

Mga karaniwang pagkakamali sa Widget

Ang una at pinakakaraniwang pagkakamali — paggamit ng StatefulWidget kung saan sapat na ang StatelessWidget. Maraming baguhang Flutter developer ang gumagawa ng StatefulWidget para sa lahat ng widget, kahit na ang estado ay naka-imbak sa external provider (Provider, Riverpod, BLoC). Ito ay kalabisan at nakakasira ng performance. Panuntunan: gamitin ang StatelessWidget kung ang estado ay pinamamahalaan mula sa labas o kung ang widget ay walang sariling nababagong estado.

Pangalawang pagkakamali — paglikha ng Widget sa loob ng build method na walang const constructor. Ang bawat Widget na nilikha nang walang const ay muling inilalaan sa bawat build. Kung sa loob ng build() ang Widget ay nilikha na may const constructor, maaaring gamitin muli ng Flutter ang parehong instance, binabawasan ang load sa garbage collector. Magdagdag ng const kahit saan posible — lalo na para sa Text, Icon, SizedBox, Padding at iba pang StatelessWidget.

Pangatlong pagkakamali — hindi tamang paggamit ng mga susi (Key). Ginagamit ng Flutter ang Key upang tukuyin ang Widget kapag muling itinatayo ang puno. Kung ang isang listahan ng Widget ay muling itinayo nang walang Key, maaaring paghaluin ng Flutter ang pagkakasunod-sunod ng mga elemento, na humahantong sa maling animation o pagkawala ng estado. Palaging magdagdag ng Key (hal., ValueKey o ObjectKey) para sa mga elemento sa mga listahan, lalo na kapag gumagamit ng ListView.builder na may dynamic na data.

Mga Madalas Itanong

Ano ang pagkakaiba ng StatelessWidget at StatefulWidget?

StatelessWidget — widget na walang nababagong estado, ang hitsura nito ay ganap na tinutukoy ng constructor. StatefulWidget — widget na may nababagong estado, na nakaimbak sa isang hiwalay na State object at maaaring i-update sa pamamagitan ng setState() nang hindi muling nililikha ang widget mismo. Gamitin ang StatelessWidget kahit saan posible, StatefulWidget — kapag kinakailangan ang lokal na estado.

Bakit tinatawag na immutable ang Widget?

Ang Widget immutable ay isang architectural decision ng Flutter para sa performance. Kung ang Widget ay mutable, hindi maihahambing ng Flutter nang ligtas ang luma at bagong configuration sa bawat build. Ang immutability ay nagpapahintulot sa Flutter na mabilis na matukoy kung nagbago ang Widget (sa pamamagitan ng == operator) at muling gamitin ang umiiral na RenderObject, na pinapaliit ang mamahaling rendering operations.

Ano ang BuildContext at para saan ito?

BuildContext ay isang descriptor ng posisyon ng Widget sa puno ng mga elemento. Sa pamamagitan nito, ang Widget ay nakaka-access sa ancestor Widgets (Theme, MediaQuery, Navigator) at InheritedWidget. Ang BuildContext ay ginagamit din para sa navigation (Navigator.of(context)), pagpapakita ng SnackBar at pakikipag-ugnayan sa Provider. Bawat Widget ay tumatanggap ng BuildContext sa pamamagitan ng build() method at ipinapasa ito sa mga tagapagmana nito.

Paano pumili sa pagitan ng Row, Column at Stack para sa layout?

Gamitin ang Row para sa horizontal na paglalagay ng mga elemento, Column — para sa vertical, Stack — para sa pagpapatong ng mga elemento sa isa't isa. Ang Row at Column ay gumagana sa flexbox principle: ang children ay sumasakop ng space ayon sa mainAxisSize, mainAxisAlignment at crossAxisAlignment. Ang Stack ay gumagamit ng positioned-children para sa tumpak na positioning kaugnay ng mga gilid o gitna.

Paano pinapanatili ng Flutter ang 60 FPS na may libu-libong Widget?

Nakakamit ng Flutter ang mataas na performance sa pamamagitan ng tatlong mekanismo: (1) Widget are cheap — magaang na immutable objects (40–80 bytes), ang paglikha ng mga ito ay hindi nagpapabigat sa GC. (2) RenderObject reuse — kapag pinapalitan ang Widget ng parehong uri, ang RenderObject ay muling ginagamit, iniiwasan ang mahal na muling paglikha. (3) Skia/Impeller engine — rendering sa C++ level na may pagliit ng mga drawing calls sa pamamagitan ng repaint boundaries.

Buod

  • Widget — immutable configuration ng bahagi ng UI sa Flutter, pangunahing building block na naglalarawan ng hitsura at pag-uugali.
  • Tatlong puno — gumagamit ang Flutter ng Widget tree (configuration), Element tree (koneksyon), RenderObject tree (rendering) para sa optimal na rendering.
  • Stateless vs Stateful — StatelessWidget walang estado, StatefulWidget na may nababagong State at setState() method para sa UI update.
  • Komposisyon — ang UI ay binuo sa pamamagitan ng paglalagay ng Widget sa pamamagitan ng child/children, walang inheritance, na nagbibigay ng flexibility at reusability.
  • BuildContext — descriptor ng posisyon ng Widget sa puno para sa access sa Theme, Navigator, MediaQuery at InheritedWidget.
  • Performance — ang Widget ay muling nililikha sa bawat build (60 FPS), ngunit ang RenderObject ay muling ginagamit kapag nagtugma ang uri.
  • Mga kategorya — ang Widget ay nahahati sa layout (Row, Column, Stack), painting (Container, Padding), interactive (GestureDetector, TextField) at platform (MaterialApp, Theme).

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.

Pag-usapan ang proyekto

Basahin din