1. Giới thiệu
Thành phần Material (MDC) giúp nhà phát triển triển khai Material Design. Được tạo bởi một nhóm các kỹ sư và nhà thiết kế trải nghiệm người dùng tại Google, MDC có nhiều thành phần giao diện người dùng đẹp mắt, dễ sử dụng và có sẵn cho Android, iOS, web và Flutter.material.io/develop |
Giờ đây, bạn có thể dùng Material Flutter để tuỳ chỉnh ứng dụng của mình mang phong cách riêng biệt hơn bao giờ hết. Việc mở rộng gần đây của Material Design giúp nhà thiết kế và nhà phát triển linh hoạt hơn trong việc thể hiện thương hiệu sản phẩm của họ.
Trong các lớp học lập trình MDC-101 và MDC-102, bạn đã sử dụng Material Flutter để xây dựng kiến thức cơ bản cho một ứng dụng có tên là Shrine, một ứng dụng thương mại điện tử bán quần áo và đồ gia dụng. Ứng dụng này chứa một luồng người dùng bắt đầu bằng màn hình đăng nhập, sau đó đưa người dùng đến màn hình chính hiển thị các sản phẩm.
Sản phẩm bạn sẽ tạo ra
Trong lớp học lập trình này, bạn sẽ tuỳ chỉnh ứng dụng Đền bằng cách sử dụng:
- Màu
- Kiểu chữ
- Độ cao
- Hình dạng
- Bố cục
Android | iOS |
Các thành phần và hệ thống con Material Flutter trong lớp học lập trình này
- Giao diện
- Kiểu chữ
- Độ cao
- Danh sách hình ảnh
Bạn đánh giá thế nào về mức độ kinh nghiệm của mình khi phát triển Flutter?
2. Thiết lập môi trường phát triển Flutter
Bạn cần có 2 phần mềm để hoàn thành phòng thí nghiệm này – Flutter SDK và trình chỉnh sửa.
Bạn có thể chạy lớp học lập trình bằng bất kỳ thiết bị nào sau đây:
- Một thiết bị Android hoặc iOS thực kết nối với máy tính của bạn và được đặt ở Chế độ nhà phát triển.
- Trình mô phỏng iOS (yêu cầu cài đặt công cụ Xcode).
- Trình mô phỏng Android (yêu cầu thiết lập trong Android Studio).
- Trình duyệt (cần có Chrome để gỡ lỗi).
- Dưới dạng ứng dụng Windows, Linux hoặc macOS. Bạn phải phát triển trên nền tảng mà bạn dự định triển khai. Vì vậy, nếu muốn phát triển một ứng dụng Windows dành cho máy tính, bạn phải phát triển trên Windows để truy cập vào chuỗi bản dựng phù hợp. Có các yêu cầu cụ thể theo hệ điều hành được đề cập chi tiết trên docs.flutter.dev/desktop.
3. Tải ứng dụng khởi đầu của lớp học lập trình
Tiếp tục từ MDC-102?
Nếu bạn đã hoàn thành MDC-102, mã của bạn đã sẵn sàng cho lớp học lập trình này. Chuyển đến bước: Thay đổi màu.
Bắt đầu từ đầu?
Tải ứng dụng khởi đầu của lớp học lập trình
Ứng dụng khởi đầu nằm trong thư mục material-components-flutter-codelabs-103-starter_and_102-complete/mdc_100_series
.
...hoặc sao chép tệp trên GitHub
Để sao chép lớp học lập trình này từ GitHub, hãy chạy các lệnh sau:
git clone https://github.com/material-components/material-components-flutter-codelabs.git cd material-components-flutter-codelabs/mdc_100_series git checkout 103-starter_and_102-complete
Mở dự án và chạy ứng dụng
- Mở dự án trong trình chỉnh sửa mà bạn chọn.
- Làm theo hướng dẫn để "Chạy ứng dụng" trong phần Bắt đầu: Dùng thử cho trình chỉnh sửa mà bạn đã chọn.
Thành công! Bạn sẽ thấy trang đăng nhập Đền từ các lớp học lập trình trước trên thiết bị của mình.
Android | iOS |
Nhấp vào "Tiếp theo" để xem trang sản phẩm.
Android | iOS |
4. Thay đổi màu sắc
Một bảng phối màu đã được tạo ra đại diện cho thương hiệu Đền và nhà thiết kế muốn bạn triển khai bảng phối màu đó trên ứng dụng Đền
Để bắt đầu, hãy nhập các màu đó vào dự án.
Tạo colors.dart
Tạo một tệp phi tiêu mới trong lib
có tên là colors.dart
. Nhập material.dart
và thêm const Color
giá trị:
import 'package:flutter/material.dart';
const kShrinePink50 = Color(0xFFFEEAE6);
const kShrinePink100 = Color(0xFFFEDBD0);
const kShrinePink300 = Color(0xFFFBB8AC);
const kShrinePink400 = Color(0xFFEAA4A4);
const kShrineBrown900 = Color(0xFF442B2D);
const kShrineErrorRed = Color(0xFFC5032B);
const kShrineSurfaceWhite = Color(0xFFFFFBFA);
const kShrineBackgroundWhite = Colors.white;
Bảng màu tuỳ chỉnh
Chủ đề màu sắc này do một nhà thiết kế tạo ra với các màu tuỳ chỉnh (minh hoạ trong hình bên dưới). Thành phần này chứa các màu đã được chọn từ thương hiệu của Shrine và áp dụng cho Material Theme Editor (Trình chỉnh sửa giao diện Material) để tạo ra bảng màu đầy đủ hơn. (Những màu này không phải từ Bảng màu Material năm 2014.)
Material Theme Editor (Trình chỉnh sửa giao diện Material) đã sắp xếp chúng thành các sắc độ được gắn nhãn bằng số, bao gồm các nhãn 50, 100, 200, .... đến 900 của mỗi màu. Đền chỉ sử dụng các sắc độ 50, 100 và 300 từ bảng màu hồng và 900 từ bảng màu nâu.
Mỗi tham số màu của một tiện ích được liên kết với một màu trong các lược đồ này. Ví dụ: màu trang trí của một trường văn bản khi chủ động nhận dữ liệu đầu vào phải là Màu chính của giao diện. Nếu không thể nhìn thấy màu đó (dễ thấy trên nền), hãy sử dụng một màu khác.
Giờ đây, khi đã có các màu muốn sử dụng, chúng ta có thể áp dụng các màu đó cho giao diện người dùng. Chúng ta thực hiện việc này bằng cách thiết lập các giá trị của tiện ích ThemeData mà chúng ta áp dụng cho thực thể MaterialApp ở đầu hệ phân cấp tiện ích.
Tuỳ chỉnh ThemeData.light()
Flutter có một số giao diện được tích hợp sẵn. Giao diện sáng là một trong những giao diện đó. Thay vì tạo một tiện ích ThemeData từ đầu, chúng ta sẽ sao chép giao diện sáng và thay đổi các giá trị để tuỳ chỉnh cho ứng dụng.
Hãy nhập colors.dart
trong app.dart.
import 'colors.dart';
Sau đó, hãy thêm đoạn mã sau vào app.dart bên ngoài phạm vi của lớp ShrineApp:
// TODO: Build a Shrine Theme (103)
final ThemeData _kShrineTheme = _buildShrineTheme();
ThemeData _buildShrineTheme() {
final ThemeData base = ThemeData.light(useMaterial3: true);
return base.copyWith(
colorScheme: base.colorScheme.copyWith(
primary: kShrinePink100,
onPrimary: kShrineBrown900,
secondary: kShrineBrown900,
error: kShrineErrorRed,
),
// TODO: Add the text themes (103)
// TODO: Decorate the inputs (103)
);
}
Bây giờ, hãy đặt theme:
ở cuối hàm build()
của ShrineApp (trong tiện ích MaterialApp) làm giao diện mới:
// TODO: Customize the theme (103)
theme: _kShrineTheme, // New code
Lưu dự án. Bây giờ, màn hình đăng nhập của bạn sẽ có dạng như sau:
Android | iOS |
5. Sửa đổi kiểu chữ và kiểu nhãn
Bên cạnh việc thay đổi màu sắc, nhà thiết kế cũng cung cấp cho chúng ta các kiểu chữ cụ thể để sử dụng. ThemeData của Flutter chứa 3 giao diện văn bản. Mỗi chủ đề văn bản là một tập hợp các kiểu văn bản, chẳng hạn như "dòng tiêu đề" và "title". Chúng ta sẽ sử dụng một vài kiểu cho ứng dụng và thay đổi một số giá trị.
Tuỳ chỉnh giao diện văn bản
Để nhập phông chữ vào dự án, bạn phải thêm các phông chữ đó vào tệp pubspec.yaml.
Trong pubspec.yaml, hãy thêm đoạn mã sau ngay sau thẻ flutter:
:
# TODO: Insert Fonts (103)
fonts:
- family: Rubik
fonts:
- asset: fonts/Rubik-Regular.ttf
- asset: fonts/Rubik-Medium.ttf
weight: 500
Giờ bạn có thể truy cập và sử dụng phông chữ Rubik.
Khắc phục sự cố với tệp pubspec
Bạn có thể gặp lỗi khi chạy pub get nếu cắt và dán nội dung khai báo ở trên. Nếu bạn gặp lỗi, hãy bắt đầu bằng cách xoá khoảng trắng ở đầu và thay thế bằng dấu cách với khoảng thụt lề 2 khoảng trắng. (Hai dấu cách trước
fonts:
, trước 4 dấu cách
family: Rubik
, v.v.)
Nếu bạn thấy thông báo Không cho phép liên kết các giá trị ở đây, hãy kiểm tra thụt lề của dòng có vấn đề và thụt lề các dòng phía trên dòng đó.
Trong login.dart
, hãy thay đổi các mục sau bên trong Column()
:
Column(
children: <Widget>[
Image.asset('assets/diamond.png'),
const SizedBox(height: 16.0),
Text(
'SHRINE',
style: Theme.of(context).textTheme.headlineSmall,
),
],
)
Trong app.dart
, hãy thêm nội dung sau đây sau _buildShrineTheme()
:
// TODO: Build a Shrine Text Theme (103)
TextTheme _buildShrineTextTheme(TextTheme base) {
return base
.copyWith(
headlineSmall: base.headlineSmall!.copyWith(
fontWeight: FontWeight.w500,
),
titleLarge: base.titleLarge!.copyWith(
fontSize: 18.0,
),
bodySmall: base.bodySmall!.copyWith(
fontWeight: FontWeight.w400,
fontSize: 14.0,
),
bodyLarge: base.bodyLarge!.copyWith(
fontWeight: FontWeight.w500,
fontSize: 16.0,
),
)
.apply(
fontFamily: 'Rubik',
displayColor: kShrineBrown900,
bodyColor: kShrineBrown900,
);
}
Thao tác này sẽ chọn TextTheme và thay đổi giao diện của tiêu đề, tiêu đề và phụ đề.
Việc áp dụng fontFamily
theo cách này sẽ chỉ áp dụng các thay đổi cho giá trị tỷ lệ kiểu chữ được chỉ định trong copyWith()
(dòng tiêu đề, tiêu đề, chú thích).
Đối với một số phông chữ, chúng ta sẽ thiết lập phông chữ tuỳ chỉnh, theo gia số 100: w500 (độ đậm 500) tương ứng với cỡ trung bình và w400 tương ứng với thông thường.
Sử dụng văn bản mớitó
Thêm các giao diện sau vào _buildShrineTheme
sau khi gặp lỗi:
// TODO: Add the text themes (103)
textTheme: _buildShrineTextTheme(base.textTheme),
textSelectionTheme: const TextSelectionThemeData(
selectionColor: kShrinePink100,
),
Lưu dự án. Lần này, bạn cũng cần khởi động lại ứng dụng (được gọi là Khởi động lại nóng) vì chúng tôi đã sửa đổi phông chữ.
Android | iOS |
Văn bản trong màn hình đăng nhập và màn hình chính trông khác nhau. Một số văn bản sử dụng phông chữ Rubik và một số văn bản khác hiển thị bằng màu nâu, thay vì màu đen hoặc trắng. Các biểu tượng cũng xuất hiện có màu nâu.
Thu hẹp văn bản
Nhãn quá lớn.
Trong home.dart
, hãy thay đổi children:
của Cột trong cùng:
// TODO: Change innermost Column (103)
children: <Widget>[
// TODO: Handle overflowing labels (103)
Text(
product.name,
style: theme.textTheme.button,
softWrap: false,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
const SizedBox(height: 4.0),
Text(
formatter.format(product.price),
style: theme.textTheme.bodySmall,
),
// End new code
],
Căn giữa và thả văn bản
Chúng ta muốn căn giữa các nhãn và căn chỉnh văn bản ở cuối mỗi thẻ, thay vì cuối mỗi hình ảnh.
Di chuyển các nhãn đến cuối (dưới cùng) của trục chính và thay đổi chúng để được căn giữa::
// TODO: Align labels to the bottom and center (103)
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
Lưu dự án.
Android | iOS |
Như vậy trông đẹp hơn nhiều.
Giao diện cho các trường văn bản
Bạn cũng có thể tạo giao diện cho phần trang trí trên các trường văn bản bằng InputDecorationTheme.
Trong app.dart
, trong phương thức _buildShrineTheme()
, hãy chỉ định một giá trị inputDecorationTheme:
:
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
),
Hiện tại, các trường văn bản có kiểu trang trí filled
. Hãy xoá mặt hàng đó. Việc xoá filled
và chỉ định inputDecorationTheme
sẽ cung cấp cho các trường văn bản kiểu đường viền.
Trong login.dart
, hãy xoá các giá trị filled: true
:
// Remove filled: true values (103)
TextField(
controller: _usernameController,
decoration: const InputDecoration(
// Removed filled: true
labelText: 'Username',
),
),
const SizedBox(height: 12.0),
TextField(
controller: _passwordController,
decoration: const InputDecoration(
// Removed filled: true
labelText: 'Password',
),
obscureText: true,
),
Khởi động lại nóng. Màn hình đăng nhập của bạn sẽ có dạng như sau khi trường Tên người dùng hoạt động (khi bạn nhập vào đó):
Android | iOS |
Nhập vào trường văn bản – đường viền và nhãn nổi hiển thị theo màu chính. Nhưng chúng tôi không thể dễ dàng thấy được. Những người gặp khó khăn trong việc phân biệt các pixel không có độ tương phản màu đủ cao sẽ không truy cập được. (Để biết thêm thông tin, hãy xem bài viết về Màu sắc và khả năng hỗ trợ tiếp cận trong Nguyên tắc Material.)
Trong app.dart
, hãy chỉ định focusedBorder:
trong inputDecorationTheme:
:
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrineBrown900,
),
),
),
Tiếp theo, hãy chỉ định floatingLabelStyle:
trong inputDecorationTheme:
:
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrineBrown900,
),
),
floatingLabelStyle: TextStyle(
color: kShrineBrown900,
),
),
Cuối cùng, hãy thiết lập để nút Cancel (Huỷ) sử dụng màu cấp hai thay vì màu chính để tăng độ tương phản.
TextButton(
child: const Text('CANCEL'),
onPressed: () {
_usernameController.clear();
_passwordController.clear();
},
style: TextButton.styleFrom(
primary: Theme.of(context).colorScheme.secondary,
),
),
Lưu dự án.
Android | iOS |
6. Điều chỉnh độ cao
Bây giờ, bạn đã tạo kiểu cho trang bằng màu và kiểu chữ cụ thể phù hợp với Đền, hãy điều chỉnh độ cao.
Thay đổi độ cao của nút NEXT
Độ cao mặc định cho ElevatedButton
là 2. Hãy nâng nó lên cao hơn.
Trong login.dart
, hãy thêm giá trị style:
vào nút RaisedButton NEXT:
ElevatedButton(
child: const Text('NEXT'),
onPressed: () {
Navigator.pop(context);
},
style: ElevatedButton.styleFrom(
foregroundColor: kShrineBrown900,
backgroundColor: kShrinePink100,
elevation: 8.0,
),
),
Lưu dự án.
Android | iOS |
Điều chỉnh độ cao của thẻ
Hiện tại, các thẻ này nằm trên một nền trắng bên cạnh phần điều hướng của trang web.
Trong home.dart
, hãy thêm giá trị elevation:
vào các Thẻ:
// TODO: Adjust card heights (103)
elevation: 0.0,
Lưu dự án.
Android | iOS |
Bạn đã loại bỏ bóng bên dưới các thẻ.
7. Thêm hình dạng
Đền thờ có phong cách hình học thú vị, nổi bật với các yếu tố cụ thể là hình bát giác hoặc hình chữ nhật. Hãy triển khai việc định kiểu hình dạng đó trong các thẻ trên màn hình chính cũng như các trường văn bản và nút trên màn hình đăng nhập.
Thay đổi hình dạng của trường văn bản trên màn hình đăng nhập
Trong app.dart
, hãy nhập tệp sau:
import 'supplemental/cut_corners_border.dart';
Vẫn trong app.dart
, hãy sửa đổi giao diện trang trí trường văn bản để sử dụng đường viền góc cắt:
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: CutCornersBorder(),
focusedBorder: CutCornersBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrineBrown900,
),
),
floatingLabelStyle: TextStyle(
color: kShrineBrown900,
),
),
Thay đổi hình dạng nút trên màn hình đăng nhập
Trong login.dart
, hãy thêm đường viền hình chữ nhật có cạnh vát vào nút CANCEL:
TextButton(
child: const Text('CANCEL'),
onPressed: () {
_usernameController.clear();
_passwordController.clear();
},
style: TextButton.styleFrom(
foregroundColor: kShrineBrown900,
shape: const BeveledRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(7.0)),
),
),
),
TextButton không hiển thị hình dạng, vậy tại sao bạn phải thêm hình dạng đường viền? Vì vậy, ảnh động gợn sóng được liên kết với cùng một hình dạng khi chạm vào.
Giờ hãy thêm hình dạng tương tự vào nút NEXT:
ElevatedButton(
child: const Text('NEXT'),
onPressed: () {
Navigator.pop(context);
},
style: ElevatedButton.styleFrom(
foregroundColor: kShrineBrown900,
backgroundColor: kShrinePink100,
elevation: 8.0,
shape: const BeveledRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(7.0)),
),
),
),
Để thay đổi hình dạng của tất cả các nút, chúng ta cũng có thể sử dụng elevatedButtonTheme
hoặc textButtonTheme
trong app.dart
. Điều này cũng là một thách thức đối với người học!
Khởi động lại nóng.
Android | iOS |
8. Thay đổi bố cục
Tiếp theo, hãy thay đổi bố cục để hiển thị các thẻ ở nhiều tỷ lệ khung hình và kích thước, nhờ đó, mỗi thẻ đều trông riêng biệt so với những thẻ khác.
Thay thế GridView bằng AsymmetricView
Chúng ta đã viết các tệp cho một bố cục bất đối xứng.
Trong home.dart
, hãy thêm dữ liệu nhập sau:
import 'supplemental/asymmetric_view.dart';
Xoá _buildGridCards
và thay thế body
:
body: AsymmetricView(
products: ProductsRepository.loadProducts(Category.all),
),
Lưu dự án.
Android | iOS |
Giờ đây, các sản phẩm sẽ cuộn theo chiều ngang với hoa văn lấy cảm hứng từ vải dệt.
9. Thử một giao diện khác (Không bắt buộc)
Màu sắc là cách hiệu quả để thể hiện thương hiệu của bạn và một thay đổi nhỏ về màu sắc cũng có thể ảnh hưởng lớn đến trải nghiệm người dùng. Để kiểm tra điều này, hãy cùng xem đền thờ trông như thế nào nếu bảng phối màu của thương hiệu có chút khác biệt.
Sửa đổi màu
Trong colors.dart
, hãy thêm màu sau:
const kShrinePurple = Color(0xFF5D1049);
Trong app.dart
, hãy thay đổi hàm _buildShrineTheme()
thành như sau:
ThemeData _buildShrineTheme() {
final ThemeData base = ThemeData.light();
return base.copyWith(
colorScheme: base.colorScheme.copyWith(
primary: kShrinePurple,
secondary: kShrinePurple,
error: kShrineErrorRed,
),
scaffoldBackgroundColor: kShrineSurfaceWhite,
textSelectionTheme: const TextSelectionThemeData(
selectionColor: kShrinePurple,
),
appBarTheme: const AppBarTheme(
foregroundColor: kShrineBrown900,
backgroundColor: kShrinePink100,
),
inputDecorationTheme: const InputDecorationTheme(
border: CutCornersBorder(),
focusedBorder: CutCornersBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrinePurple,
),
),
floatingLabelStyle: TextStyle(
color: kShrinePurple,
),
),
);
}
Khởi động lại nóng. Lúc này, giao diện mới sẽ xuất hiện.
Android | iOS |
Android | iOS |
Kết quả rất khác biệt! Hãy khôi phục app.dart's
_buildShrineTheme
về trạng thái trước bước này. Hoặc tải mã khởi đầu của 104 xuống.
10. Xin chúc mừng!
Đến đây, bạn đã tạo được một ứng dụng giống với thông số kỹ thuật thiết kế mà nhà thiết kế của bạn đưa ra.
Các bước tiếp theo
Lúc này, bạn đã sử dụng Material Flutter sau: giao diện, kiểu chữ, độ cao và hình dạng. Bạn có thể khám phá thêm các thành phần và hệ thống con khác trong thư viện Material Flutter.
Đi sâu vào các tệp trong thư mục supplemental
để tìm hiểu cách chúng tôi tạo lưới bố cục bất đối xứng và cuộn theo chiều ngang.
Nếu thiết kế ứng dụng theo kế hoạch của bạn chứa các phần tử không có thành phần trong thư viện thì sao? Trong MDC-104: Thành phần nâng cao Material, chúng ta sẽ biết cách tạo thành phần tuỳ chỉnh bằng thư viện Material Flutter để có được giao diện mong muốn.