Flutter: Thêm tương tác vào ứng dụng Flutter

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Mục lục bài viết

Trong bài viết này bạn sẽ tìm hiểu các phần chính:

  • Làm thế nào để hồi đáp các lần nhấn chuột.
  • Cách tạo một widget tùy chỉnh.
  • Sự khác biệt giữa widget trạng thái và không trạng thái.

Làm cách nào để bạn sửa đổi ứng dụng của mình để làm cho ứng dụng phản ứng với đầu vào của người dùng? Trong bài viết này, bạn sẽ thêm tính tương tác vào một ứng dụng chỉ chứa các widget không tương tác. Cụ thể, bạn sẽ sửa đổi một biểu tượng để làm cho nó có thể sử dụng được bằng cách tạo một widget trạng thái tùy chỉnh để quản lý hai widget không trạng thái.

Bài viết Hướng dẫn xây dựng bố cục cho bạn cách tạo bố trí cho các ảnh chụp màn hình sau đây:

Ứng dụng hướng dẫn bố cục
Ứng dụng hướng dẫn bố cục

Khi ứng dụng lần đầu tiên khởi chạy, ngôi sao có màu đỏ đặc, cho thấy rằng hồ trên đã được yêu thích trước đó. Con số bên cạnh ngôi sao chỉ ra rằng 41 người đã yêu thích hồ này. Sau khi hoàn thành hướng dẫn này, việc chạm vào ngôi sao sẽ xóa trạng thái ưa thích của nó, thay thế ngôi sao đặc bằng một đường viền và giảm số lượng. Chạm lại vào hồ yêu thích thì lại vẽ lại một ngôi sao đặc và tăng số lượng.

Tiện ích tùy chỉnh bạn sẽ tạo

Để thực hiện điều này, bạn sẽ tạo một widget tùy chỉnh duy nhất bao gồm cả dấu sao và số lượng, và chính chúng là các widget con. Nhấn vào dấu sao sẽ thay đổi trạng thái cho cả hai widget con, vì vậy, cùng một widget con sẽ quản lý cả hai.

Bạn có thể chạm vào mã ngay trong Bước 2: Phân lớp StatefulWidget. Nếu bạn muốn thử các cách quản lý trạng thái khác nhau, hãy chuyển đến Quản lý trạng thái.

Các widget trạng thái và không trạng thái

Một widget có thể là có trạng thái hoặc không trạng thái. Nếu một tiện ích con có thể thay đổi - ví dụ như khi người dùng tương tác với nó - thì nó ở trạng thái.

Một widget không trạng thái không bao giờ thay đổi. IconIconButton và Text là ví dụ về các widget không trạng thái. Lớp con vật dụng không trạng thái StatelessWidget.

Widget stateful là động: ví dụ, nó có thể thay đổi diện mạo của mình để đáp ứng với các sự kiện kích hoạt bằng cách tương tác người dùng hoặc khi nó nhận được dữ liệu. CheckboxRadioSliderInkWellForm, và TextField là ví dụ về các widget stateful. Lớp con của các widget trạng thái là StatefulWidget.

Trạng thái của widget con được lưu trữ trong đối tượng State, tách biệt trạng thái của tiện ích ra khỏi hình thức của nó. Trạng thái bao gồm các giá trị có thể thay đổi, như giá trị hiện tại của thanh trượt hoặc hộp kiểm có được chọn hay không. Khi trạng thái của widget thay đổi, thì đối tượng trạng thái sẽ gọi setState(), yêu cầu khung vẽ lại widget.

Tạo một widget trạng thái

Vấn đề ở đây là gì?

  • Một widget trạng thái được thực thi bởi hai lớp: lớp con của StatefulWidget và lớp con của State.
  • Lớp trạng thái chứa trạng thái có thể thay đổi của widget con và phương thức build() của widget con.
  • Khi trạng thái của widget thay đổi, đối tượng trạng thái sẽ gọi setState(), yêu cầu framework vẽ lại widget.

Trong phần này, bạn sẽ tạo một widget trạng thái tùy chỉnh. Bạn sẽ thay thế hai widget không trạng thái - dấu sao màu đỏ liền mạch và số đếm bên cạnh - bằng một widget trạng thái tùy chỉnh duy nhất quản lý một hàng có hai widget con: IconButton và Text.

