Skip to content
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Fx Studio
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Flutter
Written by chuotfx on October 3, 2022

Ứng dụng Flutter đầu tiên

Flutter & Dart

Contents

  • New Project
    • Project structure
    • Main
    • MyApp
  • Hello again!
  • New Page
    • Stateless Widget
    • Stateful Widget
      • Create
      • Override
      • Update State
  • Tạm kết

Chào mừng bạn đến với Fx Studio. Chúng ta đã tìm hiểu về Flutter và cài đặt được SDK để có thể code rồi. Bài viết này sẽ giúp bạn tạo một ứng dụng đơn giản nhất. Mục đích đem lại cho bạn cái nhìn tổng quan về ứng dụng Flutter trước. Sau đó, chúng ta mới tìm hiểu các thành phần trong ứng dụng hay cấu thành giao diện của Flutter. Chủ đề là The First App.

Nếu bạn chưa biết cài đặt SDK và Hello world, thì có thể tham khảo bài viết dưới đây.

  • Cài đặt Flutter SDK & Hello world

Nếu mọi việc đã ổn rồi, thì …

Bắt đầu thôi!

New Project

Chúng ta sẽ tạo mới một Project hoặc bạn có thể dùng lại Project từ bài trước cũng được. Mình tóm tắt lại cho bạn là chúng ta có 2 cách tạo project Flutter là:

  • Android Studio (hay Visual Studio Code), giao diện trực quan
  • Command Line với cách dùng lệnh để tạo

Mình sẽ dùng lại Project hello_flutter ở bài trước. Cho tiết kiệm nhoé.

Project structure

Trước tiên, bạn cần biết về cấu trúc một Project Flutter bao gồm những gì trước đã. Xem hình sau:

Đầu tiên, bạn chưa cần quan tâm tới các file ẩn nhoé. Chúng ta sẽ tìm hiểu nó ở các chương sau cùng của series này. Ở đây sẽ chứa rất nhiều các file, nhưng trong khuôn khổ bài viết, chúng ta chỉ cần chú ý đến các file sau :

  • android / ios : 2 folder này sẽ chứa code native. Trong khi làm việc, chúng ta sẽ nhận thấy khó vài trường hợp Flutter không thể giải quyết tất cả các bài toàn mà phải nhờ đến native code.
    • Có thể xem đó là 2 project cho Android & iOS mà Flutter sinh ra cho bạn.
    • Ví dụ như iOS thì bạn dùng nó để submit app lên store
    • Ta sẽ sử dụng ở sau này thôi, tạm thời biết vậy là ổn rồi
  • lib: đây là folder chính chúng ta sẽ làm việc, nơi này sẽ chứa gần như tất cả source code của 1 project flutter sẽ gồm các file source dart, các pakage.
  • test: nơi chúng ta tạo ra các unit-test case.
  • pubspec.yaml : file này là nơi khai báo các thư viện, config hệ thống,… Nếu các các bạn đã từng làm việc với native Android thì nó sẽ tương tự như file gradle.
  • Ngoài ra khi làm chúng ta có thể tạo thêm file như assets để chứa các resource như ảnh, icon, …

Main

Khi đã nắm được về cấu trúc của một project rồi. Chúng ta thử tuỳ biến code xem sao. Bạn mở file main.dart và xem từ trên xuống nhoé. Đâu tiên là đoạn code này:

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

Không cần quá suy nghĩ nhiều thì đích thị đây là hàm main và nó sẽ là hàm đầu tiên được chạy trong project. Trong hàm main, bạn sẽ thấy dòng lệnh duy nhất là runApp và một đối tượng MyApp() được truyền vào.

Bằng kinh nghiệm lập trình 10 mấy năm của mình thì suy luận rằng.

MyApp chính là ứng dụng của chúng ta rồi.

Và chúng ta có thể tạo thêm các lớp khác tương tự như MyApp. Để làm nhiệm vụ như MyApp đang làm.

MyApp

Ta tiếp tục xem code của MyApp như thế nào.

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Fx Studio'),
    );
  }
}

Trong đó:

  • MyApp kế thừa (extends) từ StatelessWidget, chứ không phải một thể loại App nào đó.
  • Bản thân nó đang returen về MaterialApp. À há, đuôi con thằn lằn là đây rồi.
  • Bỏ qua các phần râu ria, tập trung vào home của MaterialApp. Nó đang lại khởi tạo một đối tượng là MyHomePage

Bằng suy luận tiếp, thì chúng ta nhanh chóng hiểu được rằng

  • MyApp không quan trọng
  • Có 2 thứ làm MyApp quan trọng đó là StatelessWidget & MaterialApp
  • Có vẻ MaterialApp là đối tượng chính của ta cần phải phân tích

