Core Widgets
ทุกแอปต้องมี text, image, button, icon และ list React พึ่ง HTML element (<p>, <img>, <button>, <ul>/<li>) ผสมกับ CSS ส่วน Flutter มี widget ระดับ first-class ให้สำหรับทุกอย่างเหล่านี้ โดยแต่ละตัวมี API ที่ครบครันซึ่งรวมการแสดงผลและ styling ไว้ที่เดียวกัน
ตารางแมป HTML / React → Flutter widget
หัวข้อที่มีชื่อว่า “ตารางแมป HTML / React → Flutter widget”| HTML / React | Flutter widget |
|---|---|
<p>, <span>, <h1> | Text |
<img src="https://..."> | Image.network('https://...') |
<button>, <Button> (MUI primary) | ElevatedButton |
<button> (ghost / text) | TextButton |
<IconButton> / FontAwesome | Icon(Icons.star) + IconButton |
<ul>/<li> scrollable list | ListView / ListView.builder |
<FlatList> (React Native) | ListView.builder |
API หลัก ๆ แบบรวบรัด
หัวข้อที่มีชื่อว่า “API หลัก ๆ แบบรวบรัด”Text — Text('Hello', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87))
Image.network — Image.network('https://...', width: 100, height: 100, fit: BoxFit.cover) — fit เทียบเท่ากับ object-fit ของ CSS
ElevatedButton — ElevatedButton(onPressed: () {}, child: const Text('Submit'))
TextButton — API เหมือน ElevatedButton แต่ render โดยไม่มี elevation
Icon — Icon(Icons.favorite, color: Colors.red, size: 24) — ใช้ Material Icons ที่มีอยู่ใน Flutter อยู่แล้ว
ListView.builder — list แบบ lazy ที่ render เฉพาะ item ที่มองเห็น เทียบเท่ากับ <FlatList> ของ React หรือ <ul> ที่ทำ virtualization ส่ง itemCount และ callback itemBuilder เข้าไป
ตัวอย่างที่รันได้ — รายชื่อผู้ติดต่อเล็ก ๆ
หัวข้อที่มีชื่อว่า “ตัวอย่างที่รันได้ — รายชื่อผู้ติดต่อเล็ก ๆ”import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Core Widgets'),
actions: [
IconButton(
icon: const Icon(Icons.search),
onPressed: () {},
),
],
),
body: Column(
children: [
// Image.network
Image.network(
'https://picsum.photos/seed/flutter/800/200',
height: 140,
width: double.infinity,
fit: BoxFit.cover,
),
// Text
const Padding(
padding: EdgeInsets.all(16),
child: Text('Your Contacts',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
),
// ListView.builder
Expanded(
child: ListView.builder(
itemCount: _contacts.length,
itemBuilder: (context, index) {
final contact = _contacts[index];
return ListTile(
leading: CircleAvatar(
backgroundColor: contact.color,
child: Text(contact.initials,
style: const TextStyle(color: Colors.white,
fontWeight: FontWeight.bold)),
),
title: Text(contact.name),
subtitle: Text(contact.role),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Icon(
contact.starred ? Icons.star : Icons.star_border,
color: contact.starred ? Colors.amber : Colors.grey,
),
onPressed: () {},
),
TextButton(
onPressed: () {},
child: const Text('Message'),
),
],
),
);
},
),
),
// ElevatedButton
Padding(
padding: const EdgeInsets.all(16),
child: ElevatedButton.icon(
onPressed: () {},
icon: const Icon(Icons.person_add),
label: const Text('Add Contact'),
),
),
],
),
),
);
}
}
class _Contact {
final String name, role, initials;
final Color color;
final bool starred;
const _Contact({required this.name, required this.role,
required this.initials, required this.color, this.starred = false});
}
const _contacts = [
_Contact(name: 'Ava Tavos', role: 'Flutter Developer',
initials: 'AT', color: Colors.blue, starred: true),
_Contact(name: 'Ben React', role: 'Frontend Engineer',
initials: 'BR', color: Colors.green),
_Contact(name: 'Cleo Dart', role: 'Mobile Lead',
initials: 'CD', color: Colors.purple, starred: true),
_Contact(name: 'Dana State', role: 'UX Designer',
initials: 'DS', color: Colors.orange),
_Contact(name: 'Eli Widget', role: 'Tech Lead',
initials: 'EW', color: Colors.teal),
];