Việc triển khai một widget trạng thái tùy chỉnh yêu cầu tạo hai lớp:

  • Một lớp con của StatefulWidget để định nghĩa widget.
  • Một lớp con của State để chứa trạng thái của widget đó và định nghĩa phương thức build() của widget .

Phần này chỉ cho bạn cách tạo một widget trạng thái được gọi là FavoriteWidget dùng cho app hồ ở trên. Sau khi thiết lập, bước đầu tiên của bạn là chọn cách quản lý trạng thái FavoriteWidget.

Bước 0: Chuẩn bị sẵn sàng

Nếu bạn đã xây dựng app trong hướng dẫn bố cục tòa nhà (bước 6), hãy chuyển sang phần tiếp theo.

  1. Đảm bảo rằng bạn đã thiết lập môi trường của mình.
  2. Tạo ứng dụng Flutter “Hello World” cơ bản.
  3. Thay thế nội dung file lib/main.dart bằng main.dart.
  4. Thay thế nội dung file pubspec.yaml bằng pubspec.yaml.
  5. Tạo một thư mục tên images trong dự án của bạn và thêm ảnh lake.jpg.

Sau khi bạn có thiết bị được kết nối và kích hoạt hoặc bạn đã khởi chạy trình mô phỏng iOS (một phần của cài đặt Flutter) hoặc trình mô phỏng Android (một phần của cài đặt Android Studio), bạn đã sẵn sàng!

Bước 1: Quyết định đối tượng nào quản lý trạng thái của widget

Trạng thái của widget con có thể được quản lý theo nhiều cách, nhưng trong ví dụ của ta, chính widget con FavoriteWidget sẽ quản lý trạng thái của chính nó. Trong ví dụ này, chuyển đổi dấu sao là một hành động riêng biệt không ảnh hưởng đến widget con chính hoặc phần còn lại của giao diện người dùng, vì vậy widget con có thể xử lý trạng thái nội bộ của nó.

Tìm hiểu thêm về cách tách widget con và trạng thái cũng như cách trạng thái có thể được quản lý, trong Trạng thái quản lý.

Bước 2: Phân lớp StatefulWidget

Lớp FavoriteWidget sẽ quản lý trạng thái riêng của mình, vì vậy nó sẽ ghi đè createState() để tạo ra một đối tượng State. Framework sẽ gọi createState() khi nó muốn xây dựng widget con. Trong ví dụ này, createState() sẽ trả về một đối tượng _FavoriteWidgetState và bạn sẽ triển khai trong bước tiếp theo.

lib/main.dart (FavouriteWidget)
class FavoriteWidget extends StatefulWidget {
  @override
  _FavoriteWidgetState createState() => _FavoriteWidgetState();
}

Lưu ý: Các thành viên hoặc lớp bắt đầu bằng dấu gạch dưới ( _) là riêng tư. Để biết thêm thông tin, hãy xem Thư viện và khả năng hiển thị, một phần trong chuyến tham quan ngôn ngữ Dart.

Bước 3: Trạng thái lớp con

Lớp _FavoriteWidgetState lưu trữ các dữ liệu mà có thể thay đổi theo thời gian tồn tại của các widget. Khi ứng dụng lần đầu tiên khởi chạy, giao diện người dùng sẽ hiển thị một ngôi sao màu đỏ đặc, cho biết rằng hồ có trạng thái "yêu thích", cùng với 41 lượt thích. Các giá trị này được lưu trữ trong các trường _isFavorited và _favoriteCount:

lib / main.dart (các trường _FavoriteWidgetState)
class _FavoriteWidgetState extends State<FavoriteWidget> {
  bool _isFavorited = true;
  int _favoriteCount = 41;
  // ···
}

Lớp cũng định nghĩa phương thức build(), phương thức này tạo ra một hàng có chứa IconButton màu đỏ và Text. Bạn sử dụng IconButton (thay vì Icon) vì nó có thuộc tính onPressed để định nghĩa hàm callback (_toggleFavorite) để xử lý một lần nhấn. Tiếp theo, bạn sẽ định nghĩa hàm callback như sau.

