Skip to main content

Công cụ lập trình & quản lý mã nguồn cho sinh viên IT

· 3 min read

Việc sử dụng thành thạo các công cụ lập trình và quản lý mã nguồn giúp bạn làm việc hiệu quả, chuyên nghiệp và dễ dàng phối hợp nhóm.

1. Git & GitHub/GitLab/Bitbucket

Git Logo GitHub Logo

Git là hệ thống quản lý phiên bản phân tán phổ biến nhất hiện nay. Bạn có thể lưu lại lịch sử thay đổi mã nguồn, dễ dàng quay lại các phiên bản trước, làm việc nhóm hiệu quả.

  • Quản lý lịch sử commit, rollback khi gặp lỗi.
  • Làm việc nhóm: mỗi người một nhánh (branch), merge code, giải quyết xung đột.
  • Kết nối với GitHub/GitLab/Bitbucket để lưu trữ mã nguồn online, review code, CI/CD.

Ví dụ thực tế:

  • Làm đồ án nhóm, mỗi thành viên làm việc trên branch riêng, sau đó merge vào main.
  • Theo dõi lịch sử commit để tìm nguyên nhân lỗi.

2. VS Code / PyCharm / IntelliJ / Eclipse

VS Code Logo PyCharm Logo IntelliJ Logo Eclipse Logo

IDE (Integrated Development Environment) giúp lập trình nhanh, hỗ trợ gỡ lỗi, tự động hoàn thành code, quản lý project.

  • VS Code: Miễn phí, nhẹ, nhiều extension, hỗ trợ nhiều ngôn ngữ.
  • PyCharm/IntelliJ: Mạnh cho Python/Java, nhiều tính năng nâng cao.
  • Eclipse: Phổ biến cho Java, C/C++.

Lợi ích:

  • Tăng tốc độ lập trình, giảm lỗi cú pháp.
  • Quản lý project, tích hợp Git, debug trực tiếp.

3. Postman

Postman Logo

Postman là công cụ test API RESTful, gửi request, kiểm tra response, tự động hóa kiểm thử.

  • Hữu ích khi làm backend, kiểm tra kết nối giữa frontend-backend.
  • Lưu trữ bộ test, chia sẻ cho team.

Ví dụ:

  • Test API đăng nhập, đăng ký, lấy dữ liệu từ server.

4. Docker

Docker Logo

Docker giúp tạo môi trường ảo hóa nhẹ (container), đóng gói ứng dụng cùng môi trường chạy.

  • Dễ dàng deploy, đảm bảo chạy giống nhau trên mọi máy.
  • Đóng gói ứng dụng Python, NodeJS, Java... chỉ với 1 file Dockerfile.

Ví dụ:

  • Chạy web app Python với Docker, không lo lỗi môi trường.
  • Deploy ứng dụng lên server chỉ với 1 lệnh.

5. Terminal / Command Line

Terminal Logo

Terminal/Command Line giúp thao tác nhanh, tự động hóa, quản lý hệ thống.

  • Cài đặt phần mềm, quản lý file, chạy script.
  • Kỹ năng cần thiết cho mọi lập trình viên.

Ví dụ:

  • Sử dụng lệnh git, docker, npm, python trực tiếp trên terminal.

Kết luận:

Việc thành thạo các công cụ trên sẽ giúp bạn làm việc chuyên nghiệp, tăng hiệu suất và dễ dàng phát triển sự nghiệp trong ngành CNTT.

Hướng nghiệp CNTT: Các ngành nghề hot và xu hướng 2024

· 3 min read

Ngành CNTT đang phát triển mạnh mẽ với nhiều cơ hội việc làm hấp dẫn. Bài viết này sẽ giúp bạn định hướng nghề nghiệp phù hợp với xu hướng thị trường.

1. AI & Machine Learning

AI Logo

AI/ML là ngành đang "hot" nhất hiện nay với nhu cầu nhân lực cao và mức lương hấp dẫn.

Công việc chính:

  • Phát triển mô hình AI/ML
  • Xử lý dữ liệu lớn (Big Data)
  • Tích hợp AI vào ứng dụng
  • Nghiên cứu và phát triển thuật toán

Kỹ năng cần có:

  • Python, R, TensorFlow, PyTorch
  • Toán học, thống kê
  • Xử lý dữ liệu
  • Machine Learning algorithms

2. Web Development

Web Dev Logo

Web Development luôn là lựa chọn ổn định với nhiều cơ hội việc làm.

Công việc chính:

  • Frontend Developer (React, Vue, Angular)
  • Backend Developer (Node.js, Python, Java)
  • Full-stack Developer
  • DevOps Engineer

Kỹ năng cần có:

  • HTML, CSS, JavaScript
  • Framework frontend/backend
  • Database (SQL, NoSQL)
  • Git, Docker, CI/CD

3. Mobile App Development

Mobile Dev Logo

Mobile Development đang phát triển mạnh với sự phổ biến của smartphone.

Công việc chính:

  • iOS Developer (Swift)
  • Android Developer (Kotlin)
  • Cross-platform (Flutter, React Native)
  • Mobile App Architect

Kỹ năng cần có:

  • Swift/Kotlin
  • Flutter/React Native
  • UI/UX Design
  • Mobile Testing

4. Cloud Computing

Cloud Logo

Cloud Computing là xu hướng tất yếu với sự phát triển của AWS, Azure, GCP.

Công việc chính:

  • Cloud Architect
  • Cloud Engineer
  • DevOps Engineer
  • Cloud Security Specialist

Kỹ năng cần có:

  • AWS/Azure/GCP
  • Docker, Kubernetes
  • Infrastructure as Code
  • Cloud Security

5. Cybersecurity

Security Logo

Cybersecurity đang trở nên quan trọng hơn bao giờ hết.