Và mọi thứ giống như bạn đang chơi lắp ráp lego vậy. Thực thể được lắp ráp là Widget, nó được xem là trái tim của toàn bộ giao diện.

StatelessWidget là một widget sẽ không thay đổi nội dung của nó sau khi khởi chạy ứng dụng.

MaterialApp là container chứa toàn bộ ứng dụng. Chúng ta sẽ có nhiều màn hình khác nhau, nên ta có thể tạo thêm nhiều page tương tự như MyHomePage để thay thế.

Hello again!

Bạn đã nắm được cấu trúc project và các thành phần cơ bản cấu thành nên ứng dụng Flutter rồi. Tuy nhiên, code sinh ra quá nhiều và nhìn rối mắt quá. Ta sẽ làm màu nó lại.

Bước đầu tiên, bạn xoá toàn bộ code trong file main.dart nhoé. Tiếp theo, bạn thêm đoạn code này vào.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Fx Studio'),
        ),
        body: Center(
          child: Text('Hello again!'),
        ),
      ),
    );
  }
}

Đây chính là phiên bản thu gọn lại của Hello world nhoé. Với nó thì bạn sẽ dễ hiểu hơn nhiều.

Trong đó:

  • Vì hàm main chỉ có 1 dòng lệnh nên ta dùng cú pháp thu gọn của function với toán tử =>
  • Vẫn khởi tạo đối tượng MyApp
  • Thay vì home cần có 1 Page nào đó, ta sẽ dùng 1 widgets là Scaffold. Nó cũng là thành phần cấu tạo chính của một Page nào đó trong project.
  • Scaffold cung cấp cho ta
    • Một appBar tương tự như NavigationBar trong iOS
    • Bạn có thể xét lại title của AppBar
    • body là nội dung hiển thị chính.
    • Tạo 1 widget là Center & 1 Text. Nó sẽ hiển thị dòng chữ Hello again! ở chính giữa màn hình.

Hãy build project và cảm nhận kết quả nhoé!

flutter

Bạn thử thay đổi thêm code của chúng ta như sau:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
      home: Scaffold(
        // .....
      ),
    );
  }
}

Trong đó:

  • theme được thêm vào MaterialApp với đối tượng ThemeData
  • Chúng ta chọn màu là Colors.green

Bạn không cần build lại project mà chỉ cần nhấn vào nút Hot Restart. Ứng dụng nhanh chóng được cập nhật lại toàn bộ. Tiết kiệm thời gian build app nhoé.

New Page

Mình sẽ dùng hậu tố Page cho các màn hình trong Flutter Project. Vì cũng dùng theo cách đặt tên của Flutter trong mẫu ví dụ là MyHomePage.

Một điều hiển nhiên là bạn không thể nhét hết tất cả vào trong 1 file như main.dart rồi. Do đó, ta sẽ tạo một file mới để chưa một Page mới. Chúng ta sẽ có 2 cách tạo 1 Page theo 2 kiểu mục đích sử dụng.

Stateless Widget

Bạn tạo một file với tên là home_page.dart tại thư mục lib trong project nhoé. Sau đó, ta sẽ bắt đầu thêm code cho màn hình đầu tiên. Tham khảo ví dụ code sau:

import 'package:flutter/material.dart';

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: AppBar(
        title: Text("Home"),
      ),
      body: new Center(
        child: Text("Home Page"),
      ),
    );
  }
}

Vì HomePage mới chúng ta sẽ không có thay đổi gì nội dung (tức hiển thị tĩnh) thì ta sẽ extends với StatelessWidget. Khi bạn kế thừa StatelessWidget, thì bạn cần override lại hàm build.

  • Tham số context và kiểu dữ liệu BuildContext ta sẽ tìm hiểu sau nhoé.

Tại hàm build, chúng ta return về một đối tượng Scaffold.

Scaffold cho phép chúng ta triển khai các widget ứng dụng chuẩn material mà hầu hết các ứng dụng đều có. Chẳng hạn như AppBar, BottomAppBar, FloatingActionButton, BottomSheet, Drawer, Snackbar… Scaffold được thiết kế để trở thành vùng chứa cấp cao nhất cho MaterialApp mặc dù không cần thiết phải lồng một Scaffold.

Tại Scaffold, bạn chỉ cần khai báo các tham số cần thiết sau:

  • title
  • body

Cuối cùng, bạn cập nhật lại ở file main.dart nha. Để đứa đối tượng HomePage() vào. Tham khảo code nha:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
      home: HomePage()
    );
  }
}

Chú ý mỗi home cài MaterialApp thôi nhoé, Bạn bấm lại Hot restart và cảm nhận kết quả!

flutter

Stateful Widget

Đây là cách thứ 2 để bạn tạo một màn hình hay page với nội dung thay đổi được trong thời gian ứng dụng hoạt động. Thay vì bạn kế thừa StatelessWidget, thì bạn sẽ kế thừa StatefulWidget. Nhưng sẽ có một số điểm khác nhau.

Create

Bắt đầu, bạn sẽ tạo một file là counter_page.dart nhoé. Một StatefulWidget có một chút khác biệt so với StatelessWidget. Nó gồm hai class:

  • State object
  • widget chính.

Mục đích của class này là duy trì state khi Flutter re-render các widget. Ở đây, sẽ có bạn nhầm lẫn cho rằng State là trạng thái của các biến. Nhưng thực tế State là trạng thái của cả 1 widget.

class CounterPage extends StatefulWidget {
  
}

class _CounterPageState extends State<CounterPage> {
  
}

Ta có ví dụ cho CounterPage với StatefulWidget nhoé. Với

  • CounterPage là widget
  • _CounterPageState là State

Sử dụng tiền tố _ của State thì để xem nó là sở hữu riêng của StatefulWidget mà thôi.

Override

Chúng ta sẽ cần phải viết thêm các phương thước cần thiết cho 2 class trên. Với:

  • StatefulWidget thì cần createState để tạo đối tượng State
  • State<> thì cần build để tạo các Widget và quản lý các trạng thái dữ liệu

Xem code ví dụ nhoé!

class CounterPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new _CounterPageState();
  }
}

class _CounterPageState extends State<CounterPage> {
  
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: AppBar(
          title: Text("Home"),
        ),
        body: new Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text("Ahihi!"),
            OutlinedButton(
              onPressed: () {
                print('Received click');
              },
              child: const Text('Click Me'),
            )
          ],
        ));
  }
}

Tiện thể, mình bổ sung thêm giao diện cho State bao gồm như sau:

  • Scaffold tương tự với cách dùng StatelessWidget
  • Tại body của Scaffold, tạo mới 1 Column. Chúng là 1 bố cụ layout, bạn sẽ tìm hiểu sau nhoé
  • Column là 1 container, nên nó có thể chứa nhiều widget khác. Chúng sẽ được khai báo vào children, một Array Widget.
  • Trong đó, ta có 1 Text và 1 Button. Nội dung của 2 widget này khá đơn giản. Ta chỉ cần quan tâm tới onPressed là được.

Update State

Điều bạn cần làm được tiếp nữa là việc bạn thay đổi được nội dung hiển thi của màn hình với StatefulWidget nhoé. Trước tiên, bạn cần có một thuộc tính để lưu trữ dữ liệu. Bạn khai báo như sau vào lớp State nhoé!

var count = 0;

Ta có một biến Int là count. Tiếp theo, ta sẽ hiển thị nó lên Text. Bạn chỉnh sửa lại Text như sau:

Text("Count: $count"),

Cuối cùng, ta sẽ cập nhật giá trị tại onPressed của Button. Bạn tham khảo tiếp nhoé!

OutlinedButton(
  onPressed: () {
    print('Received click');
    setState(() {
      count += 1;
    });
  },
  child: const Text('Click Me'),
)

Với việc gọi hàm setState() trong đó với nội dung là thay đổi giá trị của thuộc tính. Thì các phần giao diện nào liên quan tới thuộc tính đó sẽ được render lại. Tức là được cập nhật lại về mặt nội dung.

Tương tự như SwiftUI, nhưng ta phải cần thêm hàm setState() để cập nhật giá trị.

Tóm lại, khi người dùng kích vào Button. Giá trị của count sẽ tăng lên 1 đơn vị. Với setState thì đi kèm với việc count tăng giá trị, là Text sẽ được render lại với giá trị mới của count.

Cuối cùng, bạn thay đổi lại đối tượng CounterPage cho HomePage ở main nhoé. Và bạn bấm Hot Restart và test lại nhoé.

flutter

Tạm kết

  • Tìm hiểu về cấu trúc Flutter Project và các thành phần trong Flutter Project
  • Main & các thành phần cấu tạo nên MyApp
  • Tạo một màn hình / page mới trong Project
  • Sử dụng StatelessWidget & StatefulWidget
  • Cập nhật giao diện & dữ liệu cơ bản với StatefulWidget

 

Okay! Tới đây, mình xin kết thúc bài viết Ứng dụng Flutter đầu tiên. Nếu có gì thắc mắc hay góp ý cho mình thì bạn có thể để lại bình luận hoặc gửi email theo trang Contact.

  • Bạn có thể checkout code tại đây.
  • Bài viết tiếp theo tại đây.

Cảm ơn bạn đã đọc bài viết này!

FacebookTweetPinYummlyLinkedInPrintEmailShares27

Related Posts:

  • Dart Defines
    Dart Defines trong Flutter và sức mạnh của nó
  • Flavor
    Flavor & Câu chuyện config trong Flutter
  • Flutter
    Giới thiệu về Flutter
  • Flutter
    Make color App Flutter
Tags: flutter
Written by chuotfx

Hãy ngồi xuống, uống miếng bánh và ăn miếng trà. Chúng ta cùng nhau đàm đạo về đời, về code nhóe!

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Donate – Buy me a coffee!

Fan page

Fx Studio

Tags

Actor Advanced Swift AI api AppDistribution autolayout basic ios tutorial blog ci/cd closure collectionview combine concurrency crashlytics dart dart basic dart tour Declarative delegate deploy design pattern fabric fastlane firebase flavor flutter GCD gradients iOS MVVM optional Prompt engineering protocol Python rxswift safearea Swift Swift 5.5 SwiftData SwiftUI SwiftUI Notes tableview testing TravisCI unittest

Recent Posts

  • Role-playing vs. Persona-based Prompting
  • [Swift 6.2] Raw Identifiers – Đặt tên hàm có dấu cách, tại sao không?
  • Vibe Coding là gì?
  • Cách Đọc Sách Lập Trình Nhanh và Hiệu Quả Bằng GEN AI
  • Nỗ Lực – Hành Trình Kiến Tạo Ý Nghĩa Cuộc Sống
  • Ai Sẽ Là Người Fix Bug Khi AI Thống Trị Lập Trình?
  • Thời Đại Của “Dev Tay To” Đã Qua Chưa?
  • Prompt Engineering – Con Đường Để Trở Thành Một Nghề Nghiệp
  • Vấn đề Ảo Giác (hallucination) khi tương tác với Gen AI và cách khắc phục nó qua Prompt
  • Điều Gì Xảy Ra Nếu… Những Người Dệt Mã Trở Thành Những Người Bảo Vệ Cuối Cùng Của Sự Sáng Tạo?

You may also like:

  • Giới thiệu về Flutter
    Flutter
  • Flavor & Câu chuyện config trong Flutter
    Flavor
  • Make color App Flutter
    Flutter
  • Cài đặt Flutter SDK & Hello world
    Flutter
  • Dart Defines trong Flutter và sức mạnh của nó
    Dart Defines

Archives

  • May 2025 (2)
  • April 2025 (1)
  • March 2025 (8)
  • January 2025 (7)
  • December 2024 (4)
  • September 2024 (1)
  • July 2024 (1)
  • June 2024 (1)
  • May 2024 (4)
  • April 2024 (2)
  • March 2024 (5)
  • January 2024 (4)
  • February 2023 (1)
  • January 2023 (2)
  • November 2022 (2)
  • October 2022 (1)
  • September 2022 (5)
  • August 2022 (6)
  • July 2022 (7)
  • June 2022 (8)
  • May 2022 (5)
  • April 2022 (1)
  • March 2022 (3)
  • February 2022 (5)
  • January 2022 (4)
  • December 2021 (6)
  • November 2021 (8)
  • October 2021 (8)
  • September 2021 (8)
  • August 2021 (8)
  • July 2021 (9)
  • June 2021 (8)
  • May 2021 (7)
  • April 2021 (11)
  • March 2021 (12)
  • February 2021 (3)
  • January 2021 (3)
  • December 2020 (3)
  • November 2020 (9)
  • October 2020 (7)
  • September 2020 (17)
  • August 2020 (1)
  • July 2020 (3)
  • June 2020 (1)
  • May 2020 (2)
  • April 2020 (3)
  • March 2020 (20)
  • February 2020 (5)
  • January 2020 (2)
  • December 2019 (12)
  • November 2019 (12)
  • October 2019 (19)
  • September 2019 (17)
  • August 2019 (10)

About me

Education, Mini Game, Digital Art & Life of coders
Contacts:
contacts@fxstudio.dev

Fx Studio

  • Home
  • About me
  • Contact us
  • Mail
  • Privacy Policy
  • Donate
  • Sitemap

Categories

  • Art (1)
  • Blog (44)
  • Code (11)
  • Combine (22)
  • Flutter & Dart (24)
  • iOS & Swift (102)
  • No Category (1)
  • RxSwift (37)
  • SwiftUI (80)
  • Tutorials (87)

Newsletter

Stay up to date with our latest news and posts.
Loading

    Copyright © 2025 Fx Studio - All rights reserved.