lib/main.dart (bản dựng _FavoriteWidgetState)
class _FavoriteWidgetState extends State<FavoriteWidget> {
  // ···
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Container(
          padding: EdgeInsets.all(0),
          child: IconButton(
            padding: EdgeInsets.all(0),
            alignment: Alignment.centerRight,
            icon: (_isFavorited ? Icon(Icons.star) : Icon(Icons.star_border)),
            color: Colors.red[500],
            onPressed: _toggleFavorite,
          ),
        ),
        SizedBox(
          width: 18,
          child: Container(
            child: Text('$_favoriteCount'),
          ),
        ),
      ],
    );
  }
}

Mẹo: Việc đặt Text trong một SizedBox và thiết lập chiều rộng của nó sẽ ngăn cản một "bước nhảy" có thể nhận thấy khi văn bản thay đổi giữa các giá trị 40 và 41 - nếu không sẽ xảy ra một bước nhảy vì các giá trị đó có chiều rộng khác nhau.

Phương thức _toggleFavorite(), được gọi khi IconButton được nhấn, khi đó nó sẽ gọi setState(). Việc gọi setState() là rất quan trọng, vì điều này sẽ cho framework biết rằng trạng thái của widget con đã thay đổi và widget con phải được vẽ lại. Đối số hàm có tác dụng để setState() chuyển đổi giao diện người dùng giữa hai trạng thái này:

  • Một biểu tượng star và số 41
  • Một biểu tượng star_border và số 40
void _toggleFavorite() {
  setState(() {
    if (_isFavorited) {
      _favoriteCount -= 1;
      _isFavorited = false;
    } else {
      _favoriteCount += 1;
      _isFavorited = true;
    }
  });
}

Bước 4: Đưa (plug) widget trạng thái vào cây tiện ích

Thêm widget trạng thái tùy chỉnh của bạn vào cây widget trong phương thức build() của app. Trước tiên ta cần xác định vị trí đoạn mã tạo Icon và Text và xóa nó. Ở cùng một vị trí, hãy tạo widget con trạng thái:

layout/lakes/{step6 → interactive}/lib/main.dart
 
@@ -10,2 +5,2 @@
10
5
  class MyApp extends StatelessWidget {
11
6
   @override
 
@@ -38,11 +33,7 @@
38
33
   ],
39
34
   ),
40
35
   ),
41
 
Icon(
 
36
FavoriteWidget(),
42
 
Icons.star,
43
 
color: Colors.red[500],
44
 
),
45
 
Text('41'),
46
37
   ],
47
38
   ),
48
39
   );
 
@@ -114,3 +105,5 @@
114
105
   ),
115
106
   ),
116
107
   ],
 
108
);
 
109
}

Hoàn thành! Khi bạn tải lại nóng ứng dụng, biểu tượng dấu sao bây giờ sẽ phản hồi với các lần nhấn.

Các vấn đề?

Nếu bạn không thể chạy mã của mình, hãy xem IDE của bạn để biết các lỗi có thể xảy ra. Gỡ lỗi ứng dụng Flutter có thể hữu ích. Nếu bạn vẫn không thể tìm thấy sự cố, hãy kiểm tra mã của bạn với ví dụ về hồ tương tác trên GitHub.

Nếu bạn vẫn còn thắc mắc, hãy tham khảo bất kỳ kênh nào trong số các kênh cộng đồng nhà phát triển.

Phần tiếp theo của bài viết này trình bày một số cách có thể quản lý trạng thái của widget con và liệt kê các widget con tương tác có sẵn khác.

Quản lý trạng thái

Vấn đề ở đây là gì?

  • Có nhiều cách tiếp cận khác nhau để quản lý trạng thái.
  • Bạn, với tư cách là người thiết kế widget, hãy chọn cách tiếp cận để sử dụng.
  • Nếu nghi ngờ, hãy bắt đầu bằng cách quản lý trạng thái trong widget con.

