Chuyển đến nội dung chính

Getting Started With Flutter

 


Phụ lục:

  1. Getting Started

  • Giới thiệu về Flutter

  • Thiết lập môi trường phát triển của bạn

  • Tạo dự án mới

  • Chỉnh sửa mã

  • Chạy ứng dụng

  1. Sử dụng Hot Reload

  2. Nhập tệp

  3. Understanding Widgets

  • Tạo Widgets

  1. Thực hiện cuộc gọi mạng

  • Nhập Packages

  • Sử dụng Asynchronous Code

  1. Sử dụng ListView

  • Adding Dividers

  1. Phân tích cú pháp thành các loại tuỳ chỉnh

  2. Tải xuống hình ảnh bằng NetworkImage

  3. Cleaning up the Code

  4. Adding a Theme

  5. Where to Go From Here?


Đi sâu vào khuôn khổ Flutter, cho phép bạn xây dựng các ứng dụng IOS, Android, web và máy

tính để bàn với một cơ sở mã duy nhất, bằng cách viết một ứng dụng đa nền tảng bằng VS Code.

Với các hệ điều hành khác nhau chạy trên các thiết bị di động và máy tính để bàn trên thế giới, phát triển đa nền tảng từ lâu đã trở thành mục tiêu phát triển ứng dụng. Có thể viết một codebase và triển khai trên nhiều nền tảng giúp tiết kiệm đáng kể thời gian và công sức cho công ty và nhóm của bạn.

Một trong những khuôn khổ gần đây nhất để tham gia vào đấu trường đa nền tảng là Flutter của Google. Mặc dù Flutter ban đầu chỉ hỗ trợ nền tảng di động Android và IOS, nhưng sau đó nó đã mở rộng để bao gồm hỗ trợ web, macOS, Windows, Linux, Fuchsia và các thiết bị nhúng. Điều này - kết hợp với chu kỳ phát triển nhanh của Flutter, thiết kế giao diện người dùng linh hoạt và hiệu suất ứng dụng gốc - khiến nó trở thành mục tiêu rất hấp dẫn đối với các nhà phát triển mới và có kinh nghiệm.

Trong hướng dẫn này, bạn sẽ xây dựng một ứng dụng Flutter có tên là GHFlutter truy vấn API GitHub cho các thành viên nhóm trong tổ chức GitHub và hiển thị thông tin trong danh sách có thể cuộn:


Bạn có thể phát triển ứng dụng bằng Trình mô phỏng iOS, Trình mô phỏng Android, trình duyệt web, ứng dụng dành cho máy tính để bàn gốc hoặc tất cả những cách trên!

  1. Getting Started

Bạn có thể sử dụng macOS, Linux, Windows hoặc Chrome OS để phát triển Flutter của mình. Trong khi bạn có thể sử dụng bất kỳ trình chỉnh sửa nào với chuỗi công cụ Flutter, có các plugin IDE cho IntelliJ IDEA, Android StudioVisual Studio Code giúp chu trình phát triển dễ dàng hơn.

Hướng dẫn này sử dụng VS Code.

  • Introduction to Flutter

Ứng dụng Flutter sử dụng ngôn ngữ lập trình Dart. Dart chia sẻ nhiều tính năng của các ngôn ngữ hiện đại khác, chẳng hạn như Kotlin và Swift. Bạn cũng có thể biên dịch Dart thành mã JavaScript. Nếu bạn muốn tìm hiểu thêm về Dart trước khi tiếp tục với hướng dẫn Flutter này, hãy xem hướng dẫn Cơ bản về Dart của chúng tôi.


Là một khuôn khổ đa nền tảng, Flutter gần giống nhất với React Native. Cả hai đều cho phép một kiểu lập trình phản ứng và khai báo. Tuy nhiên, không giống như React Native, Flutter không cần sử dụng cầu nối JavaScript, giúp cải thiện thời gian khởi động ứng dụng và hiệu suất tổng thể. Dart đạt được điều này bằng cách sử dụng biên dịch Ahead-Of-Time (AOT).


Dart cũng có thể sử dụng biên dịch Just-In-Time (JIT). Việc biên dịch JIT với Flutter cải thiện quy trình phát triển bằng cách cho phép khả năng tải lại nóng để làm mới giao diện người dùng trong quá trình phát triển mà không cần bản dựng hoàn toàn mới.


Như bạn sẽ thấy trong hướng dẫn này, khung Flutter được xây dựng dựa trên ý tưởng về các widget. Trong Flutter, bạn không chỉ sử dụng tiện ích con cho các chế độ xem ứng dụng của mình mà còn cho toàn bộ màn hình và thậm chí cho chính ứng dụng.


  • Thiết lập môi trường phát triển của bạn


Tìm hướng dẫn để thiết lập máy phát triển của bạn với khung Flutter trên Get started page của Flutter. Các bước cụ thể khác nhau tùy theo nền tảng, nhưng chúng tuân theo định dạng cơ bản sau:

1.Tải xuống gói cài đặt cho hệ điều hành của máy phát triển của bạn để nhận bản phát hành ổn định mới nhất của Flutter SDK.

2.Giải nén gói cài đặt ở vị trí mong muốn.

3.Thêm công cụ flutter vào đường dẫn của bạn.

4.Chạy lệnh Flutter doctor, lệnh này sẽ cảnh báo bạn về bất kỳ sự cố nào với quá trình cài đặt Flutter.

5.Cài đặt các phần phụ thuộc bị thiếu.

6.Thiết lập IDE của bạn với một plugin / tiện ích mở rộng Flutter.

7.Lái thử một ứng dụng.


Các hướng dẫn được cung cấp trên trang web Flutter được thực hiện rất tốt và cho phép bạn dễ dàng thiết lập môi trường phát triển trên nền tảng bạn chọn. Phần còn lại của hướng dẫn này giả định rằng bạn đã thiết lập Mã VS để phát triển Flutter và rằng bạn đã giải quyết bất kỳ vấn đề nào mà bác sĩ phát hiện được. Bạn cũng có thể sử dụng Android Studio để làm theo.


Để chạy dự án của bạn dưới dạng ứng dụng dành cho thiết bị di động, bạn sẽ cần sử dụng một trong các tùy chọn sau:


+Chạy Trình mô phỏng iOS hoặc Trình mô phỏng Android.

+Có thiết bị IOS hoặc Android được thiết lập để phát triển.

+Chạy mã của bạn dưới dạng ứng dụng web.

+Cuối cùng, bạn có thể chạy mã của mình dưới dạng ứng dụng dành cho máy tính để bàn.


Ngay cả khi mục tiêu cuối cùng của bạn là thiết bị di động, việc sử dụng ứng dụng web hoặc máy tính để bàn trong quá trình phát triển sẽ mang lại cho bạn lợi thế là có thể thay đổi kích thước ứng dụng và quan sát ứng dụng trông như thế nào với các kích thước màn hình khác nhau. Nếu bạn có máy tính cũ hơn, phiên bản web hoặc máy tính để bàn cũng sẽ tải nhanh hơn so với trình giả lập Android hoặc Trình mô phỏng IOS.


Lưu ý: Để xây dựng và thử nghiệm trên Trình mô phỏng IOS hoặc thiết bị IOS, bạn cần sử dụng macOS với Xcode. Ngoài ra, ngay cả khi bạn định sử dụng VS Code làm IDE chính của mình, thì cách dễ nhất để tải Android SDK và trình giả lập Android là cài đặt cả Android Studio.

  • Tạo một dự án mới

Trong VS Code đã cài đặt tiện ích mở rộng Flutter, hãy mở bảng lệnh bằng cách chọn View ▸ Command Palette… hoặc nhấn Command-Shift-P trên macOS hoặc Control-Shift-P trên Linux hoặc Windows. Nhập Flutter: New Application Project vào bảng màu và nhấn Return.




Chọn một thư mục để lưu trữ dự án. Sau đó, nhập ghflutter cho tên của dự án, nhấn Return và đợi Flutter thiết lập dự án trong VS Code. Khi dự án đã sẵn sàng, bạn sẽ thấy main.dart trong trình chỉnh sửa của mình.



Trong VS Code, bạn thấy một bảng ở phía bên trái hiển thị cấu trúc dự án của bạn. Có các thư mục cho Android, iOS và web. Các thư mục này chứa các tệp cần thiết để triển khai ứng dụng của bạn trên các nền tảng đó. Ngoài ra còn có một thư mục lib chứa main.dart và sẽ có mã áp dụng cho cả hai nền tảng. Bạn sẽ làm việc chủ yếu trong thư mục lib trong hướng dẫn này.


Kiểm tra là một phần quan trọng trong quá trình phát triển Flutter. Tuy nhiên, nó không phải là trọng tâm của hướng dẫn này, vì vậy hãy xóa thư mục thử nghiệm bằng cách nhấp chuột phải vào nó và chọn Xóa từ menu.

  • Chỉnh sửa mã

Tiếp theo, thay thế mã trong main.dart bằng mã sau:


import 'package:flutter/material.dart';

void main() => runApp(const GHFlutterApp());

class GHFlutterApp extends StatelessWidget {
const GHFlutterApp({Key? key}) : super(key: key);

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

Lưu ý: Nếu bạn đang sử dụng VS Code, hãy nhớ lưu các thay đổi của bạn để xem chúng có hiệu lực. Chọn Tệp ▸ Lưu từ menu Mã VS hoặc nhấn Command-S trên macOS hoặc Control-S trên Windows hoặc Linux.

Nếu bạn đang sử dụng Android Studio, đừng lo lắng về việc cố tình lưu - nó tự động lưu theo mặc định.


Trong đoạn mã trên, hàm main sử dụng toán tử => cho một hàm dòng duy nhất để chạy ứng dụng. Bạn có một lớp cho ứng dụng có tên GHFlutterApp.


Bản thân ứng dụng của bạn là một tiện ích không trạng thái. Hầu hết các thực thể trong ứng dụng Flutter là các widget, không trạng thái hoặc có trạng thái. Bạn ghi đè bản dựng để tạo tiện ích ứng dụng của mình. Ngay sau từ khóa trả về, bạn sẽ thấy tiện ích MaterialApp, tiện ích này giúp ứng dụng của bạn tuân thủ các nguyên tắc của Material Design.


