Flutter Widgets — nó là gì, cây widget và build

Tác giả: IT Sectr Đã đăng: 2026-02-21 Thời gian đọc: 8 phút

Flutter Widgets — các khối xây dựng cơ bản của giao diện người dùng trong framework Google Flutter, được phát hành ở phiên bản ổn định 1.0 vào tháng 12 năm 2018. Trong Flutter, mọi thứ đều là widget: từ màn hình và nút bấm đến khoảng đệm và căn chỉnh. Các widget tạo thành một cây (widget tree) mà Flutter render trên engine Skia/Impeller của riêng nó, bỏ qua các thành phần gốc của nền tảng. Theo Google I/O (2025), Flutter được sử dụng trong hơn 500.000 ứng dụng trên Google Play và App Store. Kiến trúc Flutter chia widget thành StatelessWidget (bất biến) và StatefulWidget (có trạng thái thay đổi được thông qua đối tượng State).

Những Điểm Chính

  • Flutter Widgets — tất cả các phần tử UI trong Flutter: từ màn hình và nút bấm đến khoảng đệm và căn chỉnh; framework không sử dụng các thành phần gốc của nền tảng.
  • StatelessWidget — widget không có trạng thái thay đổi; hiển thị dữ liệu được truyền qua hàm tạo và không thay đổi sau khi build.
  • StatefulWidget — widget có trạng thái thay đổi được lưu trong đối tượng State riêng biệt và tồn tại qua các lần rebuild.
  • Cây widget (widget tree) — hệ thống phân cấp widget mô tả UI; Flutter chuyển đổi nó thành Element Tree và Render Tree để render.
  • BuildContext — ngữ cảnh xây dựng cung cấp quyền truy cập vào vị trí của widget trong cây, theme, MediaQuery và InheritedWidget.

Flutter Widgets là gì?

Flutter Widgets — tất cả các phần tử UI trong framework Flutter, được triển khai dưới dạng các lớp Dart bất biến (immutable). Widget là cấu hình của một phần tử UI: kích thước, màu sắc, vị trí và trình xử lý sự kiện. Không giống như Android (XML + View) hay iOS (Storyboard + UIView), Flutter không sử dụng các thành phần gốc — mọi thứ đều được vẽ bởi engine Skia (Android/iOS/Linux) hoặc Impeller (iOS/macOS) trên Canvas. Điều này đảm bảo giao diện nhất quán trên tất cả các nền tảng mà không có sự khác biệt về nền tảng. Flutter đi kèm với hai bộ widget: Material Widgets (Google Material Design 3 cho Android/web) và Cupertino Widgets (Apple HIG cho iOS/macOS). Nhà phát triển có thể kết hợp cả hai bộ trong một ứng dụng. Mỗi widget có phương thức build() trả về một widget con hoặc sự kết hợp của chúng — đây là cách cây widget được xây dựng.

Ba cây của Flutter

Flutter hoạt động với ba cây: Widget Tree (cấu hình, được nhà phát triển tạo), Element Tree (ánh xạ widget đến vị trí của nó trong cây, được framework quản lý) và Render Tree (các đối tượng tính toán bố cục và thực hiện vẽ). Một Widget tạo ra một Element, Element tạo ra một RenderObject. Element được tái sử dụng khi cấu hình thay đổi (rebuild) — đây là cơ chế tối ưu hóa của Flutter: nếu loại widget và key khớp nhau, Element không được tạo lại mà được cập nhật với cấu hình mới. Hiểu ba cây là chìa khóa để tối ưu hóa hiệu suất ứng dụng Flutter.

StatelessWidget: widget bất biến

StatelessWidget — widget không lưu trữ trạng thái nội bộ. Nó nhận tham số qua hàm tạo và hiển thị chúng mà không có khả năng thay đổi sau khi build. StatelessWidget lý tưởng cho các phần tử tĩnh: tiêu đề, biểu tượng, hình đại diện, danh sách với dữ liệu cố định. Phương thức build() được gọi một lần khi tạo và khi widget cha thay đổi. Vì StatelessWidget không có trạng thái, nó không yêu cầu đối tượng State riêng — build() được định nghĩa trực tiếp trong lớp widget.

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

class ProfileHeader extends StatelessWidget {
  final String name;
  final String avatarUrl;

  const ProfileHeader({super.key, required this.name, required this.avatarUrl});

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        CircleAvatar(
          radius: 24,
          backgroundImage: NetworkImage(avatarUrl),
        ),
        const SizedBox(width: 12),
        Text(
          name,
          style: const TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
          ),
        ),
      ],
    );
  }
}

ProfileHeader — StatelessWidget nhận name và avatarUrl qua hàm tạo. CircleAvatar hiển thị hình đại diện, Text hiển thị tên. Widget không thể thay đổi các giá trị này sau khi tạo. Sử dụng hàm tạo const (const ProfileHeader) cho phép Flutter tái sử dụng thể hiện widget trong quá trình rebuild của cha — một tối ưu hóa vi mô được khuyến nghị cho tất cả StatelessWidget.

StatefulWidget: widget có trạng thái

StatefulWidget — widget có trạng thái thay đổi được lưu trong đối tượng State riêng biệt. Bản thân StatefulWidget là bất biến, giống như StatelessWidget. Phần có thể thay đổi được ủy quyền cho State: State là đối tượng được tạo một lần và tồn tại qua nhiều lần rebuild widget. Khi trạng thái thay đổi (setState()), Flutter gọi build() trên State, cập nhật UI. StatefulWidget được sử dụng cho các phần tử tương tác: bộ đếm, trường văn bản, hộp kiểm, hoạt ảnh, bộ hẹn giờ.

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

class LikeButton extends StatefulWidget {
  const LikeButton({super.key});

  @override
  State<LikeButton> createState() => _LikeButtonState();
}

class _LikeButtonState extends State<LikeButton> {
  bool liked = false;
  int count = 42;

  void _toggleLike() {
    setState(() {
      liked = !liked;
      count += liked ? 1 : -1;
    });
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: _toggleLike,
      child: Text(liked ? '♥ $count' : '♡ $count'),
    );
  }
}

LikeButton — StatefulWidget với lớp State _LikeButtonState. Các trường liked và count là trạng thái được lưu trong State và không bị đặt lại khi rebuild. setState() thông báo cho Flutter rằng UI cần được xây dựng lại. Flutter không tạo lại State ở mỗi lần rebuild của cha — chỉ khi cấu hình thay đổi (key hoặc loại widget). Tại IT Sectr, chúng tôi sử dụng StatelessWidget để hiển thị và StatefulWidget cho các thành phần tương tác, tuân theo nguyên tắc giảm thiểu StatefulWidget đến ranh giới đột biến.

Cây widget: từ Widget đến RenderObject

Widget Tree — cấu trúc phân cấp của các widget mô tả UI ứng dụng. Flutter chuyển đổi Widget Tree thành Element Tree: mỗi Widget tạo một Element, theo dõi vị trí của nó trong cây và kết nối với RenderObject. Render Tree thực hiện bố cục (xác định kích thước và vị trí) và vẽ (render). Element là một lớp tối ưu hóa quan trọng: nếu loại widget và key không thay đổi trong quá trình rebuild, Element được tái sử dụng, cập nhật cấu hình mà không tạo lại RenderObject. Điều này đảm bảo hiệu suất của Flutter ở tốc độ khung hình cao (60/120 FPS).

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Widget Flutter')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.flutter_dash, size: 80),
            const SizedBox(height: 16),
            const Text(
              'Xin chào, Flutter!',
              style: TextStyle(fontSize: 24),
            ),
          ],
        ),
      ),
    );
  }
}

Cây widget HomeScreen: Scaffold → AppBar + Center → Column → [Icon, SizedBox, Text]. Scaffold là widget bố cục gốc của Material Design. Center căn giữa Column con. Column sắp xếp các con theo chiều dọc với căn giữa (mainAxisAlignment.center). Flutter tính toán bố cục từ trên xuống (các ràng buộc được truyền từ cha) và kích thước từ dưới lên (sizedByParent hoặc sizing từ con).

BuildContext: ngữ cảnh xây dựng và truy cập cây

BuildContext — bộ mô tả vị trí của widget trong Element Tree. Mỗi phương thức build() nhận một BuildContext, qua đó widget có thể truy cập: MediaQuery (kích thước màn hình, hướng, mật độ pixel, vùng an toàn), Theme (MaterialThemeData hoặc CupertinoThemeData), Navigator (ngăn xếp điều hướng), ScaffoldMessenger (SnackBar), InheritedWidget (truyền dữ liệu xuống cây). BuildContext không nên được lưu sau khi build() kết thúc hoặc sử dụng ngoài ngữ cảnh đồng bộ — điều này gây ra lỗi như “Scaffold.of() called with a context that does not contain a Scaffold”. Thay vì lưu context, hãy sử dụng widget Builder hoặc mẫu InheritedWidget để truy cập dữ liệu.

Key: nhận dạng widget trong cây

Key — tham số tùy chọn của hàm tạo mỗi widget (super.key). Key giúp Flutter nhận dạng widget khi thứ tự hoặc số lượng phần tử trong danh sách thay đổi. Không có key, Flutter so sánh widget theo loại và vị trí; khi thêm một phần tử vào giữa danh sách mà không có key, Flutter tái sử dụng Element cho sai widget, gây ra lỗi trạng thái (StatefulWidget) và vấn đề hoạt ảnh. Sử dụng ValueKey (định danh duy nhất) cho danh sách, ObjectKey(dựa trên đối tượng dữ liệu), UniqueKey (đảm bảo duy nhất ở mỗi lần rebuild — để tạo lại bắt buộc).

Danh mục widget Flutter: Material, Cupertino, Layout

Flutter SDK (phiên bản ổn định 3.3+, Dart 3+) bao gồm hơn 200 widget tích hợp được chia thành các danh mục: Layout (Row, Column, Stack, Container, Expanded, Flexible, Wrap, GridView, ListView, CustomScrollView), Material Design (Scaffold, AppBar, Card, Drawer, BottomNavigationBar, FloatingActionButton, TabBar, Chip, DataTable), Cupertino (CupertinoPageScaffold, CupertinoNavigationBar, CupertinoButton, CupertinoTabBar), Painting & Effects (Opacity, DecoratedBox, ClipRect, Transform, BackdropFilter, ShaderMask), Async (FutureBuilder, StreamBuilder) và Accessibility (Semantics, MergeSemantics, ExcludeSemantics). Widget bố cục là nền tảng của mọi UI Flutter: Row cho chuỗi ngang, Column cho dọc, Stack cho các phần tử chồng lên nhau, Container với BoxDecoration để trang trí.

Danh mụcWidget chínhMục đích
LayoutRow, Column, Stack, Container, Expanded, FlexibleĐịnh vị và định cỡ các phần tử con
MaterialScaffold, AppBar, Card, Drawer, FAB, TabBarThành phần UI Material Design 3
CupertinoCupertinoPageScaffold, CupertinoNavigationBar, CupertinoButtonThành phần kiểu iOS
PaintingOpacity, ClipRect, Transform, DecoratedBox, BackdropFilterHiệu ứng hình ảnh và cắt xén
AsyncFutureBuilder, StreamBuilderTải dữ liệu bất đồng bộ với trạng thái UI
AccessibilitySemantics, MergeSemanticsĐánh dấu ngữ nghĩa cho trình đọc màn hình

Câu Hỏi Thường Gặp

StatelessWidget khác StatefulWidget như thế nào?

StatelessWidget không có trạng thái nội bộ — tất cả dữ liệu được truyền qua hàm tạo và không thay đổi. StatefulWidget lưu trữ trạng thái thay đổi trong đối tượng State riêng biệt tồn tại qua các lần rebuild. Thay đổi trạng thái gọi setState(), và Flutter xây dựng lại UI. Sử dụng StatelessWidget cho các phần tử bất biến; sử dụng StatefulWidget cho các phần tử tương tác.

BuildContext trong Flutter là gì?

BuildContext là bộ mô tả vị trí của widget trong Element Tree, được truyền cho phương thức build(). Thông qua context, widget truy cập MediaQuery, Theme, Navigator, ScaffoldMessenger và InheritedWidget. BuildContext không nên được lưu sau khi build() kết thúc. Để truy cập dữ liệu, hãy sử dụng widget Builder hoặc InheritedWidget.

Có cần biết Dart để làm việc với Flutter không?

Có, Flutter sử dụng Dart làm ngôn ngữ lập trình duy nhất. Dart là ngôn ngữ kiểu tĩnh với null safety, sound null safety, extension methods và pattern matching. Để bắt đầu, kiến thức Dart cơ bản là đủ: lớp, hàm, async/await, collection. Dart được biên dịch thành mã gốc (AOT) qua Dart Native và thành JavaScript (cho web) qua Dart2JS.

Flutter chỉ dành cho nền tảng di động?

Không, Flutter hỗ trợ sáu nền tảng: iOS, Android, Web, macOS, Windows, Linux. Hơn 90% mã được chia sẻ trên tất cả các nền tảng. Các điều chỉnh nền tảng (máy ảnh, hệ thống tệp) được triển khai qua plugin hoặc kênh nền tảng. Cho máy tính để bàn, Flutter sử dụng trình bao cửa sổ Flutter Desktop; cho web, nó sử dụng engine CanvasKit (WebGL) hoặc trình render HTML.

Làm thế nào Flutter đạt được hiệu suất 60 FPS?

Flutter đạt được 60/120 FPS nhờ: engine 2D riêng (Skia/Impeller), không có cầu nối gốc (không giống React Native), ba cây (Widget → Element → Render) với tái sử dụng Element khi loại/key không đổi, thuật toán bố cục một chiều (ràng buộc xuống, kích thước lên) và RepaintBoundary để cách ly việc vẽ lại các khu vực riêng lẻ của màn hình.

Tổng Kết

  • Flutter Widgets — tất cả phần tử UI: từ Scaffold đến SizedBox; Flutter tự render chúng trên Skia/Impeller, không sử dụng thành phần gốc.
  • StatelessWidget — widget không trạng thái; build() trả về UI dựa trên tham số hàm tạo bất biến.
  • StatefulWidget — widget có trạng thái thay đổi trong State; setState() kích hoạt rebuild UI.
  • Ba cây Flutter: Widget (cấu hình) → Element (vị trí) → Render (bố cục + vẽ); Element được tái sử dụng vì hiệu suất.
  • BuildContext — vị trí của widget trong cây; truy cập MediaQuery, Theme, Navigator, InheritedWidget.
  • Material và Cupertino — hai bộ widget cho Google Material Design 3 và Apple HIG tương ứng.
  • Key (ValueKey, ObjectKey, UniqueKey) — nhận dạng widget khi thay đổi thứ tự hoặc số lượng trong danh sách.

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm