Hướng dẫn học Flutter cho người mới bắt đầu
Lộ trình học Flutter từ cơ bản đến nâng cao, bao gồm cài đặt môi trường và viết ứng dụng đầu tiên

Giới thiệu về Flutter
Flutter là một framework phát triển ứng dụng di động mã nguồn mở được phát triển bởi Google. Với Flutter, bạn có thể xây dựng ứng dụng di động chất lượng cao cho iOS và Android từ một codebase duy nhất. Không chỉ dừng lại ở ứng dụng di động, Flutter còn hỗ trợ phát triển ứng dụng cho Web, macOS, Windows và Linux.
Những ưu điểm nổi bật của Flutter:
- Cross-platform: Viết mã một lần và chạy trên nhiều nền tảng
- Hot Reload: Thay đổi code và thấy kết quả ngay lập tức
- UI đẹp và linh hoạt: Hỗ trợ tùy biến UI tới từng pixel
- Hiệu năng cao: Hiệu suất gần như tương đương với ứng dụng native
- Cộng đồng lớn mạnh: Nhiều package và plugin hỗ trợ
Lộ trình học Flutter từ cơ bản đến nâng cao
Giai đoạn 1: Nền tảng và thiết lập
1.1. Học Dart
Dart là ngôn ngữ lập trình được sử dụng trong Flutter. Trước khi bắt đầu với Flutter, bạn nên làm quen với Dart.
Các khái niệm cơ bản về Dart cần nắm:
// Khai báo biến
var name = 'Nguyễn Văn A'; // Kiểu được suy ra
String city = 'Hà Nội'; // Kiểu tường minh
final age = 25; // Không thể thay đổi sau khi gán
const PI = 3.14; // Hằng số biên dịch
// Hàm trong Dart
int add(int a, int b) {
return a + b;
}
// Hàm mũi tên (Arrow function)
int multiply(int a, int b) => a * b;
// Lớp trong Dart
class Person {
String name;
int age;
Person(this.name, this.age); // Constructor ngắn gọn
void introduce() {
print('Xin chào, tôi là $name, $age tuổi.');
}
}
Tài nguyên học Dart:
1.2. Cài đặt Flutter SDK
Bước 1: Tải Flutter SDK
Truy cập trang tải xuống Flutter và tải xuống phiên bản phù hợp với hệ điều hành của bạn.
Bước 2: Giải nén file đã tải xuống
Giải nén file đã tải xuống vào thư mục bạn muốn cài đặt Flutter, ví dụ:
- Windows:
C:\dev\flutter
- macOS/Linux:
~/dev/flutter
Bước 3: Cập nhật biến môi trường PATH
Thêm thư mục flutter/bin
vào biến môi trường PATH:
Windows:
- Tìm kiếm "environment variables" trong menu Start
- Chọn "Edit the system environment variables"
- Nhấn "Environment Variables"
- Trong "System variables", chọn "Path" và click "Edit"
- Thêm đường dẫn đến thư mục
flutter\bin
- Nhấn "OK" để lưu
macOS/Linux:
- Mở file
~/.bashrc
,~/.bash_profile
, hoặc~/.zshrc
(tùy theo shell bạn đang sử dụng) - Thêm dòng sau:
export PATH="$PATH:[đường dẫn đến thư mục flutter]/bin"
- Lưu file và chạy
source ~/.bashrc
(hoặc file tương ứng)
Bước 4: Kiểm tra cài đặt
Mở terminal hoặc command prompt và chạy lệnh:
flutter doctor
Lệnh này sẽ kiểm tra cài đặt Flutter và báo cáo bất kỳ phụ thuộc nào còn thiếu. Hãy làm theo hướng dẫn để hoàn tất cài đặt.
1.3. Cài đặt IDE
Flutter làm việc tốt với nhiều IDE:
Visual Studio Code:
- Tải và cài đặt từ trang chủ VS Code
- Cài đặt extension "Flutter" từ marketplace
Android Studio / IntelliJ IDEA:
- Tải và cài đặt từ trang chủ Android Studio hoặc IntelliJ IDEA
- Cài đặt plugin Flutter và Dart từ Preferences/Settings -> Plugins
1.4. Tạo ứng dụng Flutter đầu tiên
Bằng dòng lệnh:
flutter create my_first_app cd my_first_app flutter run
Bằng IDE:
- Trong VS Code: Nhấn
Ctrl+Shift+P
(hoặcCmd+Shift+P
trên macOS), chọn "Flutter: New Project" - Trong Android Studio: Chọn "Start a new Flutter project"
Giai đoạn 2: Học các khái niệm cơ bản của Flutter
2.1. Widgets - Nền tảng UI của Flutter
Flutter sử dụng Widgets để xây dựng giao diện người dùng. Tất cả trong Flutter đều là widgets, từ một nút bấm đơn giản đến cả ứng dụng.
Các loại widget cơ bản:
// StatelessWidget - Widget không có trạng thái
import 'package:flutter/material.dart';
class MyStatelessWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Text('Hello, Flutter!'),
);
}
}
// StatefulWidget - Widget có trạng thái
class MyStatefulWidget extends StatefulWidget {
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Số lần nhấn: $_counter'),
ElevatedButton(
onPressed: _incrementCounter,
child: Text('Tăng'),
),
],
);
}
}
2.2. Layout trong Flutter
Hiểu cách sắp xếp và bố trí widgets là rất quan trọng trong Flutter.
Các widget layout phổ biến:
- Container: Widget đa năng để tùy chỉnh, tạo padding, margin, trang trí...
- Row và Column: Sắp xếp widget theo chiều ngang hoặc dọc
- Stack: Chồng các widget lên nhau
- Expanded và Flexible: Kiểm soát không gian mà widget chiếm trong Row hoặc Column
// Ví dụ về Column và Row
import 'package:flutter/material.dart';
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Dòng 1'),
Text('Dòng 2'),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Icon(Icons.star),
Icon(Icons.star),
Icon(Icons.star),
],
),
],
);
}
2.3. State Management
Quản lý trạng thái (State Management) là một trong những khía cạnh quan trọng của Flutter.
Các phương pháp quản lý trạng thái:
- setState(): Phương pháp cơ bản cho các ứng dụng đơn giản
- Provider: Dễ học và được Flutter khuyên dùng
- Bloc/Cubit: Mạnh mẽ, phù hợp cho ứng dụng lớn
- GetX: All-in-one, đơn giản hóa nhiều tác vụ
- Riverpod: Cải tiến từ Provider
Ví dụ đơn giản với Provider:
// Định nghĩa model
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Counter {
int value = 0;
void increment() {
value++;
}
}
// Sử dụng trong app
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Counter(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Provider Example'),
),
body: Center(
child: CounterDisplay(),
),
),
);
}
}
// Tiêu thụ trong Widget
class CounterDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text(
'${context.watch<Counter>().value}',
style: Theme.of(context).textTheme.headline4,
);
}
}
Giai đoạn 3: Xây dựng ứng dụng thực tế
3.1. Navigation và Routing
Điều hướng giữa các màn hình là phần cơ bản của hầu hết các ứng dụng.
// Điều hướng cơ bản
import 'package:flutter/material.dart';
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen()),
);
// Điều hướng có tên (Named Routes)
Navigator.pushNamed(context, '/second');
// Định nghĩa routes
MaterialApp(
routes: {
'/': (context) => HomeScreen(),
'/second': (context) => SecondScreen(),
'/detail': (context) => DetailScreen(),
},
);
3.2. Networking và API
Hầu hết các ứng dụng cần giao tiếp với API.
// Sử dụng package http
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<List<Post>> fetchPosts() async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));
if (response.statusCode == 200) {
List<dynamic> body = jsonDecode(response.body);
return body.map((item) => Post.fromJson(item)).toList();
} else {
throw Exception('Failed to load posts');
}
}
// Định nghĩa model
class Post {
final int id;
final String title;
final String body;
Post({required this.id, required this.title, required this.body});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
id: json['id'],
title: json['title'],
body: json['body'],
);
}
}
3.3. Lưu trữ cục bộ
Flutter cung cấp nhiều cách để lưu trữ dữ liệu cục bộ.
// Sử dụng SharedPreferences
import 'package:shared_preferences/shared_preferences.dart';
// Lưu dữ liệu
Future<void> saveData() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('username', 'NguyenVanA');
await prefs.setInt('age', 25);
await prefs.setBool('isLoggedIn', true);
}
// Đọc dữ liệu
Future<void> readData() async {
final prefs = await SharedPreferences.getInstance();
final username = prefs.getString('username') ?? 'Guest';
final age = prefs.getInt('age') ?? 0;
final isLoggedIn = prefs.getBool('isLoggedIn') ?? false;
print('Username: $username, Age: $age, Logged in: $isLoggedIn');
}
Giai đoạn 4: Nâng cao kỹ năng
4.1. Animations
Animations làm cho ứng dụng trở nên sinh động và thú vị hơn.
// Animation cơ bản với AnimatedContainer
import 'package:flutter/material.dart';
AnimatedContainer(
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
width: _expanded ? 200 : 100,
height: _expanded ? 100 : 50,
color: _expanded ? Colors.blue : Colors.red,
child: Center(child: Text('Nhấn vào tôi')),
);
// Controller-based Animation
class _MyAnimationState extends State<MyAnimation> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
_animation = CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return FadeTransition(
opacity: _animation,
child: const Text('Fade In Animation'),
);
}
}
4.2. Testing trong Flutter
Flutter hỗ trợ nhiều loại test:
- Unit tests: Kiểm tra logic không phụ thuộc vào UI
- Widget tests: Kiểm tra UI và tương tác
- Integration tests: Kiểm tra toàn bộ ứng dụng
// Unit test
import 'package:flutter_test/flutter_test.dart';
void main() {
test('Counter value should be incremented', () {
final counter = Counter();
counter.increment();
expect(counter.value, 1);
});
}
// Widget test
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
await tester.pumpWidget(MyApp());
expect(find.text('0'), findsOneWidget);
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
expect(find.text('1'), findsOneWidget);
});
}
4.3. CI/CD cho Flutter
Tích hợp liên tục và triển khai liên tục (CI/CD) giúp tự động hóa quy trình phát triển.
- Flutter CI/CD với GitHub Actions
- Fastlane cho iOS và Android
- Codemagic hoặc Bitrise cho Flutter
Giai đoạn 5: Tối ưu hóa và phát hành
5.1. Performance Optimization
Tối ưu hóa hiệu suất là quan trọng để ứng dụng chạy mượt mà.
- Sử dụng
const
constructor khi có thể - Tránh rebuild không cần thiết
- Sử dụng Flutter DevTools để phân tích hiệu suất
// Tránh rebuild không cần thiết với const
import 'package:flutter/material.dart';
const MyWidget(
key: Key('my_widget'),
child: Text('Hello'),
);
// Tối ưu với ListView.builder cho danh sách dài
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index].title),
);
},
);
5.2. Phát hành ứng dụng
Phát hành ứng dụng lên App Store và Google Play Store.
App Store (iOS):
- Đăng ký Apple Developer Account
- Tạo App ID, Certificates, và Provisioning Profiles
- Đóng gói ứng dụng:
flutter build ipa
- Sử dụng Xcode để tải lên App Store Connect
Google Play Store (Android):
- Đăng ký Google Play Developer Account
- Tạo keystore cho ứng dụng
- Đóng gói ứng dụng:
flutter build appbundle
- Tải lên Google Play Console
Ứng dụng đầu tiên: Todo List App
Để áp dụng kiến thức đã học, hãy cùng xây dựng một ứng dụng Todo List đơn giản.
Bước 1: Tạo dự án mới
flutter create todo_app cd todo_app
Bước 2: Định nghĩa model
// lib/models/todo.dart
class Todo {
final String id;
final String title;
bool isCompleted;
Todo({
required this.id,
required this.title,
this.isCompleted = false,
});
}
Bước 3: Tạo màn hình chính
// lib/screens/home_screen.dart
import 'package:flutter/material.dart';
import 'package:todo_app/models/todo.dart';
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final List<Todo> _todos = [];
final _textController = TextEditingController();
void _addTodo() {
if (_textController.text.isEmpty) return;
setState(() {
_todos.add(Todo(
id: DateTime.now().toString(),
title: _textController.text,
));
_textController.clear();
});
}
void _toggleTodo(String id) {
setState(() {
final todo = _todos.firstWhere((todo) => todo.id == id);
todo.isCompleted = !todo.isCompleted;
});
}
void _removeTodo(String id) {
setState(() {
_todos.removeWhere((todo) => todo.id == id);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Todo App'),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: _textController,
decoration: InputDecoration(
hintText: 'Thêm công việc mới...',
),
),
),
IconButton(
icon: Icon(Icons.add),
onPressed: _addTodo,
),
],
),
),
Expanded(
child: _todos.isEmpty
? Center(child: Text('Chưa có công việc nào!'))
: ListView.builder(
itemCount: _todos.length,
itemBuilder: (context, index) {
final todo = _todos[index];
return ListTile(
title: Text(
todo.title,
style: TextStyle(
decoration: todo.isCompleted
? TextDecoration.lineThrough
: null,
),
),
leading: Checkbox(
value: todo.isCompleted,
onChanged: (_) => _toggleTodo(todo.id),
),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => _removeTodo(todo.id),
),
);
},
),
),
],
),
);
}
}
Bước 4: Cập nhật main.dart
// lib/main.dart
import 'package:flutter/material.dart';
import 'package:todo_app/screens/home_screen.dart';
void main() {
runApp(TodoApp());
}
class TodoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Todo App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomeScreen(),
);
}
}
Bước 5: Chạy ứng dụng
flutter run
Các tài nguyên học Flutter

Tài liệu chính thức
Khóa học trực tuyến
- Flutter Bootcamp with Dart (Udemy)
- Learn Flutter & Dart to Build iOS & Android Apps (Udemy)
- Flutter & Firebase: Build a Complete App (YouTube - The Net Ninja)
Cộng đồng và Diễn đàn
Packages và Libraries
- Pub.dev - Kho lưu trữ packages và plugins Flutter
Lời kết
Học Flutter có thể là một hành trình thú vị và bổ ích. Bằng cách theo dõi lộ trình này, bạn sẽ dần xây dựng được nền tảng vững chắc và phát triển các ứng dụng di động chất lượng cao. Hãy nhớ rằng, thực hành là chìa khóa để thành thạo Flutter - đừng ngại thử nghiệm và xây dựng các dự án thực tế.
Chúc bạn thành công trên con đường trở thành Flutter Developer!