  • Chạy ứng dụng


Bây giờ, đã đến lúc chạy ứng dụng đơn giản của bạn. Nhấp vào nền tảng hiện được chọn ở dưới cùng bên phải để xem danh sách tất cả các nền tảng có sẵn có thể chạy ứng dụng của bạn. Hình ảnh ở đây cho thấy trình duyệt web Chrome, trình mô phỏng IOS và trình mô phỏng Android Pixel khả dụng.



Chọn một nền tảng - ví dụ: trình giả lập di động Pixel - và đợi trong khi trình mô phỏng khởi chạy.


Khi trình giả lập đã sẵn sàng, hãy xây dựng và chạy bằng cách nhấn F5, bằng cách chọn

Debug ▸ Start Debugging từ menu hoặc bằng cách nhấp vào biểu tượng Phát hình tam giác

ở trên cùng bên phải. Debug Console sẽ mở ra và nếu bạn đang chạy trên Android, bạn sẽ

thấy Gradle đang thực hiện bản dựng. Nếu chạy trên IOS, bạn sẽ thấy Xcode đang xây

dựng dự án.


Đây là ứng dụng đang chạy trong trình giả lập Android:



Hãy dành một chút thời gian để đánh giá cao thực tế là bạn vừa chạy ứng dụng Flutter đầu

tiên của mình. Công việc tốt!


Biểu ngữ DEBUG mà bạn nhìn thấy ở góc trên bên phải cho biết rằng ứng dụng đang chạy

ở chế độ gỡ lỗi.


Dừng ứng dụng đang chạy bằng cách nhấp vào nút Dừng hình vuông màu đỏ ở bên phải

thanh công cụ ở đầu cửa sổ VS Code:



Quay lại dạng xem Project Explorer bằng cách nhấp vào biểu tượng Explorer ở phía trên
bên trái của VS Code hoặc bằng cách chọn View ▸ Explorer.




2. Sử dụng Hot Reload


Một trong những khía cạnh tốt nhất của quá trình phát triển Flutter là bạn có thể tải lại ứng dụng của mình khi bạn thực hiện các thay đổi. Tính năng này cho phép bạn nhận phản hồi tức thì khi cập nhật các phần khác nhau của giao diện người dùng.


Xây dựng và chạy lại:


Bây giờ, không cần dừng ứng dụng đang chạy, hãy thay đổi chuỗi thanh ứng dụng trong main.dart thành một chuỗi khác:


appBar: AppBar(
title: const Text('GHFlutter App'),
),

Trước đây, biểu ngữ ghi GHFlutter; bây giờ, nó cho biết GHFlutter App.


Bây giờ, hãy lưu main.dart. Thao tác này sẽ tự động kích hoạt tải lại nóng, nhưng bạn cũng có thể nhấp vào nút Hot Reload:



Bạn sẽ thấy thay đổi được phản ánh trong ứng dụng đang chạy gần như ngay lập tức:



Tính năng hot reload có thể không phải lúc nào cũng hoạt động - các tài liệu chính thức của Hot Reload thực hiện rất tốt công việc giải thích các trường hợp mà nó không hoạt động - nhưng nhìn chung, đó là một công cụ tiết kiệm thời gian tuyệt vời khi bạn xây dựng giao diện người dùng của mình.


3. Nhập tệp


Thay vì giữ tất cả mã Dart của bạn trong tệp main.dart duy nhất, bạn muốn có thể nhập mã từ các tệp khác mà bạn tạo. Bây giờ, bạn sẽ thấy một ví dụ về nhập chuỗi, điều này sẽ hữu ích khi bạn cần bản địa hóa chuỗi hướng tới người dùng của mình.


Tạo một tệp có tên string.dart trong thư mục lib bằng cách bấm vào lib và sau đó bấm vào nút New File:



Thêm dòng sau vào tệp mới:


const appTitle = 'GHFlutter';

Lưu ý: Nếu bạn có kinh nghiệm với một ngôn ngữ lập trình khác, bạn có thể quen với việc giữ các chuỗi dưới dạng hằng số tĩnh trong một lớp. Dart cho phép các hằng số cấp cao nhất bên ngoài một lớp. Nhóm chúng trong cùng một tệp là đủ.


Thêm nhập sau vào đầu main.dart:


import 'strings.dart' as strings;

Thay đổi tiện ích của bạn để sử dụng các string.dart mới. GHFlutterApp sẽ giống như sau:

class GHFlutterApp extends StatelessWidget {
const GHFlutterApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
title: strings.appTitle,
home: Scaffold(
appBar: AppBar(
title: const Text(strings.appTitle),
),
body: const Center(
child: Text(strings.appTitle),
),
),
);
}
}

Lưu các thay đổi của bạn và hot reload. Ứng dụng hiện đã trở lại trạng thái ban đầu nhưng bạn đang sử dụng một chuỗi từ string.dart.


4. Understanding Widgets


Hầu hết mọi thành phần của ứng dụng Flutter của bạn đều là một widget. Các widget được thiết kế để không thay đổi hoặc không thể thay đổi, vì việc sử dụng các widget bất biến giúp giữ cho giao diện người dùng ứng dụng nhẹ. Bạn có thể nghĩ về các tiện ích con như bản thiết kế cho biết giao diện người dùng sẽ trông như thế nào. Một cái nhìn khác cần một bản thiết kế khác.


Bạn sẽ sử dụng hai loại tiện ích cơ bản:


  • Không trạng thái: Các tiện ích chỉ phụ thuộc vào thông tin cấu hình của riêng chúng, chẳng hạn như hình ảnh tĩnh trong chế độ xem hình ảnh.

  • Trạng thái: Các tiện ích cần duy trì thông tin động. Họ làm như vậy bằng cách tương tác với một đối tượng State.


Cả widget trạng thái và không trạng thái đều vẽ lại bất cứ khi nào khung Flutter yêu cầu chúng. Sự khác biệt là các widget trạng thái ủy thác cấu hình của chúng cho một đối tượng State.

  • Tạo widget

Để tạo các widget của riêng bạn, hãy chuyển đến cuối main.dart và bắt đầu nhập stful, một từ viết tắt của “stateful”. Điều này sẽ cung cấp cho bạn một cửa sổ bật lên tương tự như sau:



Nhấn Return để chọn tùy chọn đầu tiên.

VS Code sẽ giúp bạn điền tên bằng nhiều con trỏ. Viết GHFlutter:


Đây là mã mới mà bạn vừa thêm:


class GHFlutter extends StatefulWidget {
const GHFlutter({ Key? key }) : super(key: key);

@override
_GHFlutterState createState() => _GHFlutterState();
}

class _GHFlutterState extends State<GHFlutter> {
@override
Widget build(BuildContext context) {
return Container(
);
}
}

Dưới đây là một số điều cần lưu ý:


  • Bạn đã tạo một lớp con StatefulWidget có tên là GHFlutter.

  • Dòng bắt đầu bằng const là hàm tạo lớp.

  • Bạn đang ghi đè createState để tạo đối tượng trạng thái của tiện ích con stateful.

  • _GHFlutterState là tên của lớp trạng thái. Dấu gạch dưới phía trước _GHFlutterState có nghĩa là lớp này là tệp riêng tư. Nó không thể được nhập vào các tệp khác.

  • xây dựng là nơi chính mà bạn xây dựng các vật dụng của mình. Cái này hiện trả về một Vùng chứa trống theo mặc định. Bạn sẽ hoán đổi thứ đó với thứ khác tiếp theo.


Thay thế toàn bộ phương thức xây dựng trong _GHFlutterState bằng như sau:


@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(strings.appTitle),
),
body: const Text(strings.appTitle),
);
}

Scaffold là một thùng chứa các vật dụng Material Design. Nó hoạt động như là gốc của hệ thống phân cấp tiện ích con. Tại đây, bạn đã thêm một AppBar và một phần thân vào Scaffold và mỗi phần chứa một tiện ích Văn bản.


Thay thế GHFlutterApp bằng mã sau:


class GHFlutterApp extends StatelessWidget {
const GHFlutterApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
title: strings.appTitle,
home: const GHFlutter(),
);
}
}

Giờ đây, GHFlutterApp sử dụng GHFlutter mới của bạn làm thuộc tính nhà của nó, thay vì xây dựng một Scaffold của riêng nó.


Lưu ý: Từ khóa const, mà đôi khi bạn nhìn thấy trước các widget và biến, biểu thị một hằng số thời gian biên dịch. Không phải lúc nào cũng có thể hoặc cần thiết để thêm const, nhưng làm như vậy cho phép Flutter thực hiện một số tối ưu hóa.


Hot reload và bạn sẽ thấy tiện ích con mới hoạt động:



Bạn vẫn chưa thay đổi nhiều, nhưng bây giờ bạn đã thiết lập để xây dựng tiện ích con mới.


5. Thực hiện cuộc gọi mạng


Trước đó, bạn đã nhập string.dart vào dự án. Tương tự, bạn có thể nhập các gói khác từ

khung công tác Flutter hoặc thậm chí từ các nhà phát triển khác. Ví dụ: bây giờ bạn sẽ sử

dụng một vài gói bổ sung để thực hiện cuộc gọi mạng HTTP và phân tích cú pháp phản

hồi JSON thu được thành các đối tượng Dart.

  • Nhập Packages

Thêm hai lần nhập mới ở đầu main.dart:


import 'dart:convert';
import 'package:http/http.dart' as http;

Bạn sẽ nhận thấy gói http không khả dụng. Đó là bởi vì bạn chưa thêm nó vào dự án.


Điều hướng đến pubspec.yaml trong thư mục gốc của dự án của bạn. Trong phần phụ thuộc, ngay dưới cupertino_icons: ^ 1.0.2, thêm dòng sau:


http: ^0.13.3

Lưu ý: Hãy chú ý đến vết lõm. Sử dụng cùng một thụt lề hai dấu cách mà gói cupertino_icons có.


Bây giờ, khi bạn lưu pubspec.yaml của mình, phần mở rộng Flutter trong VS Code sẽ chạy lệnh Flutter pub get. Flutter sẽ lấy gói http đã khai báo và làm cho nó có sẵn trong main.dart.


Bây giờ bạn sẽ thấy các đường màu xanh lam bên dưới hai lần nhập gần đây nhất của bạn trong main.dart, cho biết chúng hiện không được sử dụng.



Đừng lo lắng. Bạn sẽ sử dụng chúng chỉ trong giây lát.

  • Sử dụng Asynchronous Code

Các ứng dụng Dart là một luồng, nhưng Dart cung cấp hỗ trợ để chạy mã trên các luồng

khác. Nó cũng hỗ trợ chạy mã không đồng bộ không chặn chuỗi giao diện người dùng.

Nó sử dụng mẫu async/await để thực hiện việc này.


Lưu ý: Nhiều người mới bắt đầu giả định không chính xác rằng các phương thức không đồng

bộ chạy trên một luồng khác. Trong khi các tác vụ I/O như cuộc gọi mạng mà bạn ủy quyền

cho hệ thống chạy trên một luồng hệ thống khác, mã bạn tự viết bên trong các phương

thức không đồng bộ đều chạy trên luồng giao diện người dùng. Nó chỉ được lên lịch để

chạy sau, khi giao diện người dùng không bận. Nếu bạn thực sự muốn chạy một số mã trên

một chuỗi khác, thì bạn cần tạo cái được gọi là một vùng cô lập Dart mới.


Tiếp theo, bạn sẽ thực hiện một cuộc gọi mạng không đồng bộ để truy xuất danh sách

các thành viên trong nhóm GitHub. Để thực hiện việc này, hãy thêm danh sách trống làm

thuộc tính trong _GHFlutterState cũng như thuộc tính để giữ kiểu văn bản:


var _members = <dynamic>[];
final _biggerFont = const TextStyle(fontSize: 18.0);

Như bạn đã học trước đó, dấu gạch dưới ở đầu tên làm cho các thành viên của tệp lớp ở

chế độ riêng tư. Từ khóa dynamic cho Dart biết rằng danh sách có thể chứa bất kỳ thứ gì.

Nói chung, không lý tưởng để sử dụng dynamic vì nó chọn không tham gia vào hệ thống

an toàn loại mà Dart có. Tuy nhiên, khi thực hiện các cuộc gọi nội mạng, việc xử lý dynamic

là điều khó tránh khỏi.


Để thực hiện cuộc gọi HTTP không đồng bộ, hãy thêm _loadData vào _GHFlutterState:


Future<void> _loadData() async {
const dataUrl = 'https://api.github.com/orgs/raywenderlich/members';
final response = await http.get(Uri.parse(dataUrl));
setState(() {
_members = json.decode(response.body) as List;
});
}

Tại đây, bạn đã thêm từ khóa async vào _loadData để cho Dart biết rằng từ khóa không đồng bộ. Một manh mối khác cho thấy nó không đồng bộ là kiểu trả về Future . Bạn đặt await  ở phía trước http.get() vì đó là một lệnh gọi không đồng bộ khác có thể mất một lúc.


Khi cuộc gọi HTTP hoàn tất, bạn chuyển một lệnh gọi lại đến setState chạy đồng bộ trên

chuỗi giao diện người dùng. Trong trường hợp này, bạn đang giải mã phản hồi JSON và gán

nó vào danh sách _members. Nếu bạn đặt _members mà không gọi setState, thì Flutter

sẽ không xây dựng lại giao diện người dùng và người dùng của bạn sẽ không nhận ra

rằng trạng thái đã thay đổi.


Thêm ghi đè initState vào _GHFlutterState:


@override
void initState() {
super.initState();
_loadData();
}

Phương thức này gọi _loadData khi lớp trạng thái được tạo lần đầu tiên.


Bây giờ bạn đã tạo danh sách thành viên trong Dart, bạn cần một cách để hiển thị họ trong danh sách trong giao diện người dùng.


6. Sử dụng ListView


Dart cung cấp một ListView cho phép bạn hiển thị dữ liệu trong một danh sách. ListView hoạt động giống như RecyclerView trên Android hoặc UICollectionView trên IOS, chế độ xem tái chế khi người dùng cuộn qua danh sách để đạt được hiệu suất cuộn mượt mà.


Thêm _buildRow vào _GHFlutterState:


Widget _buildRow(int i) {
return ListTile(
title: Text('${_members[i]['login']}', style: _biggerFont),
);
}

Tại đây, bạn đang trả về một ListTile hiển thị tên đăng nhập được phân tích cú pháp từ JSON cho thành viên tại chỉ mục i. Nó cũng sử dụng kiểu văn bản bạn đã tạo trước đó.


Thay thế body trong phương thức build của _GHFlutterState bằng dòng sau:


body: ListView.builder(
padding: const EdgeInsets.all(16.0),
itemCount: _members.length,
itemBuilder: (BuildContext context, int position) {
return _buildRow(position);
}),

Phần đệm thêm một số không gian trống xung quanh mỗi mục danh sách - 16 pixel lôgic, trong trường hợp này. Đặt itemCount cho ListView biết tổng cộng nó sẽ có bao nhiêu hàng. Cuối cùng, gọi itemBuilder cho mỗi hàng mới hiển thị trên màn hình, hàng này bạn sử dụng như một cơ hội để tạo ListTile tùy chỉnh của mình trong _buildRow.


Lưu ý: Việc sao chép và dán đôi khi làm sai định dạng. Sửa định dạng bằng cách nhấn Shift-Option-F trên macOS hoặc Shift-Alt-F trên Windows. Việc lưu tệp cũng có thể tự động định dạng, nếu bạn thiết lập VS Code để làm như vậy.


Tại thời điểm này, bạn có thể cần phải khởi động lại hoàn toàn thay vì hot reload. Nút Hot Restart rất hữu ích cho việc đó. Việc dừng hoàn toàn ứng dụng và xây dựng lại vẫn nhanh hơn.



Sau khi khởi động lại, bạn sẽ thấy như sau:



Đó là cách dễ dàng để thực hiện cuộc gọi mạng, phân tích cú pháp dữ liệu và hiển thị kết quả trong danh sách!




Bây giờ, đã đến lúc làm cho danh sách đẹp hơn một chút.

  • Adding Dividers

Để Adding Dividers vào danh sách, bạn sẽ sử dụng ListView.separated thay

vì ListView.builder. Thay thế phần thân của Scaffold bằng mã bên dưới:


body: ListView.separated(
itemCount: _members.length,
itemBuilder: (BuildContext context, int position) {
return _buildRow(position);
},
separatorBuilder: (context, index) {
return const Divider();
}),


Việc sử dụng ListView.separated cung cấp cho bạn tùy chọn phân táchBuilder, cho phép bạn thêm Dải phân cách giữa các ô danh sách. Bây giờ bạn đã có các dải phân cách, bạn cũng đã loại bỏ phần đệm khỏi trình tạo.


Hot reload. Bây giờ, bạn sẽ thấy các dải phân cách giữa các hàng:



Để thêm phần đệm vào mỗi hàng, hãy bọc ListTile bằng phần đệm bên trong _buildRow. Cách dễ nhất để làm điều đó trong mã VS là đặt con trỏ của bạn trên ListTile và nhấn Command-. trên macOS hoặc Control-. trên Windows. Sau đó, tăng phần đệm lên 16.0, như được hiển thị trong GIF động bên dưới.



Ngoài ra, bạn có thể thay thế _buildRow bằng mã sau để đạt được kết quả tương tự:


Widget _buildRow(int i) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: ListTile(
title: Text('${_members[i]['login']}', style: _biggerFont),
),
);
}

ListTile hiện là một widget con của Padding. Hot reload để xem phần đệm xuất hiện trên các hàng, nhưng không xuất hiện trên các dải phân cách.



7. Phân tích cú pháp thành các loại tùy chỉnh


Trong phần trước, trình phân tích cú pháp JSON đã lấy các thành viên trong phản hồi JSON

và gán chúng cho _members. Mặc dù bạn đã xác định danh sách là dynamic, nhưng kiểu

thực tế mà Dart đưa vào danh sách là Map, một cấu trúc dữ liệu chứa các cặp khóa-giá trị.

Điều này tương đương với Map trong Kotlin hoặc Dictionary trong Swift.


Tuy nhiên, bạn cũng muốn có thể sử dụng các loại tùy chỉnh của riêng mình.


Thêm một loại Member mới ở cuối main.dart:


class Member {
Member(this.login);
final String login;
}

Member có một phương thức khởi tạo đặt thuộc tính đăng nhập khi bạn tạo một đối tượng thành viên.


Cập nhật khai báo _members trong _GHFlutterState để đó là danh sách các đối tượng Member:


final _members = <Member>[];

Bạn đã sử dụng final thay cho var vì thay vì chỉ định lại danh sách mới cho _members, bạn sẽ thêm các mục vào danh sách hiện có.


Thay thế setState trong _loadData bằng mã sau:


setState(() {
final dataList = json.decode(response.body) as List;
for (final item in dataList) {
final login = item['login'] as String? ?? '';
final member = Member(login);
_members.add(member);
}
});

Điều này biến mỗi bản đồ được giải mã thành một Member và thêm nó vào danh sách các thành viên.


Lưu ý: Bạn tò mò về đĩa đơn? và gấp đôi ?? dấu chấm hỏi? Hãy xem hướng dẫn Khái niệm cơ bản về Dart để biết thêm chi tiết về các toán tử này.


Flutter vẫn đang phàn nàn bên trong ListTile vì nó mong đợi Map hơn là Member. Thay thế dòng title của ListTile bằng dòng sau:


title: Text('${_members[i].login}', style: _biggerFont),

Bạn sẽ thấy lỗi nếu thử tải lại nóng, vì vậy hãy khởi động lại nóng. Bạn sẽ thấy màn hình giống như trước đây, ngoại trừ màn hình hiện sử dụng lớp Member mới của bạn.


8. Tải xuống hình ảnh bằng NetworkImage


Trong GitHub, mỗi thành viên có một URL cho ảnh đại diện của họ. Cải tiến tiếp theo của bạn là thêm hình đại diện đó vào lớp Member và hiển thị hình đại diện trong ứng dụng.


Cập nhật Member để thêm thuộc tính avatarUrl. Nó sẽ trông như thế này bây giờ:


class Member {
Member(this.login, this.avatarUrl);
final String login;
final String avatarUrl;
}

Vì avatarUrl bây giờ là một tham số bắt buộc, nên Flutter phàn nàn về bạn trong _loadData. Thay thế lệnh gọi lại setState trong _loadData bằng phiên bản cập nhật sau:


setState(() {
final dataList = json.decode(response.body) as List;
for (final item in dataList) {
final login = item['login'] as String? ?? '';
final url = item['avatar_url'] as String? ?? '';
final member = Member(login, url);
_members.add(member);
}
});

Đoạn mã trên sử dụng khóa avatar_url để tra cứu giá trị URL trong bản đồ được phân tích cú pháp từ JSON, sau đó đặt nó thành chuỗi url mà bạn chuyển cho Member.


Bây giờ bạn đã có quyền truy cập vào URL cho hình đại diện, hãy thêm nó vào ListTile của bạn. Thay thế _buildRow bằng như sau:


Widget _buildRow(int i) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: ListTile(
title: Text('${_members[i].login}', style: _biggerFont),
leading: CircleAvatar(
backgroundColor: Colors.green,
backgroundImage: NetworkImage(_members[i].avatarUrl),
),
),
);
}

Điều này sẽ thêm một CircleAvatar vào cạnh đầu của ListTile của bạn. Trong khi bạn chờ tải hình ảnh xuống, nền của CircleAvatar sẽ có màu xanh lục.


Thực hiện khởi động lại nóng hơn là hot reload. Bạn sẽ thấy hình đại diện thành viên của mình trong mỗi hàng:




9. Cleaning up the Code


Hầu hết mã của bạn hiện nằm trong main.dart. Để làm cho mã gọn gàng hơn một chút, bạn sẽ cấu trúc lại các lớp thành các tệp của riêng chúng.


Tạo tệp có tên member.dart và ghflutter.dart trong thư mục lib. Di chuyển Member vào member.dart và cả _GHFlutterState và GHFlutter vào ghflutter.dart.


Bạn sẽ không cần bất kỳ câu lệnh nhập nào trong member.dart, nhưng các câu lệnh nhập trong ghflutter.dart phải là:


import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'member.dart';
import 'strings.dart' as strings;

Bạn cũng cần cập nhật các lần nhập trong main.dart. Thay thế toàn bộ tệp bằng tệp sau:

import 'package:flutter/material.dart';
import 'ghflutter.dart';
import 'strings.dart' as strings;

void main() => runApp(const GHFlutterApp());

class GHFlutterApp extends StatelessWidget {
const GHFlutterApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
title: strings.appTitle,
// TODO: add theme here
home: const GHFlutter(),
);
}
}

Lưu mọi thứ và chạy lại ứng dụng. Bạn sẽ không thấy thay đổi, nhưng mã hiện đã gọn gàng hơn một chút.


Bạn có thể đã nhận thấy một nhận xét mới: //TODO: add theme here.. Ở đó, bạn sẽ thực hiện một thay đổi cuối cùng trước khi hướng dẫn kết thúc.


10. Adding a Theme


Cải tiến cuối cùng của bạn là dễ dàng thêm chủ đề vào ứng dụng bằng cách thêm thuộc tính chủ đề vào MaterialApp bạn đã tạo trong main.dart.


Tìm //TODO: add theme here và thay thế bằng chủ đề sau:


theme: ThemeData(primaryColor: Colors.green.shade800),

Ở đây, bạn đang sử dụng màu xanh lục làm giá trị màu Material Design cho chủ đề.


Lưu và tải lại nóng để xem chủ đề mới đang hoạt động:




Các ảnh chụp màn hình ứng dụng cho đến nay đều là từ trình giả lập Android. Bạn cũng có

thể chạy ứng dụng theo chủ đề cuối cùng trong Trình mô phỏng IOS:



Và đây là giao diện của nó trên trình duyệt web Chrome:



Hãy thoải mái chạy nó như một ứng dụng Windows, Mac hoặc Linux. Nó chỉ yêu cầu a little extra setupadding desktop support vào ứng dụng của bạn. Trên macOS, bạn cũng nên give the app permission to access the internet.


Đây là ứng dụng đang chạy trên macOS:



Bây giờ đó là những gì bạn gọi là đa nền tảng!


11. Where to Go From Here?


Bạn có thể mở dự án trong VS Code hoặc Android Studio.


Mở nó trong VS Code bằng cách mở thư mục gốc. Bạn sẽ cần tìm nạp các gói trước khi

chạy dự án. Làm như vậy bằng cách nhấn Command-Shift-P trên MacOS hoặc

Control-Shift-P trên Windows hoặc Linux để mở bảng lệnh và chạy lệnh Flutter: Get Packages.


Để mở dự án trong Android Studio, hãy chọn Open an existing project từ màn hình Welcome

to Android Studio và điều hướng để chọn thư mục gốc của dự án cuối cùng. Sau đó, chọn

Get dependencies trên dòng'Pub get' has not been run trong Android Studio.


Còn rất nhiều điều cần tìm hiểu về Flutter và Dart. Dưới đây là một số nơi để bắt đầu:


  • Trang Flutter chính tại Flutter.dev. Bạn sẽ tìm thấy nhiều tài liệu hay và thông tin khác.
  • Tìm hiểu thêm về widgets in Introduction to Widgets.
  • Nếu bạn đến từ một nền tảng khác, hãy xem hướng dẫn Flutter dành cho các nhà phát
triển Android, IOSReact Native.
  • Để đi sâu vào các khía cạnh quan trọng nhất của Flutter, hãy đọc cuốn sách
Flutter Apprentice của chúng tôi.


Chúng tôi hy vọng bạn thích hướng dẫn này. Nếu bạn có bất kỳ câu hỏi hoặc ý kiến nào,

hãy tham gia thảo luận của diễn đàn bên dưới!

Nhận xét

Bài đăng phổ biến từ blog này

Jetpack Compose VS SwiftUI !VS Flutter

  Việc phát triển Android đã trở nên dễ dàng hơn khi các bản cập nhật liên tục đến. Sau bản cập nhật 2020.3.1, rất nhiều thứ đã thay đổi. Nhưng thay đổi chính mà tôi nghĩ hầu hết các nhà phát triển phải chờ đợi là Jetpack Compose cho ứng dụng sản xuất. Và Kotlin là lựa chọn duy nhất cho jetpack Compose, cũng là ngôn ngữ được ưu tiên. Để biết thêm chi tiết hoặc các thay đổi trên Jetpack Compose, bạn có thể truy cập vào https://developer.android.com/jetpack/compose Tương tự, IOS Development cũng cung cấp một tùy chọn để phát triển khai báo, SwiftUI. Trong IDE, không có thay đổi nào do điều này. Nhưng khái niệm gần giống với Jetpack Compose. Thay vì bảng phân cảnh, chúng tôi tạo giao diện người dùng bằng Swift. Để biết thêm chi tiết hoặc các thay đổi trên SwiftUI, hãy truy cập https://developer.apple.com/xcode/swiftui/ Hãy xem cách cả hai hoạt động bằng cách sử dụng một dự án demo. Tôi đã lấy một số ví dụ về số lần chạm tương tự của Flutter. 1. Android Jetpack Compose Chúng tôi có thể tạo

Thiết kế giao diện với DotNetBar (Phần 1)

Đây là phiên bản DotNetBar hỗ trợ C# và Visual Basic https://www.dropbox.com/s/wx80jpvgnlrmtux/DotNetBar.rar  , phiên bản này hỗ trợ giao diện Metro cực kỳ “dễ thương” Các bạn load về và cài đặt, khi cài đặt xong sẽ có source code mẫu của tất cả các control. Để sử dụng được các control của DotNetBar các bạn nhớ add item vào controls box. Thiết kế giao diện với DotNetBar, giao diện sẽ rất đẹp. Link các video hướng dẫn chi tiết cách sử dụng và coding: http://www.devcomponents.com/dotnetbar/movies.aspx Hiện tại DotNetBar có rất nhiều công cụ cực mạnh, trong đó có 3 công cụ dưới đây: DotNetBar for Windows Forms Requires with Visual Studio 2003, 2005, 2008, 2010 or 2012.   DotNetBar for WPF Requires with Visual Studio 2010 or 2012 and Windows Presentation Foundation.   DotNetBar for Silverlight Requires with Visual Studio 2010 or 2012 and Silverlight. Dưới đây là một số hình ảnh về các control trong DotnetBar.   Metro User Interface  controls with Metro Tiles, toolbars, slide panels, forms,

Một số bài tập Winform C#

Một số bài tập: 1. Mô phỏng game đoán số. Luật chơi:         o Đúng số và đúng vị trí   +         o Đúng số mà sai vị trí      ?         o Sai số và sai vị trí          -         . . .         - Kết quả được tạo ngẫu nhiên từ các số có 4 chữ số.         - Các chữ số có giá trị từ 0-6.         - Người chơi có 6 lần đoán. Chương trình tham khảo: 2. In số điện tử Yêu cầu: người dùng nhập vào 1 số ( hoặc 1 chuỗi số) yêu cầu in ra số đó dưới dạng số điện tử. Chương trình tham khảo: 3. Mô phỏng game CARO  (update) 4. Mô phỏng game DÒ MÌN (update)