Công việc chính:

  • Security Engineer
  • Penetration Tester
  • Security Analyst
  • Security Architect

Kỹ năng cần có:

  • Network Security
  • Ethical Hacking
  • Security Tools
  • Compliance & Risk Management

6. Data Science & Analytics

Data Logo

Data Science giúp doanh nghiệp đưa ra quyết định dựa trên dữ liệu.

Công việc chính:

  • Data Scientist
  • Data Analyst
  • Business Intelligence
  • Data Engineer

Kỹ năng cần có:

  • Python, R
  • SQL, NoSQL
  • Data Visualization
  • Statistical Analysis

Lời khuyên cho sinh viên CNTT

  1. Chọn chuyên ngành phù hợp:

    • Dựa trên sở thích và thế mạnh
    • Theo dõi xu hướng thị trường
    • Tham khảo ý kiến chuyên gia
  2. Xây dựng kỹ năng:

    • Học lập trình cơ bản
    • Thực hành qua dự án thực tế
    • Tham gia cộng đồng CNTT
  3. Tích lũy kinh nghiệm:

    • Làm thêm, thực tập
    • Tham gia hackathon
    • Đóng góp mã nguồn mở
  4. Phát triển kỹ năng mềm:

    • Giao tiếp
    • Làm việc nhóm
    • Tiếng Anh

Kết luận

Ngành CNTT luôn thay đổi và phát triển. Việc chọn đúng hướng đi và liên tục cập nhật kiến thức sẽ giúp bạn thành công trong sự nghiệp. Hãy bắt đầu từ những bước nhỏ, xây dựng nền tảng vững chắc và phát triển theo đam mê của mình.

Hướng nghiệp Data Science & Analytics: Từ A đến Z

· 5 min read

Data Science & Analytics đang là một trong những ngành nghề hot nhất trong lĩnh vực CNTT. Với sự bùng nổ của dữ liệu và nhu cầu phân tích dữ liệu ngày càng tăng, đây là thời điểm tốt để bắt đầu sự nghiệp trong lĩnh vực này.

1. Tổng quan về Data Science & Analytics

Data Science Logo

Data Science & Analytics là ngành kết hợp giữa:

  • Thống kê & Toán học
  • Lập trình & Công nghệ
  • Kiến thức chuyên ngành
  • Kỹ năng giao tiếp & thuyết trình

để phân tích dữ liệu và đưa ra các quyết định kinh doanh dựa trên dữ liệu.

2. Các vị trí công việc phổ biến

2.1. Data Scientist

Mô tả công việc:

  • Phát triển và triển khai các mô hình machine learning
  • Phân tích dữ liệu phức tạp
  • Xây dựng thuật toán dự đoán
  • Tối ưu hóa quy trình kinh doanh

Mức lương tham khảo:

  • Junior: 15-25 triệu VND/tháng
  • Senior: 30-50 triệu VND/tháng
  • Lead/Manager: 50-80 triệu VND/tháng

2.2. Data Analyst

Mô tả công việc:

  • Phân tích dữ liệu kinh doanh
  • Tạo báo cáo và dashboard
  • Đề xuất giải pháp dựa trên dữ liệu
  • Theo dõi KPI và metrics

Mức lương tham khảo:

  • Junior: 12-20 triệu VND/tháng
  • Senior: 25-40 triệu VND/tháng
  • Lead/Manager: 40-60 triệu VND/tháng

2.3. Data Engineer

Mô tả công việc:

  • Xây dựng và duy trì data pipeline
  • Tối ưu hóa database
  • ETL (Extract, Transform, Load)
  • Data warehousing

Mức lương tham khảo:

  • Junior: 15-25 triệu VND/tháng
  • Senior: 30-50 triệu VND/tháng
  • Lead/Manager: 50-80 triệu VND/tháng

2.4. Business Intelligence Analyst

Mô tả công việc:

  • Phân tích xu hướng kinh doanh
  • Tạo báo cáo BI
  • Tư vấn chiến lược
  • Đo lường hiệu suất

Mức lương tham khảo:

  • Junior: 12-20 triệu VND/tháng
  • Senior: 25-40 triệu VND/tháng
  • Lead/Manager: 40-60 triệu VND/tháng

3. Kỹ năng cần thiết

3.1. Kỹ năng kỹ thuật

Ngôn ngữ lập trình:

  • Python (pandas, numpy, scikit-learn)
  • R
  • SQL
  • Scala (cho Big Data)

Công cụ & Framework:

  • TensorFlow, PyTorch
  • Apache Spark
  • Tableau, Power BI
  • Git, Docker

3.2. Kiến thức nền tảng

  • Thống kê & Xác suất
  • Machine Learning
  • Data Mining
  • Data Visualization
  • Big Data Technologies

3.3. Kỹ năng mềm

  • Giao tiếp & Thuyết trình
  • Tư duy phân tích
  • Giải quyết vấn đề
  • Làm việc nhóm
  • Tiếng Anh

4. Lộ trình học tập

4.1. Giai đoạn 1: Nền tảng (3-6 tháng)

  • Học Python cơ bản
  • SQL cơ bản
  • Thống kê cơ bản
  • Excel nâng cao

4.2. Giai đoạn 2: Chuyên sâu (6-12 tháng)

  • Python cho Data Science
  • Machine Learning
  • Data Visualization
  • Big Data basics

4.3. Giai đoạn 3: Thực hành (6-12 tháng)

  • Làm dự án thực tế
  • Tham gia Kaggle competitions
  • Đóng góp open source
  • Tìm việc làm thêm/thực tập

5. Chứng chỉ quan trọng

5.1. Chứng chỉ chung

  • Google Data Analytics Professional Certificate
  • IBM Data Science Professional Certificate
  • Microsoft Certified: Data Analyst Associate

