Flutter: Codelab
Giải phóng thời gian, khai phóng năng lực
Mục lục bài viết
- Các lớp Row và Column
- Kích thước và căn chỉnh trục
- Widget Flexible
- Widget Expanded
- Widget SizedBox
- Widget Spacer
- Widget Text
- Widget Icon
- Widget Image
- Tổng kết
Bài viết này sẽ hướng dẫn bạn cách xây dựng giao diện người dùng Flutter mà không cần tải xuống và cài đặt Flutter hoặc Dart!
Quan trọng: Codelab này bao gồm các khái niệm cơ bản về bố cục Flutter bằng cách sử dụng một trình soạn thảo code thử nghiệm có tên là DartPad. DartPad chưa được thử nghiệm đầy đủ trên tất cả các trình duyệt. Nếu bạn gặp bất kỳ khó khăn nào khi sử dụng DartPad trên một trình duyệt cụ thể, vui lòng tạo sự cố DartPad và chỉ định trình duyệt bạn đang sử dụng trong tiêu đề sự cố.
Flutter khác với các framework khác vì giao diện người dùng của nó được xây dựng trong mã, không phải (ví dụ) trong tệp XML hoặc tương tự. Các widget là các khối xây dựng cơ bản của giao diện người dùng Flutter. Sau khi bạn đã tiến bộ qua codelab này, bạn sẽ biết rằng hầu hết mọi thứ trong Flutter đều là một widget. Widget là một đối tượng bất biến mô tả một phần cụ thể của giao diện người dùng. Bạn cũng sẽ biết rằng các widget Flutter có thể kết hợp, nghĩa là bạn có thể kết hợp các widget hiện có để tạo ra các widget phức tạp hơn. Ở phần cuối của codelab này, bạn sẽ áp dụng những gì đã học vào việc xây dựng giao diện người dùng Flutter hiển thị danh thiếp.
Thời gian ước tính để hoàn thành codelab này: 45-60 phút.
Các lớp Row và Column
Row
và Column
là các lớp chứa và bố trí các widget. Các widget bên trong của một Row
hoặc Column
được gọi là con, Row
và Column
được gọi là cha. Row
đặt các widget của nó theo chiều ngang và Column
đặt các widget của nó theo chiều dọc.
Ví dụ: Tạo một cột
Ví dụ sau đây hiển thị sự khác biệt giữa a Row
và Column
.
1. Nhấp vào nút Run.
2. Trong đoạn code bạn hãy thay đổi Row
thành một Column
và chạy lại.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( children: [ BlueBox(), BlueBox(), BlueBox(), ], ); } } class BlueBox extends StatelessWidget { @override Widget build(BuildContext context) { return Container( width:50, height:50, decoration:BoxDecoration( color:Colors.blue, border:Border.all(), ), ); } }
Kích thước và căn chỉnh trục (axis)
Các BlueBox
widget đã được sắp xếp lại với nhau (ở bên trái hoặc ở trên cùng của Đầu ra giao diện người dùng). Bạn có thể thay đổi cách sắp xếp các BlueBox
widget bằng cách sử dụng thuộc tính kích thước trục và căn chỉnh.
Thuộc tính mainAxisSize
Row
và Column
chiếm các trục chính khác nhau. Trục chính của Row
là trục ngang và trục chính của Column
là trục thẳng. Thuộc tính mainAxisSize
sẽ xác định bao nhiêu không gian cho một Row
và Column
có thể chiếm trên trục chính của họ. mainAxisSize
có hai giá trị có thể:
MainAxisSize.max
Row
và Column
chiếm tất cả không gian trên các trục chính của chúng. Nếu chiều rộng tổng hợp của các con của chúng nhỏ hơn tổng không gian trên các trục chính của chúng, thì các con của chúng được bố trí thêm không gian.
MainAxisSize.min
Row
và Column
chỉ chiếm đủ không gian trên các trục chính của chúng cho con của chúng. Con của chúng được bố trí không có không gian thừa và ở giữa các trục chính của chúng.
Mẹo:
MainAxisSize.max
là giá trị mặc định của thuộc tínhmainAxisSize
. Nếu bạn không chỉ định giá trị khác, giá trị mặc định sẽ được sử dụng, như được hiển thị trong ví dụ trên.
Ví dụ: Sửa đổi kích thước trục
Ví dụ sau đặt mainAxisSize
thành giá trị mặc định của nó MainAxisSize.max
.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( mainAxisSize: MainAxisSize.max, children: [ BlueBox(), BlueBox(), BlueBox(), ], ); } } class BlueBox extends StatelessWidget { @override Widget build(BuildContext context) { return Container( width: 50, height: 50, decoration: BoxDecoration( color: Colors.blue, border: Border.all(), ), ); } }
Mẹo: Lưu ý cách phần màu xám đậm của Row biến mất khi bạn thay đổi
MainAxisSize.max
thànhMainAxisSize.min
. Bản thân Row đang chiếm ít chiều rộng hơn của trục chính và được căn giữa vì điều này.
Thuộc tính mainAxisAlignment
Khi mainAxisSize
được đặt thành MainAxisSize.max
thì Row
và Column
có thể khiến con của chúng có thêm không gian. Thuộc tính mainAxisAlignment
xác định cách thức Row
và Column
có thể định vị con của chúng trong không gian bổ sung đó. mainAxisAlignment
có sáu giá trị có thể có:
MainAxisAlignment.start
Vị trí con gần đầu trục chính (trái cho Row
, trên cùng cho Column
).
MainAxisAlignment.end
Vị trí con gần cuối trục chính (phải cho Row
, dưới cùng cho Column
).
MainAxisAlignment.center
Vị trí con ở giữa trục chính.
MainAxisAlignment.spaceBetween
Chia đều không gian thừa giữa các con.
MainAxisAlignment.spaceEvenly
Chia đều không gian thừa giữa con và trước và sau con.
MainAxisAlignment.spaceAround
Tương tự như MainAxisAlignment.spaceEvenly
, nhưng giảm một nửa không gian trước con đầu tiên và sau con cuối cùng xuống một nửa chiều rộng giữa các con.
Ví dụ: Sửa đổi căn chỉnh trục chính
Ví dụ sau đặt mainAxisAlignment
thành giá trị mặc định của nó MainAxisAlignment.start
.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.start, children: [ BlueBox(), BlueBox(), BlueBox(), ], ); } } class BlueBox extends StatelessWidget { @override Widget build(BuildContext context) { return Container( width: 50, height: 50, decoration: BoxDecoration( color: Colors.blue, border: Border.all(), ), ); } }
Mẹo: Trước khi chuyển sang phần tiếp theo, hãy thay đổi
MainAxisAlignment.end
sang giá trị khác.
Thuộc tính crossAxisAlignment
Thuộc tính crossAxisAlignment
xác định cách Row
và Column
có thể xác định vị trí con của chúng trên trục chéo của chúng. Trục chéo của Row
là thẳng và của Column
là nằm ngang. crossAxisAlignment
có năm giá trị có thể:
CrossAxisAlignment.start
Vị trí con gần điểm bắt đầu của trục chéo (trên cùng cho Row
, trái cho Column
).
CrossAxisAlignment.end
Vị trí con gần cuối trục chéo (dưới cùng cho Row
, phải cho Column
).
CrossAxisAlignment.center
Vị trí con ở giữa trục chéo (giữa cho Row
, trung tâm cho Column
).
CrossAxisAlignment.stretch
Kéo dài con qua trục chéo (từ trên xuống dưới cho Row
, từ trái sang phải cho Column
).
CrossAxisAlignment.baseline
Căn chỉnh con theo đường cơ bản của chúng (chỉ dành cho lớp Text
và yêu cầu thuộc tính textBaseline
được đặt thành TextBaseline.alphabetic
. Hãy xem phần Text widget để biết ví dụ).
Ví dụ: Sửa đổi căn chỉnh trục chéo
Ví dụ sau đặt crossAxisAlignment
thành giá trị mặc định của nó CrossAxisAlignment.center
.
Để chứng minh sự căn chỉnh trục chéo, mainAxisAlignment
được đặt thành MainAxisAlignment.spaceAround
và Row
hiện chứa một widget con BiggerBlueBox
cao hơn các widget BlueBox
.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.spaceAround, crossAxisAlignment: CrossAxisAlignment.center, children: [ BlueBox(), BiggerBlueBox(), BlueBox(), ], ); } } class BlueBox extends StatelessWidget { @override Widget build(BuildContext context) { return Container( width: 50, height: 50, decoration: BoxDecoration( color: Colors.blue, border: Border.all(), ), ); } } class BiggerBlueBox extends StatelessWidget { @override Widget build(BuildContext context) { return Container( width: 50, height: 100, decoration: BoxDecoration( color: Colors.blue, border: Border.all(), ), ); } }
Mẹo: Trước khi chuyển sang phần tiếp theo, hãy thay đổi
CrossAxisAlignment.start
thành giá trị khác.
Widget Flexible
Như bạn đã thấy, các thuộc tính mainAxisAlignment
và crossAxisAlignment
xác định cách Row
và Column
định vị trí các widget dọc theo cả hai trục. Row
và Column
đầu tiên bố trí các widget có kích thước cố định. Các widget có kích thước cố định được coi là không linh hoạt vì chúng không thể tự thay đổi kích thước sau khi đã được bố trí.
Widget Flexible
sẽ gộp widget, vì vậy widget đó có thể thay đổi kích thước. Khi widget Flexible
gộp một widget thì widget đó sẽ trở thành Flexible
con của widget đó và được coi là linh hoạt . Sau khi các widget không linh hoạt được bố trí, các widget được thay đổi kích thước theo các thuộc tính flex
và fit
của chúng:
flex
So sánh chính nó với các thuộc tính flex
khác trước khi xác định phần nào trong tổng dung lượng còn lại mà mỗi widget Flexible
nhận được.
fit
Xác định xem một widget Flexible
có lấp đầy tất cả không gian bổ sung của nó hay không.
Ví dụ: Thay đổi thuộc tính phù hợp
Ví dụ sau minh họa thuộc tính fit
, có thể có một trong hai giá trị:
FlexFit.loose
Kích thước ưa thích của tiện ích được sử dụng (mặc định).
FlexFit.tight
Buộc tiện ích phải lấp đầy tất cả không gian thừa của nó.
Trong ví dụ này, hãy thay đổi thuộc tính fit
để làm cho các widget Flexible
lấp đầy không gian thừa.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( children: [ BlueBox(), Flexible( fit: FlexFit.loose, flex: 1, child: BlueBox(), ), Flexible( fit: FlexFit.loose, flex: 1, child: BlueBox(), ), ], ); } } class BlueBox extends StatelessWidget { @override Widget build(BuildContext context) { return Container( width: 50, height: 50, decoration: BoxDecoration( color: Colors.blue, border: Border.all(), ), ); } }
Ví dụ: Kiểm tra giá trị flex
Trong ví dụ sau, Row
chứa một widget BlueBox
và hai widget Flexible
bao ngoài hai widget BlueBox
. Các widget Flexible
chứa các thuộc tính flex
có giá trị flex
đặt thành 1 (giá trị mặc định).
Khi các thuộc tính flex
được so sánh với nhau, tỷ lệ giữa các giá trị flex
của chúng xác định phần nào trong tổng không gian còn lại mà mỗi widget Flexible
nhận được.
remainingSpace * (flex / totalOfAllFlexValues)
Trong ví dụ này, tổng các giá trị flex
(2), xác định rằng cả hai widget Flexible
đều nhận được một nửa tổng không gian còn lại. Widget BlueBox
(hoặc widget kích thước cố định) vẫn cùng kích thước.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( children: [ BlueBox(), Flexible( fit: FlexFit.tight, flex: 1, child: BlueBox(), ), Flexible( fit: FlexFit.tight, flex: 1, child: BlueBox(), ), ], ); } } class BlueBox extends StatelessWidget { @override Widget build(BuildContext context) { return Container( width: 50, height: 50, decoration: BoxDecoration( color: Colors.blue, border: Border.all(), ), ); } }
Mẹo: Trước khi chuyển sang ví dụ tiếp theo, hãy thử thay đổi các thuộc tính
flex
thành các giá trị khác, chẳng hạn như 2 và 1.
Widget Expanded
Tương tự như Flexible
, widget Expanded
có thể bao ngoài một widget khác và buộc nó phải lấp đầy không gian mở rộng.
Mẹo: Sự khác biệt giữa Flexible và Expanded là gì? Sử dụng
Flexible
để thay đổi kích thước các widget trongRow
hoặcColumn
. Bằng cách đó, bạn có thể điều chỉnh khoảng cách của tiện ích con trong khi vẫn giữ kích thước của nó tương quan với tiện ích mẹ. Sử dụngExpanded
để thay đổi các ràng buộc của một widget con, để nó lấp đầy bất kỳ không gian trống nào.
Để tìm hiểu thêm về các ràng buộc và cách chúng ảnh hưởng đến cách Flutter xác định kích thước và vị trí của các tiện ích con của nó, hãy xem bài viết Tìm hiểu các ràng buộc.
Ví dụ: Điền thêm không gian
Ví dụ sau minh họa cách widget Expanded
buộc widget con của nó là BlueBox lấp đầy không gian thừa.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( children: [ BlueBox(), Expanded( child: BlueBox(), ), BlueBox(), ], ); } } class BlueBox extends StatelessWidget { @override Widget build(BuildContext context) { return Container( width: 50, height: 50, decoration: BoxDecoration( color: Colors.blue, border: Border.all(), ), ); } }
Widget SizedBox
Widget SizedBox
có thể được sử dụng theo một trong hai cách khi tạo kích thước chính xác. Khi SizedBox
kết thúc một widget, nó sẽ thay đổi kích thước của widget bằng cách sử dụng các thuộc tính height
và width
. Khi nó không bao ngoài widget nào thì nó sẽ sử dụng các thuộc tính height
và width
để tạo không gian trống.
Ví dụ: Thay đổi kích thước widget
Ví dụ sau bao ngoài widget BlueBox
thứ 2 bởi một widget SizedBox
và đặt chiều rộng và chiều cao của BlueBox
đó thành 100 pixel.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( mainAxisSize: MainAxisSize.max, children: [ BlueBox(), SizedBox( width: 100, height: 100, child: BlueBox(), ), BlueBox(), ], ); } } class BlueBox extends StatelessWidget { @override Widget build(BuildContext context) { return Container( width: 50, height: 50, decoration: BoxDecoration( color: Colors.blue, border: Border.all(), ), ); } }
Ví dụ: Tạo không gian
Ví dụ sau chứa ba widget BlueBox
và hai widget SizedBox
nằm xen kẽ giữa các widget BlueBox
, trong đó widget SizedBox
thứ nhất chứa thuộc tính width
mang giá trị 50 pixel, widget SizedBox còn lại chứa thuộc tính width mang giá trị 25 pixel.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( children: [ BlueBox(), SizedBox(width: 50), BlueBox(), SizedBox(width: 25), BlueBox(), ], ); } } class BlueBox extends StatelessWidget { @override Widget build(BuildContext context) { return Container( width: 50, height: 50, decoration: BoxDecoration( color: Colors.blue, border: Border.all(), ), ); } }
Widget Spacer
Tương tự như SizedBox
, widget Spacer
cũng có thể tạo khoảng cách giữa các widget.
Mẹo: Sự khác biệt giữa SizedBox và Spacer là gì? Sử dụng
Spacer
khi bạn muốn tạo không gian bằng thuộc tínhflex
. Sử dụngSizedBox
khi bạn muốn tạo không gian bằng cách sử dụng một số pixel logic cụ thể.
Ví dụ: Tạo thêm không gian
Ví dụ sau xen kẽ các widget BlueBox
là các widget Spacer
có flex
giá trị là 1.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( children: [ BlueBox(), Spacer(flex: 1), BlueBox(), Spacer(flex: 1), BlueBox(), ], ); } } class BlueBox extends StatelessWidget { @override Widget build(BuildContext context) { return Container( width: 50, height: 50, decoration: BoxDecoration( color: Colors.blue, border: Border.all(), ), ); } }
Widget Text
Widget Text
hiển thị widget và có thể được cấu hình cho các phông chữ, kích thước và màu sắc khác nhau.
Ví dụ: Căn chỉnh văn bản
Ví dụ sau hiển thị “V1S!” ba lần, nhưng ở các cỡ chữ khác nhau và có màu sắc khác nhau. Row
xác định các thuộc tính crossAxisAlignment
và textBaseline
.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.baseline, textBaseline: TextBaseline.alphabetic, children: [ Text( 'V1S!', style: TextStyle( fontSize: 30, fontFamily: 'Futura', color: Colors.blue, ), ), Text( 'V1S!', style: TextStyle( fontSize: 50, fontFamily: 'Futura', color: Colors.green, ), ), Text( 'V1S!', style: TextStyle( fontSize: 40, fontFamily: 'Futura', color: Colors.red, ), ), ], ); } }
Widget Icon
Widget Icon
hiển thị một biểu tượng đồ họa thể hiện một phần của giao diện người dùng. Flutter có sẵn các gói biểu tượng cho các ứng dụng Material và Cupertino.
Ví dụ: Tạo biểu tượng
Ví dụ sau đây hiển thị widget Icons.widget
từ thư viện Icon Material bằng màu đỏ và xanh lam.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( crossAxisAlignment:CrossAxisAlignment.center, textBaseline:TextBaseline.alphabetic, children: [ Icon( Icons.widgets, size:50, color:Colors.blue, ), Icon( Icons.widgets, size:50, color:Colors.red, ), Icon( Icons.widgets, size:50, color:Colors.amber, ), ], ); } }
Widget Image
Widget Image
dùng để hiển thị một hình ảnh. Bạn có thể tham chiếu hình ảnh bằng URL hoặc bạn có thể bao gồm hình ảnh bên trong gói ứng dụng của mình. Vì DartPad không thể đóng gói hình ảnh, nên ví dụ sau sử dụng hình ảnh từ mạng.
Ví dụ: Hiển thị hình ảnh
Ví dụ sau hiển thị một hình ảnh được lưu trữ từ xa trên photo của google. Phương thức Image.network
có một tham số chuỗi chứa URL của hình ảnh.
Trong ví dụ này, Image.network
chứa một URL ngắn.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.network('https://photos.app.goo.gl/Js91nDs2fPcRwGRy5'), ], ); } }
Ví dụ áp dụng
Bạn sắp kết thúc bài viết codelab này. Nếu bạn muốn kiểm tra kiến thức của mình về các kỹ thuật bạn đã học, bạn hãy áp dụng những kỹ năng đó vào việc xây dựng giao diện người dùng Flutter hiển thị danh thiếp như hình dưới đây nhé:
Bạn sẽ chia bố cục của Flutter thành các phần, đó là cách bạn tạo giao diện người dùng Flutter trong thế giới thực.
Trong Phần 1, bạn sẽ triển khai một Column
chứa tên và tiêu đề. Sau đó, bạn sẽ bọc Column
trong một Row
cái có chứa biểu tượng, được đặt ở bên trái của tên và tiêu đề.
Trong Phần 2, bạn sẽ bao ngoài mã Row
trong một Column
, vì vậy thành ra là mã chứa một Column
trong một Row
trong một Column
. Sau đó, bạn sẽ điều chỉnh bố cục Column
của ngoài cùng , để nó trông đẹp mắt hơn. Cuối cùng, bạn sẽ thêm thông tin liên hệ vào danh sách con Column
ở ngoài cùng, vì vậy thông tin liên hệ được hiển thị bên dưới tên, tiêu đề và biểu tượng như sau:
Trong Phần 3, bạn sẽ hoàn thành việc xây dựng hiển thị danh thiếp bằng cách thêm bốn biểu tượng khác, được đặt bên dưới thông tin liên hệ.
Phần 1
Bài tập: Tạo tên và tiêu đề
Triển khai một Column
chứa hai widget văn bản:
-
Widget Text đầu tiên có tên
Flutter McFlutter
và thuộc tínhstyle
được đặt thànhTheme.of(context).textTheme.headline
. -
Widget Text thứ hai chứa tiêu đề
Experienced Developer
.
Đối với Column
, đặt mainAxisSize
thành MainAxisSize.min
và crossAxisAlignment
thành CrossAxisAlignment.start
.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Flutter McFlutter', style: Theme.of(context).textTheme.headline), Text('Experienced Developer'), ], ); } }
Bài tập: Gộp cột trong một hàng
Gộp Column
mà bạn đã triển khai trong một Row
chứa các widget sau:
-
Một widget
Icon
được đặt thànhIcons.account_circle
và có kích thước là 50 pixel. -
Một widget
Padding
tạo ra một không gian 8 pixel xung quanh widgetIcon
.Để làm điều này, bạn có thể chỉ định
const EdgeInsets.all(8.0)
cho thuộc tínhpadding
.Row
sẽ trông như thế này:Row( children: [ Padding( padding: const EdgeInsets.all(8.0), child: Icon(Icons.account_circle, size: 50), ), Column( ... ), // <--- The Column you first implemented ], );
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Row( children: [ Padding( padding: const EdgeInsets.all(8.0), child: Icon(Icons.account_circle, size: 50)), Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Flutter McFlutter', style: Theme.of(context).textTheme.headline), Text('Experienced App Developer'), ], ), ], ); } }
Phần 2
Bài tập: Chỉnh sửa bố cục
Bao ngoài Row
trong một Column
có thuộc tính mainAxisSize
được đặt thành MainAxisSize.min
và thuộc tính crossAxisAlignment
tính được đặt thành CrossAxisAlignment.stretch
. Column
chứa các widget sau:
-
Một widget
SizedBox
có chiều cao là 8. -
Khoảng trống
Row
nơi bạn sẽ thêm thông tin liên hệ ở bước sau. -
Widget SizedBox thứ hai có chiều cao là 16.
-
Khoảng trống thứ hai
Row
nơi bạn sẽ thêm bốn biểu tượng (Phần 3).
Các widget của Column
cần được định dạng như sau để thông tin liên lạc và các biểu tượng được hiển thị dưới tên và chức danh:
],
), // <--- Closing parenthesis for the Row
SizedBox(),
Row(), // First empty Row
SizedBox(),
Row(), // Second empty Row
],
); // <--- Closing parenthesis for the Column that wraps the Row
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Row( children: [ Padding( padding: const EdgeInsets.all(8.0), child: Icon(Icons.account_circle, size: 50), ), Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( 'Flutter McFlutter', style: Theme.of(context).textTheme.headline, ), Text( 'Experienced App Developer', ) ], ), ], ), SizedBox(height: 8), Row(), SizedBox(height: 16), Row(), ], ); } }
Bài tập: Nhập thông tin liên hệ
Nhập hai widget Text
bên trong ô trống đầu tiên Row
:
-
Widget Text đầu tiên chứa địa chỉ
123 Main Street
. -
Widget Text thứ hai chứa số điện thoại
(415) 555-0198
.
Đối với ô trống đầu tiên Row
, hãy đặt thuộc tính mainAxisAlignment
thành MainAxisAlignment.spaceBetween
.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.account_circle, size: 50),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Flutter McFlutter',
style: Theme.of(context).textTheme.headline,
),
Text(
'Experienced App Developer',
)
],
),
],
),
SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'123 Main Street',
),
Text(
'(415) 555-0198',
),
],
),
SizedBox(height: 16),
Row(),
],
);
}
}
Phần 3
Bài tập: Thêm bốn biểu tượng
Đưa các widget Icon
sau vào ô trống thứ hai Row
:
Icons.accessibility
Icons.timer
Icons.phone_android
Icons.phone_iphone
Đối với ô trống thứ hai Row
, hãy đặt thuộc tính mainAxisAlignment
thành MainAxisAlignment.spaceAround
.
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Column( mainAxisSize:MainAxisSize.min, crossAxisAlignment:CrossAxisAlignment.stretch, children: [ Row( children: [ Padding( padding: const EdgeInsets.all(8.0), child:Icon(Icons.account_circle, size:50), ), Column( crossAxisAlignment:CrossAxisAlignment.start, mainAxisSize:MainAxisSize.min, children: [ Text( 'Flutter McFlutter', style:Theme.of(context).textTheme.headline, ), Text( 'Experienced App Developer', ) ], ), ], ), SizedBox(height:8), Row( mainAxisAlignment:MainAxisAlignment.spaceBetween, children: [ Text( '123 Main Street', ), Text( '(415) 555-0198', ), ], ), SizedBox(height:16), Row( mainAxisAlignment:MainAxisAlignment.spaceAround, children: [ Icon(Icons.accessibility), Icon(Icons.timer), Icon(Icons.phone_android), Icon(Icons.phone_iphone), ], ), ], ); } }
Tổng kết
Xin chúc mừng, bạn đã hoàn thành codelab! Nếu bạn muốn biết thêm về Flutter, đây là một vài gợi ý về các tài nguyên đáng để khám phá:
- Tìm hiểu thêm về bố cục trong Flutter bằng cách truy cập bài viết Xây dựng bố cục (layout).
- Kiểm tra các ứng dụng mẫu.
- Truy cập kênh YouTube của Flutter , nơi bạn có thể xem nhiều video khác nhau, từ video tập trung vào các tiện ích riêng lẻ đến video của các nhà phát triển đang xây dựng ứng dụng.
Giải phóng thời gian, khai phóng năng lực