Ai quản lý trạng thái của tiện ích con stateful? Chính các widget đó? Các widget con? Cả hai? Đối tượng khác? Câu trả lời còn phụ thuộc vào nhiều thứ. Có một số cách hợp lệ để làm cho widget con của bạn tương tác. Bạn, với tư cách là người thiết kế widget, đưa ra quyết định dựa trên cách bạn mong đợi widget của mình sẽ được sử dụng. Dưới đây là những cách phổ biến nhất để quản lý trạng thái:

Làm thế nào để bạn quyết định cách tiếp cận để sử dụng? Các nguyên tắc sau sẽ giúp bạn quyết định:

  • Nếu trạng thái được đề cập là dữ liệu người dùng, ví dụ như chế độ được chọn hoặc không được chọn của hộp kiểm hoặc vị trí của thanh trượt, thì trạng thái được quản lý tốt nhất bởi widget con.
  • Nếu trạng thái được đề cập liên quan đến mỹ thuật, chẳng hạn như một hình ảnh động, thì trạng thái đó được quản lý tốt nhất bởi chính widget.

Bạn hãy bắt đầu bằng cách quản lý trạng thái trong widget con xem sao.

Ta sẽ đưa ra các ví dụ về các cách quản lý trạng thái khác nhau bằng cách tạo ba ví dụ đơn giản: TapboxA, TapboxB và TapboxC. Tất cả các ví dụ đều hoạt động tương tự - mỗi ví dụ tạo ra một container mà khi chạm vào sẽ chuyển đổi giữa hộp màu xanh lục hoặc màu xám. Giá trị boolean của _active sẽ xác định màu: màu xanh lá cây là active hoặc màu xám là inactive.

Trạng thái hoạt động Trạng thái không hoạt động

Những ví dụ trên sử dụng GestureDetector để nắm bắt hoạt động trên Container.

Widget tự quản lý trạng thái của nó

Đôi khi, việc widget con quản lý trạng thái nội bộ là điều hợp lý nhất. Ví dụ: ListView tự động cuộn khi nội dung của nó vượt quá hộp kết xuất. Hầu hết các nhà phát triển sử dụng ListView không muốn quản lý hành vi cuộn của ListView, vì vậy ListView chính nó sẽ quản lý độ lệch cuộn của nó.

Lớp _TapboxAState:

  • Quản lý trạng thái cho TapboxA.
  • Định nghĩa _active để xác định màu hiện tại của hộp.
  • Định nghĩa hàm _handleTap() sẽ cập nhật _active khi chạm vào hộp và gọi hàm setState() để cập nhật giao diện người dùng.
  • Triển khai tất cả các hành vi tương tác cho widget con.
// ParentWidget manages the state for TapboxB.

//------------------------ ParentWidget --------------------------------

class ParentWidget extends StatefulWidget {
  @override
  _ParentWidgetState createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
  bool _active = false;

  void _handleTapboxChanged(bool newValue) {
    setState(() {
      _active = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: TapboxB(
        active: _active,
        onChanged: _handleTapboxChanged,
      ),
    );
  }
}

//------------------------- TapboxB ----------------------------------

class TapboxB extends StatelessWidget {
  TapboxB({Key key, this.active: false, @required this.onChanged})
      : super(key: key);

  final bool active;
  final ValueChanged<bool> onChanged;

  void _handleTap() {
    onChanged(!active);
  }

  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: _handleTap,
      child: Container(
        child: Center(
          child: Text(
            active ? 'Active' : 'Inactive',
            style: TextStyle(fontSize: 32.0, color: Colors.white),
          ),
        ),
        width: 200.0,
        height: 200.0,
        decoration: BoxDecoration(
          color: active ? Colors.lightGreen[700] : Colors.grey[600],
        ),
      ),
    );
  }
}

Widget cha quản lý trạng thái của widget con

Thường thì widget cha có ý nghĩa nhất trong việc quản lý trạng thái và thông báo cho widget con của nó khi nào cần cập nhật. Ví dụ: IconButton cho phép bạn coi một biểu tượng như một nút có thể nhấn. IconButton là một widget con không trạng thái vì tiện ích con cần biết liệu nút đã được nhấn hay chưa để có thể thực hiện hành động thích hợp.

Trong ví dụ sau, TapboxB xuất trạng thái của nó sang trạng thái cha của nó thông qua một lệnh callback. Vì TapboxB không quản lý bất kỳ trạng thái nào nên nó phân lớp StatelessWidget.

Lớp ParentWidgetState:

  • Quản lý trạng thái _active cho TapboxB.
  • Triển khai _handleTapboxChanged(), phương thức được gọi khi hộp được chạm vào.
  • Khi trạng thái thay đổi, lời gọi setState() sẽ cập nhật giao diện người dùng.

Lớp TapboxB:

  • Mở rộng StatelessWidget vì tất cả trạng thái được xử lý bởi cha của nó.
  • Khi được nhấn, nó sẽ thông báo cho cha của nó.
// ParentWidget manages the state for TapboxB.

//------------------------ ParentWidget --------------------------------

class ParentWidget extends StatefulWidget {
  @override
  _ParentWidgetState createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
  bool _active = false;

  void _handleTapboxChanged(bool newValue) {
    setState(() {
      _active = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: TapboxB(
        active: _active,
        onChanged: _handleTapboxChanged,
      ),
    );
  }
}

//------------------------- TapboxB ----------------------------------

class TapboxB extends StatelessWidget {
  TapboxB({Key key, this.active: false, @required this.onChanged})
      : super(key: key);

  final bool active;
  final ValueChanged<bool> onChanged;

  void _handleTap() {
    onChanged(!active);
  }

  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: _handleTap,
      child: Container(
        child: Center(
          child: Text(
            active ? 'Active' : 'Inactive',
            style: TextStyle(fontSize: 32.0, color: Colors.white),
          ),
        ),
        width: 200.0,
        height: 200.0,
        decoration: BoxDecoration(
          color: active ? Colors.lightGreen[700] : Colors.grey[600],
        ),
      ),
    );
  }
}

Mẹo: Khi tạo API, hãy cân nhắc sử dụng @required cho bất kỳ thông số nào mà mã của bạn dựa vào. Để sử dụng @required, hãy đưa vào thư viện foundation (xuất lại thư viện meta.dart của Dart):

import 'package:flutter/foundation.dart';

Kết hợp các phương pháp

Đối với một số widget, cách tiếp cận kết hợp các phương pháp có ý nghĩa nhất. Trong trường hợp này, widget trạng thái quản lý một số trạng thái và widget cha quản lý các khía cạnh khác của trạng thái.

Trong ví dụ TapboxC, khi nhấn chuột thì một đường viền màu xanh lá cây đậm sẽ xuất hiện xung quanh hộp. Khi nhả chuột thì đường viền biến mất và màu của hộp thay đổi. TapboxC xuất trạng thái _active của nó cho cha của nó nhưng quản lý trạng thái nội bộ _highlight của nó. Ví dụ này có hai đối tượng State là _ParentWidgetState và _TapboxCState.

Đối tượng _ParentWidgetState:

  • Quản lý trạng thái _active.
  • Triển khai _handleTapboxChanged(), phương thức được gọi khi hộp được chạm vào.
  • Lời gọi setState() để cập nhật giao diện người dùng khi một lần nhấn xảy ra và trạng thái _active thay đổi.

Đối tượng _TapboxCState:

  • Quản lý trạng thái _highlight.
  • GestureDetector lắng nghe tất cả các sự kiện nhấn. Khi người dùng nhấn xuống, nó sẽ thêm phần highlight (được thực hiện dưới dạng đường viền màu xanh lá cây đậm). Khi người dùng nhả nút, nó sẽ xóa phần highlight.
  • Lời gọi setState() để cập nhật giao diện người dùng khi nhấn xuống, nhấn lên hoặc nhấn hủy và trạng thái _highlight sẽ thay đổi.
  • Sự kiện nhấn sẽ truyền thay đổi trạng thái đó cho widget con để thực hiện hành động thích hợp bằng cách sử dụng thuộc tính widget.
//---------------------------- ParentWidget ----------------------------

class ParentWidget extends StatefulWidget {
  @override
  _ParentWidgetState createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
  bool _active = false;

  void _handleTapboxChanged(bool newValue) {
    setState(() {
      _active = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: TapboxC(
        active: _active,
        onChanged: _handleTapboxChanged,
      ),
    );
  }
}

//----------------------------- TapboxC ------------------------------

class TapboxC extends StatefulWidget {
  TapboxC({Key key, this.active: false, @required this.onChanged})
      : super(key: key);

  final bool active;
  final ValueChanged<bool> onChanged;

  _TapboxCState createState() => _TapboxCState();
}

class _TapboxCState extends State<TapboxC> {
  bool _highlight = false;

  void _handleTapDown(TapDownDetails details) {
    setState(() {
      _highlight = true;
    });
  }

  void _handleTapUp(TapUpDetails details) {
    setState(() {
      _highlight = false;
    });
  }

  void _handleTapCancel() {
    setState(() {
      _highlight = false;
    });
  }

  void _handleTap() {
    widget.onChanged(!widget.active);
  }

  Widget build(BuildContext context) {
    // This example adds a green border on tap down.
    // On tap up, the square changes to the opposite state.
    return GestureDetector(
      onTapDown: _handleTapDown, // Handle the tap events in the order that
      onTapUp: _handleTapUp, // they occur: down, up, tap, cancel
      onTap: _handleTap,
      onTapCancel: _handleTapCancel,
      child: Container(
        child: Center(
          child: Text(widget.active ? 'Active' : 'Inactive',
              style: TextStyle(fontSize: 32.0, color: Colors.white)),
        ),
        width: 200.0,
        height: 200.0,
        decoration: BoxDecoration(
          color:
              widget.active ? Colors.lightGreen[700] : Colors.grey[600],
          border: _highlight
              ? Border.all(
                  color: Colors.teal[700],
                  width: 10.0,
                )
              : null,
        ),
      ),
    );
  }
}

Một triển khai thay thế có thể đã xuất trạng thái đánh dấu sang trạng thái chính trong khi vẫn giữ trạng thái hoạt động bên trong, nhưng nếu bạn yêu cầu ai đó sử dụng hộp nhấn đó, họ có thể sẽ phàn nàn rằng điều đó không có ý nghĩa gì. Nhà phát triển quan tâm xem hộp có hoạt động hay không. Nhà phát triển có thể không quan tâm đến cách quản lý phần đánh dấu và muốn hộp nhấn xử lý các chi tiết đó.

Các widget tương tác khác

Flutter cung cấp nhiều loại nút và các widget tương tác tương tự. Hầu hết các widget con này đều triển khai các nguyên tắc Material Design, nguyên tắc này định nghĩa một tập hợp các thành phần với một giao diện người dùng phù hợp.

Nếu muốn, bạn có thể sử dụng GestureDetector để xây dựng tính tương tác vào bất kỳ widget con tùy chỉnh nào. Bạn có thể tìm thấy ví dụ về GestureDetector trong Quản lý trạng thái. Tìm hiểu thêm về GestureDetector trong Handle tap , một công thức trong cookbook Flutter.

Mẹo: Flutter cũng cung cấp một tập hợp các widget kiểu iOS được gọi là Cupertino.

Khi bạn cần sự tương tác, cách dễ nhất là sử dụng một trong những widget có sẵn. Đây là danh sách một số widget có sẵn:

Widget tiêu chuẩn

Thành phần Material

Tài nguyên

Các tài nguyên sau có thể hữu ích khi thêm tính tương tác vào ứng dụng của bạn.

Cử chỉ, một phần trong cookbook Flutter.

Xử lý cử chỉ, một phần trong Giới thiệu về widget con: Cách tạo một nút và làm cho nó phản hồi với đầu vào.

Cử chỉ trong Flutter: Mô tả cơ chế cử chỉ của Flutter.

Tài liệu API Flutter: Tài liệu tham khảo cho tất cả các thư viện Flutter.

Ứng dụng đang chạy Flutter Gallery, repo: Ứng dụng demo giới thiệu nhiều thành phần Material và các tính năng Flutter khác.

Thiết kế phân lớp của Flutter (video): Video này bao gồm thông tin về các widget trạng thái và không trạng thái. Được trình bày bởi kỹ sư của Google, Ian Hickson.

Nguồn: flutter.dev
» Tiếp: Thêm Asset và ảnh
« Trước: Đối phó với các ràng buộc hộp
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!