5.2. Chứng chỉ chuyên sâu

  • AWS Certified Data Analytics
  • Google Cloud Professional Data Engineer
  • Databricks Certified Associate

6. Xu hướng thị trường 2024

6.1. Các lĩnh vực hot

  • AI & Machine Learning
  • Big Data Analytics
  • Business Intelligence
  • Data Engineering
  • MLOps

6.2. Công nghệ mới

  • Large Language Models (LLM)
  • AutoML
  • Edge Computing
  • Real-time Analytics
  • Data Mesh

7. Lời khuyên cho người mới bắt đầu

  1. Xác định mục tiêu rõ ràng:

    • Chọn hướng đi phù hợp (Data Scientist, Analyst, Engineer)
    • Đặt mục tiêu ngắn hạn và dài hạn
    • Theo dõi tiến độ học tập
  2. Xây dựng portfolio:

    • Tạo GitHub repository
    • Làm các dự án thực tế
    • Viết blog chia sẻ kiến thức
    • Tham gia cộng đồng Data Science
  3. Tìm mentor & networking:

    • Tham gia các group Data Science
    • Kết nối với chuyên gia trong ngành
    • Tham gia meetup, workshop
    • Tìm mentor hướng dẫn
  4. Liên tục cập nhật:

    • Theo dõi xu hướng mới
    • Học thêm kỹ năng mới
    • Đọc sách, blog, paper
    • Tham gia khóa học online

Kết luận

Data Science & Analytics là ngành nghề đầy tiềm năng với nhiều cơ hội phát triển. Tuy nhiên, để thành công, bạn cần:

  • Kiên trì học tập và thực hành
  • Xây dựng nền tảng vững chắc
  • Liên tục cập nhật kiến thức
  • Phát triển kỹ năng mềm

Hãy bắt đầu từ những bước nhỏ, xây dựng lộ trình học tập phù hợp và kiên trì theo đuổi đam mê của mình.

Nên học ngôn ngữ lập trình nào khi mới bắt đầu?

· 2 min read

Khi mới bắt đầu học lập trình, việc chọn ngôn ngữ phù hợp rất quan trọng. Bài viết này sẽ giúp bạn hiểu rõ về các ngôn ngữ lập trình phổ biến và định hướng nghề nghiệp tương ứng.

1. Python

Python là ngôn ngữ lập trình đa năng, dễ học, được sử dụng rộng rãi trong nhiều lĩnh vực:

  • Phân tích dữ liệu: Thư viện như Pandas, NumPy, Matplotlib.
  • Trí tuệ nhân tạo (AI): TensorFlow, PyTorch, scikit-learn.
  • Lập trình web: Django, Flask, FastAPI.

Python Logo

2. JavaScript

JavaScript là ngôn ngữ không thể thiếu trong phát triển web:

  • Frontend: React, Vue, Angular.
  • Backend: Node.js, Express.
  • Full-stack: MERN (MongoDB, Express, React, Node.js).

JavaScript Logo

3. Java

Java là ngôn ngữ mạnh mẽ, được sử dụng trong nhiều lĩnh vực:

  • Ứng dụng doanh nghiệp: Spring Boot, Hibernate.
  • Phát triển Android: Android Studio.
  • Backend: Microservices, RESTful API.

Java Logo

4. C#

C# là ngôn ngữ của Microsoft, phù hợp cho nhiều ứng dụng:

  • Ứng dụng Windows: WPF, WinForms.
  • Phát triển game: Unity.
  • Backend: .NET Core, ASP.NET.

C# Logo

5. C/C++

C/C++ là ngôn ngữ cấp thấp, mạnh mẽ và hiệu quả:

  • Phần mềm nhúng: IoT, vi điều khiển.
  • Hệ thống: Hệ điều hành, driver.
  • Giải thuật: Hiệu suất cao, tối ưu bộ nhớ.

C++ Logo

6. SQL

SQL là ngôn ngữ truy vấn dữ liệu, nền tảng cho nhiều ngành:

  • Phân tích dữ liệu: Truy vấn, báo cáo.
  • Cơ sở dữ liệu: MySQL, PostgreSQL, SQL Server.
  • Business Intelligence: Data warehousing, ETL.

SQL Logo

7. So sánh và lựa chọn

Python vs JavaScript: Lập trình viên mới nên chọn gì?

  • Python: Dễ học, cú pháp đơn giản, phù hợp cho AI, data science.
  • JavaScript: Bắt buộc cho web, linh hoạt, cộng đồng lớn.

Python vs JavaScript

8. Kết luận

Việc chọn ngôn ngữ lập trình phụ thuộc vào mục tiêu nghề nghiệp của bạn. Hãy bắt đầu với một ngôn ngữ phù hợp và mở rộng kiến thức dần dần.


Hy vọng bài viết giúp bạn định hướng rõ ràng hơn về ngôn ngữ lập trình nên học!

Tổng quan về Power BI và cài đặt môi trường phát triển

· 3 min read

Power BI là công cụ phân tích dữ liệu mạnh mẽ của Microsoft, giúp kết nối, xử lý và trực quan hóa dữ liệu từ nhiều nguồn khác nhau. Bài viết này sẽ giúp bạn hiểu rõ về Power BI, cách cài đặt và các tính năng chính.

1. Giới thiệu về Power BI

Power BI bao gồm ba thành phần chính:

  • Power BI Desktop: Công cụ thiết kế báo cáo và dashboard.
  • Power BI Service: Nền tảng cloud để chia sẻ và cộng tác.
  • Power BI Mobile: Ứng dụng di động để xem báo cáo mọi lúc, mọi nơi.

Kiến trúc Power BI

2. Cài đặt Power BI Desktop

