Bỏ qua để đến nội dung

💡 Giới thiệu Widget

Trong Flutter, Widget là thành phần cơ bản để xây dựng UI. Mọi thứ bạn thấy trên màn hình đều là widget:

Text('Hello') // Widget hiển thị text
Container() // Widget chứa nội dung
Row() // Widget sắp xếp theo hàng
ElevatedButton() // Widget button

“Everything is a Widget” là triết lý cốt lõi của Flutter.


Flutter UI được tổ chức thành cây widget (Widget Tree):

MaterialApp
└── Scaffold
├── AppBar
│ └── Text
└── Body
└── Center
└── Column
├── Text
└── ElevatedButton

Code tương ứng:

MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My App'),
),
body: Center(
child: Column(
children: [
Text('Hello'),
ElevatedButton(
onPressed: () {},
child: Text('Click'),
),
],
),
),
),
)

Widget không có state, không thay đổi theo thời gian:

class GreetingCard extends StatelessWidget {
final String name;
const GreetingCard({super.key, required this.name});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(16),
child: Text('Hello, $name!'),
);
}
}

Widget có state, có thể thay đổi và rebuild:

class Counter extends StatefulWidget {
const Counter({super.key});
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $_count'),
ElevatedButton(
onPressed: () {
setState(() {
_count++;
});
},
child: Text('Increment'),
),
],
);
}
}

Category Ví dụ Mô tả
Structural Container, Padding, Center Layout và positioning
Layout Row, Column, Stack Sắp xếp children
Display Text, Image, Icon Hiển thị nội dung
Input TextField, Checkbox Nhập liệu
Interactive GestureDetector, InkWell Xử lý touch

Mỗi widget có các properties để customize:

Container(
width: 200,
height: 100,
color: Colors.blue,
padding: EdgeInsets.all(16),
margin: EdgeInsets.symmetric(vertical: 8),
child: Text('Content'),
)
// child - một widget con
Center(
child: Text('Single child'),
)
// children - nhiều widget con
Column(
children: [
Text('Child 1'),
Text('Child 2'),
Text('Child 3'),
],
)

Flutter khuyến khích composition over inheritance:

// Tạo widget mới bằng cách kết hợp widgets có sẵn
class ProfileCard extends StatelessWidget {
final String name;
final String avatarUrl;
const ProfileCard({
super.key,
required this.name,
required this.avatarUrl,
});
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Row(
children: [
CircleAvatar(
backgroundImage: NetworkImage(avatarUrl),
),
SizedBox(width: 16),
Text(name, style: TextStyle(fontSize: 18)),
],
),
),
);
}
}
// Sử dụng
ProfileCard(name: 'John', avatarUrl: 'https://...')

BuildContext chứa thông tin về vị trí widget trong tree:

@override
Widget build(BuildContext context) {
// Lấy theme
final theme = Theme.of(context);
// Lấy screen size
final size = MediaQuery.of(context).size;
return Container(
color: theme.primaryColor,
width: size.width * 0.5,
);
}

Sử dụng const để optimize performance:

// Good - widget được tạo một lần
const Text('Hello')
// Widget không đổi nên dùng const
const Padding(
padding: EdgeInsets.all(8),
child: Text('Static content'),
)

Khái niệm Mô tả
Widget Building block của Flutter UI
Widget Tree Cấu trúc cây của widgets
StatelessWidget Widget không có state
StatefulWidget Widget có state, có thể rebuild
child Một widget con
children Danh sách widget con
const Optimize widget không thay đổi