Flutter Widgets
Flutter Widgets សំខាន់ៗ
Widgets គឺជា building blocks នៃ Flutter UI។ ក្នុង Flutter គ្រប់យ៉ាងជា Widget - ចាប់ពី buttons, text, icons រហូតដល់ layouts, themes, និង animations។
📘 Widget Theory
Widget Lifecycle & Rendering
នៅពេលអ្នកបង្កើត widget Flutter ធ្វើការតាមជំហានទាំងនេះ:
1. Widget (Configuration)
- Immutable description of UI
- Contains properties (color, size, etc.)
2. Element (Instance)
- Manages widget lifecycle
- Links widget to RenderObject
- Tracks state changes
3. RenderObject (Rendering)
- Performs layout calculation
- Paints pixels on screen
- Handles hit testing
Widget Tree vs Element Tree vs Render Tree
Widget Tree Element Tree Render Tree
Text StatelessElement RenderParagraph
│ │ │
Container ContainerElement RenderDecoratedBox
│ │ │
Column ColumnElement RenderFlex
🎨 Widget Types
1. Stateless Widgets (មិនផ្លាស់ប្តូរ)
- Immutable - properties cannot change
- UI does not change over time
- Better performance (no state tracking)
- Examples: Text, Icon, Image
2. Stateful Widgets (អាចផ្លាស់ប្តូរ)
- Mutable state that can change
- UI rebuilds when setState() is called
- Examples: Checkbox, TextField, AnimatedContainer
3. Inherited Widgets (ចែករំលែក data)
- Share data down the widget tree
- Efficient propagation of changes
- Examples: Theme, MediaQuery, Provider
📋 Widget Categories
ប្រភេទ | ឧទាហរណ៍ | មុខងារ |
---|---|---|
Layout | Container, Row, Column, Stack | រៀបចំ widgets |
Text | Text, RichText, SelectableText | បង្ហាញអត្ថបទ |
Input | TextField, Checkbox, Radio, Switch | ទទួលយក input |
Button | ElevatedButton, TextButton, IconButton | ប៊ូតុង |
Display | Image, Icon, CircleAvatar | បង្ហាញមាតិកា |
List | ListView, GridView, ListTile | បញ្ជី |
Dialog | AlertDialog, BottomSheet, SnackBar | បង្ហាញសារ |
📝 TextField Widget
TextField(
decoration: InputDecoration(
labelText: 'ឈ្មោះ',
hintText: 'បញ្ចូលឈ្មោះរបស់អ្នក',
prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
filled: true,
fillColor: Colors.grey[200],
),
keyboardType: TextInputType.text,
maxLength: 50,
onChanged: (value) {
print('Input: $value');
},
onSubmitted: (value) {
print('Submitted: $value');
},
)
✅ Checkbox, Radio, Switch
class FormExample extends StatefulWidget {
@override
_FormExampleState createState() => _FormExampleState();
}
class _FormExampleState extends State<FormExample> {
bool isChecked = false;
int selectedRadio = 1;
bool isSwitched = false;
@override
Widget build(BuildContext context) {
return Column(
children: [
// Checkbox
CheckboxListTile(
title: Text('យល់ព្រមលើកិច្ចព្រមព្រៀង'),
value: isChecked,
onChanged: (value) {
setState(() {
isChecked = value ?? false;
});
},
),
// Radio Buttons
RadioListTile(
title: Text('ប្រុស'),
value: 1,
groupValue: selectedRadio,
onChanged: (value) {
setState(() {
selectedRadio = value ?? 1;
});
},
),
RadioListTile(
title: Text('ស្រី'),
value: 2,
groupValue: selectedRadio,
onChanged: (value) {
setState(() {
selectedRadio = value ?? 2;
});
},
),
// Switch
SwitchListTile(
title: Text('បើក Notifications'),
value: isSwitched,
onChanged: (value) {
setState(() {
isSwitched = value;
});
},
),
],
);
}
}
📜 ListView Widget
Basic ListView
ListView(
padding: EdgeInsets.all(16),
children: [
Text('Item 1'),
Text('Item 2'),
Text('Item 3'),
],
)
ListView.builder (សម្រាប់ list ធំ)
class ItemListPage extends StatelessWidget {
final List<String> items = List.generate(100, (index) => 'Item ' + (index + 1).toString());
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
child: Text((index + 1).toString()),
),
title: Text(items[index]),
subtitle: Text('Description'),
trailing: Icon(Icons.arrow_forward_ios),
onTap: () {
print('Tapped: ' + items[index]);
},
);
},
);
}
}
ListView.separated
ListView.separated(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index]),
);
},
separatorBuilder: (context, index) {
return Divider(thickness: 1);
},
)
🔲 GridView Widget
GridView.count(
crossAxisCount: 2, // ចំនួន columns
crossAxisSpacing: 10,
mainAxisSpacing: 10,
padding: EdgeInsets.all(16),
children: List.generate(10, (index) {
return Container(
decoration: BoxDecoration(
color: Colors.blue[100],
borderRadius: BorderRadius.circular(12),
),
child: Center(
child: Text(
'Item ' + (index + 1).toString(),
style: TextStyle(fontSize: 18),
),
),
);
}),
)
🔔 Dialog Widgets
AlertDialog
void showAlertDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('បញ្ជាក់'),
content: Text('តើអ្នកពិតជាចង់លុបមែនទេ?'),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('បោះបង់'),
),
ElevatedButton(
onPressed: () {
// Perform delete
Navigator.pop(context);
},
child: Text('លុប'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
),
),
],
);
},
);
}
SnackBar
void showSnackBar(BuildContext context) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('រក្សាទុកបានជោគជ័យ'),
duration: Duration(seconds: 2),
action: SnackBarAction(
label: 'មិនធ្វើវិញ',
onPressed: () {
// Undo action
},
),
),
);
}
BottomSheet
void showBottomSheet(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
padding: EdgeInsets.all(20),
height: 200,
child: Column(
children: [
Text(
'ជ្រើសរើសជម្រើស',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
SizedBox(height: 20),
ListTile(
leading: Icon(Icons.share),
title: Text('ចែករំលែក'),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.edit),
title: Text('កែ'),
onTap: () {
Navigator.pop(context);
},
),
],
),
);
},
);
}
🖼️ Card Widget
Card(
elevation: 4,
margin: EdgeInsets.all(16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CircleAvatar(
backgroundImage: NetworkImage('https://example.com/avatar.jpg'),
),
SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'សុខា',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
'2 hours ago',
style: TextStyle(color: Colors.grey, fontSize: 12),
),
],
),
],
),
SizedBox(height: 12),
Text('នេះជាមាតិកានៃ Card widget។'),
SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton.icon(
icon: Icon(Icons.thumb_up_outlined),
label: Text('Like'),
onPressed: () {},
),
TextButton.icon(
icon: Icon(Icons.comment_outlined),
label: Text('Comment'),
onPressed: () {},
),
TextButton.icon(
icon: Icon(Icons.share_outlined),
label: Text('Share'),
onPressed: () {},
),
],
),
],
),
),
)
⏳ CircularProgressIndicator
// Loading indicator
CircularProgressIndicator()
// With custom color and size
SizedBox(
width: 50,
height: 50,
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
strokeWidth: 6,
),
)
// Linear progress indicator
LinearProgressIndicator(
value: 0.7, // 70% complete
backgroundColor: Colors.grey[300],
valueColor: AlwaysStoppedAnimation<Color>(Colors.green),
)
💡 ជំនួយ: ពិនិត្យមើល Flutter widget catalog នៅ docs.flutter.dev/ui/widgets សម្រាប់ widgets ទាំងអស់។