2.1. Yêu cầu hệ thống

  • Windows 10 hoặc mới hơn
  • RAM tối thiểu 4GB
  • Ổ cứng trống 1GB

2.2. Các bước cài đặt

  1. Tải Power BI Desktop từ trang chủ Microsoft
  2. Chạy file cài đặt và làm theo hướng dẫn
  3. Khởi động Power BI Desktop

Quy trình cài đặt Power BI

3. Tính năng chính của Power BI

3.1. Kết nối dữ liệu

  • Hỗ trợ nhiều nguồn dữ liệu: Excel, SQL Server, SharePoint, Web API...
  • Có thể kết hợp nhiều nguồn dữ liệu khác nhau

3.2. Xử lý dữ liệu

  • Power Query Editor: Chuyển đổi và làm sạch dữ liệu
  • DAX (Data Analysis Expressions): Ngôn ngữ công thức mạnh mẽ
  • Mô hình dữ liệu: Tạo mối quan hệ giữa các bảng

3.3. Trực quan hóa dữ liệu

  • Hơn 100 loại biểu đồ và trực quan
  • Tùy chỉnh giao diện và tương tác
  • Drill-down và cross-filtering

Các tính năng chính Power BI

4. Ví dụ thực tế

4.1. Tạo báo cáo doanh số

  1. Kết nối với file Excel chứa dữ liệu doanh số
  2. Tạo các biểu đồ và bảng tổng hợp
  3. Thêm slicer để lọc dữ liệu theo thời gian, sản phẩm
  4. Xuất bản lên Power BI Service

4.2. Dashboard tương tác

  • Tạo dashboard tổng quan về KPI
  • Thêm các biểu đồ tương tác
  • Cấu hình cảnh báo và thông báo

Dashboard Power BI

5. Best Practices

  • Tối ưu hiệu suất:

    • Sử dụng cột tính toán thay vì cột lưu trữ khi có thể
    • Giảm thiểu số lượng biểu đồ trên một trang
    • Sử dụng DirectQuery cho dữ liệu lớn
  • Thiết kế báo cáo:

    • Sử dụng màu sắc nhất quán
    • Đặt tên rõ ràng cho các trường và biểu đồ
    • Thêm chú thích và hướng dẫn sử dụng

6. Tài liệu tham khảo


Hy vọng bài viết giúp bạn hiểu rõ về Power BI và bắt đầu sử dụng công cụ này hiệu quả!

Flutter: Button, TextField và Form widgets

· 4 min read

Button, TextField và Form là những widget quan trọng để tạo giao diện tương tác trong ứng dụng Flutter. Bài viết này sẽ hướng dẫn bạn cách sử dụng chúng một cách hiệu quả.

1. Button Widgets

Flutter cung cấp nhiều loại button khác nhau để phù hợp với các nhu cầu khác nhau.

Button Widget Examples

1.1. ElevatedButton

ElevatedButton(
onPressed: () {
// Xử lý sự kiện khi button được nhấn
},
child: const Text('Elevated Button'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
)

1.2. TextButton

TextButton(
onPressed: () {
// Xử lý sự kiện khi button được nhấn
},
child: const Text('Text Button'),
style: TextButton.styleFrom(
foregroundColor: Colors.blue,
),
)

1.3. IconButton

IconButton(
onPressed: () {
// Xử lý sự kiện khi button được nhấn
},
icon: const Icon(Icons.favorite),
color: Colors.red,
)

1.4. OutlinedButton

OutlinedButton(
onPressed: () {
// Xử lý sự kiện khi button được nhấn
},
child: const Text('Outlined Button'),
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Colors.blue),
),
)

2. TextField Widget

TextField widget được sử dụng để nhận input từ người dùng.

TextField Widget Examples

2.1. Basic TextField

TextField(
decoration: InputDecoration(
labelText: 'Username',
hintText: 'Enter your username',
prefixIcon: const Icon(Icons.person),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
)

2.2. Password TextField

TextField(
obscureText: true,
decoration: InputDecoration(
labelText: 'Password',
hintText: 'Enter your password',
prefixIcon: const Icon(Icons.lock),
suffixIcon: IconButton(
icon: const Icon(Icons.visibility),
onPressed: () {
// Toggle password visibility
},
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
)

2.3. Number TextField

TextField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Age',
hintText: 'Enter your age',
prefixIcon: const Icon(Icons.numbers),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
)

3. Form Widget

Form widget được sử dụng để quản lý và validate nhiều TextField cùng lúc.

Form Widget Examples

3.1. Basic Form

final _formKey = GlobalKey<FormState>();

Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: const InputDecoration(
labelText: 'Email',
hintText: 'Enter your email',
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your email';
}
return null;
},
),
TextFormField(
decoration: const InputDecoration(
labelText: 'Password',
hintText: 'Enter your password',
),
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your password';
}
return null;
},
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// Process form data
}
},
child: const Text('Submit'),
),
],
),
)

3.2. Form với Custom Validation

TextFormField(
decoration: const InputDecoration(
labelText: 'Phone Number',
hintText: 'Enter your phone number',
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your phone number';
}
if (!RegExp(r'^\d{10}$').hasMatch(value)) {
return 'Please enter a valid 10-digit phone number';
}
return null;
},
)

4. Best Practices

4.1. Button

  • Sử dụng đúng loại button cho từng trường hợp
  • Thêm loading state cho button khi cần
  • Xử lý disable state khi cần thiết
  • Sử dụng const constructor khi có thể

4.2. TextField

  • Luôn có label hoặc hint text
  • Sử dụng prefix/suffix icon khi cần
  • Xử lý keyboard type phù hợp
  • Validate input khi cần thiết

4.3. Form

  • Sử dụng Form widget để quản lý nhiều field
  • Implement validation logic rõ ràng
  • Hiển thị error message rõ ràng
  • Xử lý form submission một cách an toàn

Kết luận

Button, TextField và Form là những widget cơ bản nhưng rất quan trọng trong Flutter. Việc hiểu rõ cách sử dụng chúng sẽ giúp bạn tạo ra giao diện người dùng tương tác hiệu quả.


Tài liệu tham khảo:

Cấu trúc dự án Flutter và Hello World app

· 4 min read

Flutter Project Structure

Flutter là một framework phát triển ứng dụng di động đa nền tảng của Google. Bài viết này sẽ giúp bạn hiểu rõ về cấu trúc thư mục của một dự án Flutter và cách tạo ứng dụng Hello World đầu tiên.

1. Cấu trúc thư mục dự án Flutter

Khi tạo một dự án Flutter mới, bạn sẽ thấy cấu trúc thư mục như sau:

my_flutter_app/
├── android/ # Mã nguồn Android
├── ios/ # Mã nguồn iOS
├── lib/ # Mã nguồn Dart chính
├── test/ # Unit tests và widget tests
├── pubspec.yaml # File cấu hình dự án và dependencies
└── README.md # Tài liệu dự án

Giải thích các thư mục chính:

  1. lib/

    • Chứa mã nguồn Dart chính của ứng dụng
    • File main.dart là điểm khởi đầu của ứng dụng
    • Thường được tổ chức theo mô hình:
      lib/
      ├── main.dart
      ├── screens/ # Các màn hình
      ├── widgets/ # Các widget tái sử dụng
      ├── models/ # Các model dữ liệu
      ├── services/ # Các service (API, database)
      └── utils/ # Các tiện ích
  2. android/ios/

    • Chứa mã nguồn native cho từng nền tảng
    • Thường không cần chỉnh sửa trừ khi cần tích hợp native code
  3. test/

    • Chứa các file test
    • Bao gồm unit tests và widget tests
  4. pubspec.yaml

    • File cấu hình quan trọng nhất
    • Định nghĩa:
      • Tên và phiên bản ứng dụng
      • Dependencies
      • Assets (hình ảnh, fonts)
      • Cấu hình build

2. Tạo ứng dụng Hello World

Bước 1: Tạo dự án mới

flutter create hello_world
cd hello_world

Bước 2: Cấu trúc thư mục

lib/
├── main.dart
├── screens/
│ └── home_screen.dart
└── widgets/
└── greeting_widget.dart

Bước 3: Tạo các file

main.dart

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

void main() {
runApp(const MyApp());
}

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

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Hello World App',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
home: const HomeScreen(),
);
}
}

screens/home_screen.dart

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

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

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Hello World'),
),
body: const Center(
child: GreetingWidget(),
),
);
}
}

widgets/greeting_widget.dart

import 'package:flutter/material.dart';

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

@override
Widget build(BuildContext context) {
return const Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Hello, World!',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 16),
Text(
'Welcome to Flutter',
style: TextStyle(
fontSize: 16,
color: Colors.grey,
),
),
],
);
}
}

Bước 4: Chạy ứng dụng

flutter run

3. Giải thích code

MaterialApp

  • Widget gốc của ứng dụng
  • Cung cấp các thành phần cơ bản như theme, navigation
  • useMaterial3: true để sử dụng Material Design 3

Scaffold

  • Widget cung cấp cấu trúc cơ bản cho màn hình
  • Bao gồm AppBar, body, bottom navigation, drawer

StatelessWidget vs StatefulWidget

  • StatelessWidget: Widget không có state
  • StatefulWidget: Widget có state có thể thay đổi

4. Best Practices

  1. Tổ chức code

    • Tách biệt logic và UI
    • Sử dụng các widget có thể tái sử dụng
    • Đặt tên file và class rõ ràng
  2. Quản lý state

    • Sử dụng setState cho state đơn giản
    • Sử dụng state management (Provider, Bloc) cho ứng dụng lớn
  3. Performance

    • Tránh rebuild không cần thiết
    • Sử dụng const constructor khi có thể
    • Tối ưu hóa hình ảnh và assets

Kết luận

Hiểu rõ cấu trúc dự án Flutter và cách tổ chức code là bước đầu tiên quan trọng trong việc phát triển ứng dụng Flutter. Với kiến thức này, bạn có thể bắt đầu xây dựng các ứng dụng phức tạp hơn.


Tài liệu tham khảo:

Cơ bản về ngôn ngữ Dart - Lập trình hướng đối tượng

· 4 min read

Dart OOP Hero

Dart là một ngôn ngữ lập trình hướng đối tượng mạnh mẽ, hỗ trợ đầy đủ các tính năng của OOP. Bài viết này sẽ giúp bạn hiểu rõ về các khái niệm cơ bản của lập trình hướng đối tượng trong Dart.

1. Class và Object

Định nghĩa Class

Class là một khuôn mẫu để tạo ra các đối tượng. Trong Dart, chúng ta định nghĩa class như sau:

class Person {
// Thuộc tính (Properties)
String name;
int age;

// Constructor
Person(this.name, this.age);

// Phương thức (Methods)
void introduce() {
print('Xin chào, tôi là $name, $age tuổi.');
}
}

Tạo và sử dụng Object

void main() {
// Tạo đối tượng từ class
var person = Person('John', 25);

// Gọi phương thức
person.introduce();

// Truy cập thuộc tính
print(person.name); // John
print(person.age); // 25
}

2. Tính đóng gói (Encapsulation)

Dart hỗ trợ tính đóng gói thông qua các access modifier:

class BankAccount {
// Private field (bắt đầu bằng dấu _)
double _balance = 0;

// Getter
double get balance => _balance;

// Setter
set balance(double value) {
if (value >= 0) {
_balance = value;
}
}

// Public method
void deposit(double amount) {
if (amount > 0) {
_balance += amount;
}
}

// Private method
void _updateBalance(double amount) {
_balance = amount;
}
}

3. Kế thừa (Inheritance)

Dart hỗ trợ kế thừa đơn thông qua từ khóa extends:

// Class cha
class Animal {
String name;

Animal(this.name);

void makeSound() {
print('Some sound');
}
}

// Class con
class Dog extends Animal {
Dog(String name) : super(name);

@override
void makeSound() {
print('Woof!');
}

void fetch() {
print('$name is fetching the ball');
}
}

4. Đa hình (Polymorphism)

Dart hỗ trợ đa hình thông qua việc ghi đè phương thức:

class Shape {
double area() {
return 0;
}
}

class Circle extends Shape {
double radius;

Circle(this.radius);

@override
double area() {
return 3.14 * radius * radius;
}
}

class Rectangle extends Shape {
double width;
double height;

Rectangle(this.width, this.height);

@override
double area() {
return width * height;
}
}

5. Interface và Abstract Class

Abstract Class

abstract class Vehicle {
void start();
void stop();

// Có thể có phương thức có sẵn
void honk() {
print('Beep beep!');
}
}

class Car extends Vehicle {
@override
void start() {
print('Car starting...');
}

@override
void stop() {
print('Car stopping...');
}
}

Interface

Trong Dart, mọi class đều là một interface. Chúng ta có thể sử dụng từ khóa implements:

class Flyable {
void fly() {
print('Flying...');
}
}

class Bird implements Flyable {
@override
void fly() {
print('Bird is flying');
}
}

6. Mixins

Mixins cho phép tái sử dụng code giữa các class:

mixin Swimming {
void swim() {
print('Swimming...');
}
}

mixin Flying {
void fly() {
print('Flying...');
}
}

class Duck with Swimming, Flying {
void quack() {
print('Quack!');
}
}

7. Ví dụ thực tế

// Định nghĩa class Product
class Product {
final String id;
final String name;
final double price;

Product(this.id, this.name, this.price);
}

// Định nghĩa class Cart
class Cart {
final List<Product> _items = [];

void addItem(Product product) {
_items.add(product);
}

void removeItem(String productId) {
_items.removeWhere((item) => item.id == productId);
}

double get total => _items.fold(0, (sum, item) => sum + item.price);

void displayItems() {
for (var item in _items) {
print('${item.name}: \$${item.price}');
}
print('Total: \$${total}');
}
}

// Sử dụng
void main() {
var cart = Cart();

cart.addItem(Product('1', 'Laptop', 999.99));
cart.addItem(Product('2', 'Mouse', 29.99));

cart.displayItems();
}

Kết luận

Lập trình hướng đối tượng trong Dart cung cấp một cách tiếp cận mạnh mẽ và linh hoạt để tổ chức và quản lý code. Hiểu rõ các khái niệm cơ bản như class, object, inheritance, polymorphism và encapsulation sẽ giúp bạn viết code Dart hiệu quả và dễ bảo trì hơn.


Tài liệu tham khảo:

Flutter: Quản lý form và validation

· 8 min read

Form là một phần quan trọng trong hầu hết các ứng dụng. Bài viết này sẽ hướng dẫn cách quản lý form và thực hiện validation trong Flutter.

Form Validation

1. Form Widget

1.1. Cấu trúc cơ bản

class MyForm extends StatefulWidget {
@override
_MyFormState createState() => _MyFormState();
}

class _MyFormState extends State<MyForm> {
final _formKey = GlobalKey<FormState>();

@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(
labelText: 'Username',
hintText: 'Enter your username',
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your username';
}
return null;
},
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// Xử lý form
}
},
child: Text('Submit'),
),
],
),
);
}
}

1.2. FormField Widget

class CustomFormField extends FormField<String> {
CustomFormField({
Key? key,
required String label,
required String? Function(String?) validator,
void Function(String?)? onSaved,
}) : super(
key: key,
validator: validator,
onSaved: onSaved,
builder: (FormFieldState<String> state) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label),
TextField(
onChanged: (value) {
state.didChange(value);
},
decoration: InputDecoration(
errorText: state.errorText,
),
),
],
);
},
);
}

2. Validation

2.1. Validation cơ bản

class ValidationForm extends StatefulWidget {
@override
_ValidationFormState createState() => _ValidationFormState();
}

class _ValidationFormState extends State<ValidationForm> {
final _formKey = GlobalKey<FormState>();
String _email = '';
String _password = '';

String? _validateEmail(String? value) {
if (value == null || value.isEmpty) {
return 'Email is required';
}
if (!value.contains('@')) {
return 'Please enter a valid email';
}
return null;
}

String? _validatePassword(String? value) {
if (value == null || value.isEmpty) {
return 'Password is required';
}
if (value.length < 6) {
return 'Password must be at least 6 characters';
}
return null;
}

@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(labelText: 'Email'),
validator: _validateEmail,
onSaved: (value) => _email = value ?? '',
),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
validator: _validatePassword,
onSaved: (value) => _password = value ?? '',
),
ElevatedButton(
onPressed: _submitForm,
child: Text('Submit'),
),
],
),
);
}

void _submitForm() {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
// Xử lý form
}
}
}

2.2. Validation nâng cao

class AdvancedValidationForm extends StatefulWidget {
@override
_AdvancedValidationFormState createState() => _AdvancedValidationFormState();
}

class _AdvancedValidationFormState extends State<AdvancedValidationForm> {
final _formKey = GlobalKey<FormState>();
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
final _confirmPasswordController = TextEditingController();

@override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
_confirmPasswordController.dispose();
super.dispose();
}

String? _validateEmail(String? value) {
if (value == null || value.isEmpty) {
return 'Email is required';
}
final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegex.hasMatch(value)) {
return 'Please enter a valid email';
}
return null;
}

String? _validatePassword(String? value) {
if (value == null || value.isEmpty) {
return 'Password is required';
}
if (value.length < 8) {
return 'Password must be at least 8 characters';
}
if (!value.contains(RegExp(r'[A-Z]'))) {
return 'Password must contain at least one uppercase letter';
}
if (!value.contains(RegExp(r'[0-9]'))) {
return 'Password must contain at least one number';
}
return null;
}

String? _validateConfirmPassword(String? value) {
if (value != _passwordController.text) {
return 'Passwords do not match';
}
return null;
}

@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _emailController,
decoration: InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email),
),
keyboardType: TextInputType.emailAddress,
validator: _validateEmail,
),
TextFormField(
controller: _passwordController,
decoration: InputDecoration(
labelText: 'Password',
prefixIcon: Icon(Icons.lock),
),
obscureText: true,
validator: _validatePassword,
),
TextFormField(
controller: _confirmPasswordController,
decoration: InputDecoration(
labelText: 'Confirm Password',
prefixIcon: Icon(Icons.lock_outline),
),
obscureText: true,
validator: _validateConfirmPassword,
),
ElevatedButton(
onPressed: _submitForm,
child: Text('Register'),
),
],
),
);
}

void _submitForm() {
if (_formKey.currentState!.validate()) {
// Xử lý form
}
}
}

3. Form với Provider

3.1. Form Provider

class FormProvider extends ChangeNotifier {
String _email = '';
String _password = '';
bool _isLoading = false;
String? _error;

String get email => _email;
String get password => _password;
bool get isLoading => _isLoading;
String? get error => _error;

void updateEmail(String value) {
_email = value;
notifyListeners();
}

void updatePassword(String value) {
_password = value;
notifyListeners();
}

Future<void> submitForm() async {
_isLoading = true;
_error = null;
notifyListeners();

try {
// Xử lý form
await Future.delayed(Duration(seconds: 1)); // Giả lập API call
} catch (e) {
_error = e.toString();
} finally {
_isLoading = false;
notifyListeners();
}
}
}

3.2. Form với Provider

class ProviderForm extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => FormProvider(),
child: Consumer<FormProvider>(
builder: (context, formProvider, child) {
return Form(
child: Column(
children: [
TextFormField(
decoration: InputDecoration(labelText: 'Email'),
onChanged: formProvider.updateEmail,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Email is required';
}
return null;
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
onChanged: formProvider.updatePassword,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Password is required';
}
return null;
},
),
if (formProvider.error != null)
Text(
formProvider.error!,
style: TextStyle(color: Colors.red),
),
ElevatedButton(
onPressed: formProvider.isLoading
? null
: formProvider.submitForm,
child: formProvider.isLoading
? CircularProgressIndicator()
: Text('Submit'),
),
],
),
);
},
),
);
}
}

4. Best Practices

4.1. Tách biệt logic validation

class ValidationRules {
static String? validateEmail(String? value) {
if (value == null || value.isEmpty) {
return 'Email is required';
}
final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegex.hasMatch(value)) {
return 'Please enter a valid email';
}
return null;
}

static String? validatePassword(String? value) {
if (value == null || value.isEmpty) {
return 'Password is required';
}
if (value.length < 8) {
return 'Password must be at least 8 characters';
}
return null;
}
}

4.2. Xử lý lỗi và loading state

class FormState {
final bool isLoading;
final String? error;
final Map<String, String> fieldErrors;

FormState({
this.isLoading = false,
this.error,
this.fieldErrors = const {},
});

FormState copyWith({
bool? isLoading,
String? error,
Map<String, String>? fieldErrors,
}) {
return FormState(
isLoading: isLoading ?? this.isLoading,
error: error ?? this.error,
fieldErrors: fieldErrors ?? this.fieldErrors,
);
}
}

5. Ví dụ thực tế

5.1. Form đăng ký

class RegistrationForm extends StatefulWidget {
@override
_RegistrationFormState createState() => _RegistrationFormState();
}

class _RegistrationFormState extends State<RegistrationForm> {
final _formKey = GlobalKey<FormState>();
final _nameController = TextEditingController();
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
bool _isLoading = false;

@override
void dispose() {
_nameController.dispose();
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}

Future<void> _submitForm() async {
if (_formKey.currentState!.validate()) {
setState(() {
_isLoading = true;
});

try {
// Xử lý đăng ký
await Future.delayed(Duration(seconds: 1));
// Chuyển hướng sau khi đăng ký thành công
} catch (e) {
// Hiển thị lỗi
} finally {
setState(() {
_isLoading = false;
});
}
}
}

@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _nameController,
decoration: InputDecoration(
labelText: 'Full Name',
prefixIcon: Icon(Icons.person),
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Name is required';
}
return null;
},
),
TextFormField(
controller: _emailController,
decoration: InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email),
),
keyboardType: TextInputType.emailAddress,
validator: ValidationRules.validateEmail,
),
TextFormField(
controller: _passwordController,
decoration: InputDecoration(
labelText: 'Password',
prefixIcon: Icon(Icons.lock),
),
obscureText: true,
validator: ValidationRules.validatePassword,
),
ElevatedButton(
onPressed: _isLoading ? null : _submitForm,
child: _isLoading
? CircularProgressIndicator()
: Text('Register'),
),
],
),
);
}
}

5.2. Form đăng nhập

class LoginForm extends StatefulWidget {
@override
_LoginFormState createState() => _LoginFormState();
}

class _LoginFormState extends State<LoginForm> {
final _formKey = GlobalKey<FormState>();
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
bool _isLoading = false;
bool _obscurePassword = true;

@override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}

Future<void> _submitForm() async {
if (_formKey.currentState!.validate()) {
setState(() {
_isLoading = true;
});

try {
// Xử lý đăng nhập
await Future.delayed(Duration(seconds: 1));
// Chuyển hướng sau khi đăng nhập thành công
} catch (e) {
// Hiển thị lỗi
} finally {
setState(() {
_isLoading = false;
});
}
}
}

@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _emailController,
decoration: InputDecoration(
labelText: 'Email',
prefixIcon: Icon(Icons.email),
),
keyboardType: TextInputType.emailAddress,
validator: ValidationRules.validateEmail,
),
TextFormField(
controller: _passwordController,
decoration: InputDecoration(
labelText: 'Password',
prefixIcon: Icon(Icons.lock),
suffixIcon: IconButton(
icon: Icon(
_obscurePassword
? Icons.visibility
: Icons.visibility_off,
),
onPressed: () {
setState(() {
_obscurePassword = !_obscurePassword;
});
},
),
),
obscureText: _obscurePassword,
validator: ValidationRules.validatePassword,
),
ElevatedButton(
onPressed: _isLoading ? null : _submitForm,
child: _isLoading
? CircularProgressIndicator()
: Text('Login'),
),
],
),
);
}
}

Kết luận

Quản lý form và validation là một phần quan trọng trong phát triển ứng dụng Flutter. Việc hiểu và áp dụng đúng cách các kỹ thuật quản lý form và validation sẽ giúp bạn tạo ra trải nghiệm người dùng tốt hơn và giảm thiểu lỗi trong ứng dụng.


Tài liệu tham khảo:

Flutter: Navigation và Routing cơ bản

· 4 min read

Navigation và Routing là những khái niệm quan trọng trong phát triển ứng dụng Flutter. Bài viết này sẽ hướng dẫn bạn cách thực hiện điều hướng giữa các màn hình và quản lý route trong ứng dụng Flutter.

Navigation &amp; Routing

1. Navigation cơ bản

1.1. Điều hướng đơn giản

// Điều hướng đến màn hình mới
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondScreen()),
);

// Quay lại màn hình trước
Navigator.pop(context);

1.2. Điều hướng với tham số

// Điều hướng và truyền tham số
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen(item: item),
),
);

// Nhận tham số trong màn hình đích
class DetailScreen extends StatelessWidget {
final Item item;

const DetailScreen({Key? key, required this.item}) : super(key: key);

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(item.title)),
body: Center(child: Text(item.description)),
);
}
}

2. Named Routes

2.1. Định nghĩa routes

MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => HomeScreen(),
'/details': (context) => DetailScreen(),
'/settings': (context) => SettingsScreen(),
},
);

2.2. Điều hướng với named routes

// Điều hướng đến route đã đặt tên
Navigator.pushNamed(context, '/details');

// Điều hướng và truyền tham số
Navigator.pushNamed(
context,
'/details',
arguments: item,
);

// Nhận tham số trong màn hình đích
class DetailScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final item = ModalRoute.of(context)!.settings.arguments as Item;
return Scaffold(
appBar: AppBar(title: Text(item.title)),
body: Center(child: Text(item.description)),
);
}
}

3. Nested Navigation

3.1. Bottom Navigation Bar

class MainScreen extends StatefulWidget {
@override
_MainScreenState createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
int _selectedIndex = 0;

final List<Widget> _screens = [
HomeScreen(),
SearchScreen(),
ProfileScreen(),
];

@override
Widget build(BuildContext context) {
return Scaffold(
body: _screens[_selectedIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: (index) {
setState(() {
_selectedIndex = index;
});
},
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
],
),
);
}
}

3.2. TabBar

class TabScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.home), text: 'Home'),
Tab(icon: Icon(Icons.search), text: 'Search'),
Tab(icon: Icon(Icons.person), text: 'Profile'),
],
),
),
body: TabBarView(
children: [
HomeScreen(),
SearchScreen(),
ProfileScreen(),
],
),
),
);
}
}

4. Best Practices

4.1. Quản lý Route

  • Sử dụng named routes cho các màn hình chính
  • Tổ chức routes theo cấu trúc rõ ràng
  • Xử lý các trường hợp route không tồn tại
MaterialApp(
onUnknownRoute: (settings) {
return MaterialPageRoute(
builder: (context) => NotFoundScreen(),
);
},
);

4.2. Xử lý Back Button

WillPopScope(
onWillPop: () async {
// Xử lý khi người dùng nhấn nút back
return await showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Thoát?'),
content: Text('Bạn có muốn thoát không?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: Text('Không'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: Text('Có'),
),
],
),
);
},
child: Scaffold(
// ...
),
);

4.3. Deep Linking

MaterialApp(
onGenerateRoute: (settings) {
// Xử lý deep link
if (settings.name?.startsWith('/product/') ?? false) {
final productId = settings.name!.split('/').last;
return MaterialPageRoute(
builder: (context) => ProductScreen(id: productId),
);
}
return null;
},
);

5. Ví dụ thực tế

5.1. Ứng dụng E-commerce

class EcommerceApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => HomeScreen(),
'/categories': (context) => CategoriesScreen(),
'/product': (context) => ProductScreen(),
'/cart': (context) => CartScreen(),
'/checkout': (context) => CheckoutScreen(),
},
);
}
}

5.2. Ứng dụng Social Media

class SocialApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => FeedScreen(),
'/profile': (context) => ProfileScreen(),
'/messages': (context) => MessagesScreen(),
'/notifications': (context) => NotificationsScreen(),
},
);
}
}

Kết luận

Navigation và Routing là những khái niệm cơ bản nhưng quan trọng trong phát triển ứng dụng Flutter. Việc hiểu rõ và áp dụng đúng cách sẽ giúp bạn tạo ra trải nghiệm người dùng tốt hơn.


Tài liệu tham khảo: