Kiến thức

Layouts trong Flutter 14 tháng 04, 2022 – 26 lượt xem Di động Flutter Đầu mục bài viết Bài viết liên quan Khoá học hay

Tiêu chí của bài viết

  • Nắm được những widget ( những class) được sử dụng để tạo UI.
  • Widget được sử dụng cho cả layout và thành phần UI.
  • Liên kết những widget dễ dãi để xây dựng những widget phức tạp.

Giới thiệu

Chế độ mấu chốt để xây dựng nên layout trong Flutter là Widget. Trong Flutter, hầu như tất cả mọi thứ đều là Widget – thậm chí là model layout cũng là Widget. Ảnh, icon, text bạn thấy trong 1 phần mềm Flutter tất cả đều là widget. Nhưng mà những thứ bạn ko thấy cũng là widget, thí dụ như rows, columns, và grid,… những widget này tạo điều kiện cho việc sắp đặt, buộc ràng, căn chỉnh những visible widget (những widget nhưng mà bạn thấy nhìn là thấy). ( Từ đây mình sẽ gọi widget nhận ra được – visible widget, và widget ko nhận ra được – invisible widget; để các bạn có thể tiện theo dõi).

Bạn có thể tạo layout bằng cách liên kết những widget với nhau để hình thành những widget phức tạp hơn. Thí dụ dưới đây tạo ra 3 icon với nhãn dán nằm dưới:

Dưới đây là diagram của widget tree cho UI trên:

Hầu như mọi thứ bạn thấy trên ảnh có vẻ giống như bạn tưởng tượng đúng ko? Nhưng mà bạn thử chú ý về những hình Container ( màu hồng trong ảnh) xem. Container là 1 widget class cho phép bạn có thể tùy chỉnh widget con bên trong nó. Sử dụng Container lúc bạn muốn thêm padding, margin, border, màu nền…

Trong thí dụ này, mỗi Text widget được đặt bên trong 1 Container để chúng ta có thể thêm margin, cách 1 khoảng so với Icon phía trên nó. Toàn thể Row được đặt trong Container để thêm padding bao quanh Row.

Phần còn lại của UI trong thí dụ này được điều khiển bằng properties. Thí dụ: Chỉnh sửa màu Icon bằng cách sử dụng color property, sử dụng Text.style property để tạo Font chữ, màu, độ đậm nhạt… Column và row có những property cho phép bạn xác định cách những widget con được căn chỉnh dọc hay ngang, hay xác định độ giãn cách giữa các widget con này.

Sắp xếp 1 Widget

Làm thế nào để sắp đặt 1 widget trong Flutter? Bài viết này sẽ chỉ ra cách bạn có thể tạo và hiển thị 1 widget dễ dãi và chúng ta sẽ cùng nhau code 1 thí dụ Hello world dễ dãi nhất nhé!

Trong Flutter, chúng ta sẽ mất 1 vài bước để đặt text, icon, hoặc Image vào màn hình.

1. Cách tuyển lựa layout widget

Việc tuyển lựa layout widget từ 1 tập rất nhiều layout widget ngày nay dựa trên cách nhưng mà bạn muốn căn chỉnh hay buộc ràng visible widget, vì những đặc điểm này thường được chuyển cho widget con.

Thí dụ ta sử dụng widget Center trong trường hợp muốn căn giữa content trong nó theo cả chiều dọc và chiều ngang.

2. Tạo 1 visible widget

Thí dụ, để tạo 1 Text widget:

Text('Hello World'),

Tạo 1 Image widget:

Image.asset(
'images/lake.jpg',
fit: BoxFit.cover,
),

Tạo 1 Icon widget:

Icon(
Icons.star,
color: Colors.red[500],
),

3. Thêm visible widget vào layout widget

Tất cả những layout widget đều có những thứ sau:

  • 1 tính chất (property) child nếu nó cần 1 widget con, thí dụ: Center, Container,

  • 1 tính chất (property) children nếu nó cần 1 tập danh sách các widget con, thí dụ: Row, Column, ListView, Stack,…

Thêm Text widget vào Center widget:

const Center(
child: Text('Hello World'),
),

4. Thêm layout widget vào trong trang (page) UI

Bản thân 1 app Flutter cũng là 1 widget, và hầu như đều có method build(). Khởi tạo và trả về 1 widget trong method build() sẽ giúp hiển thị widget.

Material apps

Đối với 1 Material app, bạn có thể sử dụng Scaffold widget, widget này hỗ trợ 1 banner mặc định, màu nền page, và có API cho việc thêm drawer, snackbar, bottom sheet… Sau đấy bạn có thể thêm Center widget trực tiếp vào body property để căn giữa nội dung hiển thị trong page.

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

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

Để mắt: Thư viện Material khai triển những widget dựa theo nguyên lý Material Design. Lúc thiết kế UI của bạn, bạn có thể sử dụng những thư viện widget tiêu chuẩn, hoặc bạn cũng có thể sử dụng widget từ thư viện Material

Non-Material apps

Đối với 1 non-Material app, bạn có thể thêm Center widget vào method build():

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

@override
Widget build(BuildContext context) {
    return Container(
      decoration: const BoxDecoration(color: Colors.white),
      child: const Center(
        child: Text(
          'Hello World',
          textDirection: TextDirection.ltr,
          style: TextStyle(
            fontSize: 32,
            color: Colors.black87,
          ),
        ),
      ),
    );
}
}

Mặc định, non-Material ko bao gồm AppBar, tiêu đề hay màu nền. Nếu bạn muốn những tác dụng này trong non-Material, bạn phải tự làm.

Sắp xếp các widget theo chiều ngang và dọc

1 trong những layout pattern tầm thường nhất là sắp đặt widget theo chiều dọc và ngang. Bạn có thể sử dụng Row widget để sắp đặt widget theo chiều ngang, và dùng Column để sắp đặt theo chiều dọc.

  • RowColumn là 2 trong số những layout pattern được sử dụng tầm thường nhất.

  • RowColumn cần 1 danh sách các widget con.

  • Mỗi widget con có thể là Row hoặc Column, hoặc 1 widget phức tạp nào khác.

  • Bạn có thân xác định cách RowColumn căn chỉnh widget con của nó, theo cả chiều ngang và dọc.

  • Bạn có thể nới rộng hoặc buộc ràng widget con.

  • Bạn có thân xác định cách những widget con sử dụng khoảng trống có sẵn của Row hoặc Column

Thí dụ sau đây chỉ ra cách 1 Row hoặc Column nằm trong Row hoặc Column.

RowColumn là các widget nguyên thủy căn bản cho bố cục ngang và dọc — những widget con cấp thấp này cho phép tùy chỉnh tối đa. Flutter cũng hỗ trợ các widget chuyên biệt, cấp cao hơn có thể đủ cho nhu cầu của bạn. Thí dụ: thay vì Row, bạn có thể thích ListTile, 1 tiện ích dễ sử dụng với các tính chất cho các biểu trưng đầu và cuối, và tối đa 3 dòng văn bản. Thay vì Column, bạn có thể thích ListView, 1 bố cục giống như cột nhưng mà tự động cuộn nếu nội dung của nó quá dài để thích hợp với ko gian có sẵn.

Aligning widgets ( căn chỉnh widget)

Bạn có thể kiểm soát cách 1 Row hoặc Column căn chỉnh con của nó bằng cách sử dụng các tính chất mainAxisAlignmentcrossAxisAlignment. Đối với 1 Row, trục chính chạy theo chiều ngang và trục chéo chạy theo chiều dọc. Đối với 1 Column, trục chính chạy theo chiều dọc và trục chéo chạy theo chiều ngang. Bạn có thể nhìn hình vẽ sau để thông suốt hơn:

1 thí dụ khác RowColumn sử dụng với Image:

Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
	Image.asset(‘images/pic1.jpg’),
	Image.asset(‘images/pic2.jpg’),
	Image.asset(‘images/pic3.jpg’),
],
);

Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
    Image.asset('images/pic1.jpg'),
    Image.asset('images/pic2.jpg'),
    Image.asset('images/pic3.jpg'),
],
);

Sizing widgets

Lúc bố cục quá bự để vừa với 1 thiết bị, 1 hình sọc màu vàng và đen sẽ hiện ra dọc theo cạnh bị tác động. Đây là 1 thí dụ về Row quá rộng:

Các widget con có thể được định kích tấc để vừa với 1 Row hoặc Column bằng cách sử dụng Expanded widget. Để sửa thí dụ trước trong đấy hàng hình ảnh quá rộng đối với mức hiển thị của nó, hãy bọc mỗi hình ảnh bằng 1 Expanded widget.

Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
    Expanded(
      child: Image.asset('images/pic1.jpg'),
    ),
    Expanded(
      child: Image.asset('images/pic2.jpg'),
    ),
    Expanded(
      child: Image.asset('images/pic3.jpg'),
    ),
],
);

Nếu bạn muốn 1 widget chiếm ko gian gấp đôi so với các widget anh chị em của nó. Để làm điều này, hãy sử dụng tính chất flex trong Expanded widget, 1 số nguyên xác định hệ số flex cho widget con. Hệ số flex mặc định là 1. Đoạn mã sau đặt hệ số flex của hình ảnh giữa thành 2:

Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
    Expanded(
      child: Image.asset('images/pic1.jpg'),
    ),
    Expanded(
      flex: 2,
      child: Image.asset('images/pic2.jpg'),
    ),
    Expanded(
      child: Image.asset('images/pic3.jpg'),
    ),
],
);

Packing widgets

Theo mặc định, 1 Row hoặc Column chiếm càng nhiều ko gian dọc theo trục chính của nó càng tốt, nhưng mà nếu bạn muốn kéo các widget con lại gần nhau, hãy đặt mainAxisSize của nó thành MainAxisSize.min. Thí dụ sau sử dụng tính chất này để đóng gói các hình ngôi sao lại với nhau.

Row(
mainAxisSize: MainAxisSize.min,
children: [
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    const Icon(Icons.star, color: Colors.black),
    const Icon(Icons.star, color: Colors.black),
],
)

Nesting rows and columns

Layout framework cho phép bạn lồng các hàng và cột vào bên trong các hàng và cột tùy thích. Hãy xem đoạn code cho phần được phác thảo của bố cục sau:

Phần được phác thảo được tiến hành thành 2 hàng. Hàng xếp hạng chứa 5 sao và số lượng bình chọn. Hàng biểu trưng chứa 3 cột biểu trưng và văn bản.

Widget tree cho Row chứa 5 sao như sau:

Và mã code cho Row chứa 5 sao và số lượng bình chọn như sau:

var stars = Row(
mainAxisSize: MainAxisSize.min,
children: [
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    Icon(Icons.star, color: Colors.green[500]),
    const Icon(Icons.star, color: Colors.black),
    const Icon(Icons.star, color: Colors.black),
],
);

final ratings = Container(
padding: const EdgeInsets.all(20),
child: Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: [
      stars,
      const Text(
        '170 Reviews',
        style: TextStyle(
          color: Colors.black,
          fontWeight: FontWeight.w800,
          fontFamily: 'Roboto',
          letterSpacing: 0.5,
          fontSize: 20,
        ),
      ),
    ],
),
);

Để hạn chế sự lầm lẫn trực giác có thể do code các layout lồng nhau nhiều, hãy viết các phần của giao diện người mua trong các biến và hàm.

Hàng biểu trưng, bên dưới hàng xếp hạng, có 3 cột, mỗi cột chứa 1 biểu trưng và 2 dòng văn bản, như bạn có thể thấy trong widget tree con của nó:

Mã code như sau:

const descTextStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 18,
height: 2,
);

// DefaultTextStyle.merge() allows you phệ create a default text
// style that is inherited by its child and all subsequent children.
final iconList = DefaultTextStyle.merge(
style: descTextStyle,
child: Container(
    padding: const EdgeInsets.all(20),
    child: Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        Column(
          children: [
            Icon(Icons.kitchen, color: Colors.green[500]),
            const Text('PREP:'),
            const Text('25 min'),
          ],
        ),
        Column(
          children: [
            Icon(Icons.timer, color: Colors.green[500]),
            const Text('COOK:'),
            const Text('1 hr'),
          ],
        ),
        Column(
          children: [
            Icon(Icons.restaurant, color: Colors.green[500]),
            const Text('FEEDS:'),
            const Text('4-6'),
          ],
        ),
      ],
    ),
),
);

Ta có mã code cho phần hình bên trái như sau:

final leftColumn = Container(
padding: const EdgeInsets.fromLTRB(20, 30, 20, 20),
child: Column(
    children: [
      titleText,
      subTitle,
      ratings,
      iconList,
    ],
),
);

Mã code cho toàn thể UI của chúng ta như sau:

body: Center(
child: Container(
    margin: const EdgeInsets.fromLTRB(0, 40, 0, 30),
    height: 600,
    child: Card(
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          SizedBox(
            width: 440,
            child: leftColumn,
          ),
          mainImage,
        ],
      ),
    ),
),
),

Common layout widgets – 1 số widget tầm thường thường gặp

Standard widgets

  • Container: Có thể thêm padding, margins, borders, background color, hoặc decorations vào a widget.
  • GridView: Tạo widgets dạng lưới có bản lĩnh scroll.
  • ListView: Tạo widgets dạng danh sách có bản lĩnh scroll.
  • Stack: Tạo widget có bản lĩnh đè lên trên các widget khác.

Material widgets

  • Card: Tạo 1 widget hình hộp được bo góc và có đổ bóng.
  • ListTile: Tạo widget với 3 dang text, có leading và trailing icon trong 1 dòng.

Container

Rất nhiều layout sử dụng Container, Container dùng để padding, thêm viền, margin… Bạn có thể thay màu nền của thiết bị bằng cách đổi toàn thể layout thành Container và đổi màu nền hoặc ảnh.

Tóm lược về Container

  • Thêm padding, margins, borders
  • Đổi màu background color hoặc image
  • Bao gồm 1 child widget, nhưng mà child có thể là Row, Column, hoặc thậm chi là root của 1 widget tree

Examples (Container)

Thí dụ dưới tạo 1 Column với 2 Row, mỗi Row lại gồm 2 hình ảnh. Container được sử dụng để đổi màu của Column thành màu xám.

Widget _buildImageColumn() {
return Container(
    decoration: const BoxDecoration(
      color: Colors.black26,
    ),
    child: Column(
      children: [
        _buildImageRow(1),
        _buildImageRow(3),
      ],
    ),
);
}

GridView

Sử dụng GridView để sắp đặt các widget dưới dạng danh sách 2 chiều. GridView hỗ trợ 2 danh sách tạo sẵn hoặc bạn có thể tạo lưới tùy chỉnh của riêng mình. Lúc GridView phát hiện thấy nội dung của nó quá dài để vừa với render box, nó sẽ tự động cuộn.

Tóm lược (GridView)

  • Đặt các widget trong 1 danh sách dạng lưới
  • Phát hiện lúc nội dung vượt quá render box và tự động hỗ trợ tác dụng cuộn
  • Tạo lưới tùy chỉnh của riêng bạn hoặc sử dụng 1 trong các lưới được hỗ trợ:
    • GridView.count cho phép bạn chỉ định số lượng cột
    • GridView.extent cho phép bạn chỉ định chiều rộng pixel tối đa của 1 ô

Xem xét: Lúc hiển thị danh sách 2 chiều, trong đấy điều quan trọng là hàng và cột nhưng mà ô chiếm dùng để chứa dữ liệu, hãy sử dụng Bảng hoặc Bảng dữ liệu.

Examples (GridView)

Sử dụng GridView.extent để tạo danh Sách lưới với các ô có chiều rộng tối đa là 150 pixel.
Sử dụng GridView.count để tạo danh sách dạng lưới với 2 ô ở cơ chế dọc và 3 ô ở cơ chế ngang. Tiêu đề được tạo bằng cách đặt tính chất footer cho mỗi GridTile.
Widget _buildGrid() => GridView.extent(
    maxCrossAxisExtent: 150,
    padding: const EdgeInsets.all(4),
    mainAxisSpacing: 4,
    crossAxisSpacing: 4,
    children: _buildGridTileList(30));

// The images are saved with names pic0.jpg, pic1.jpg...pic29.jpg.
// The List.generate() constructor allows an easy way phệ create
// a list when objects have a predictable naming pattern.
List<Container> _buildGridTileList(int count) => List.generate(
    count, (i) => Container(child: Image.asset('images/pic$i.jpg')));

ListView

ListView, 1 widget giống như Column, nhưng mà tự có bản lĩnh cuộn lúc nội dung quá dài so với render box của nó.

Tóm lược (ListView)

  • 1 Column được thiết kế cho việc tổ chức 1 danh sách các hộp, tiệm.
  • Có thể đặt theo chiều dọc hoặc ngang.
  • Phát hiện lúc nội dung ko vừa và tự động cuộn.
  • Ít phải cấu hình hơn Column, nhưng mà dễ sử dụng và trợ ô sin scroll.

Examples (ListView)

Sử dụng ListView để hiển thị danh sách công tác kinh doanh với ListTiles. 1 thanh ngăn Divider giúp chia tách các rạp phim với danh sách nhà hàng
Sử dụng ListView để hiện danh sách Colors từ Material Design palette.
Widget _buildList() {
return ListView(
    children: [
      _tile('CineArts at the Empire', '85 W Portal Ave', Icons.theaters),
      _tile('The Castro Theater', '429 Castro St', Icons.theaters),
      _tile('Alamo Drafthouse Cinema', '2550 Mission St', Icons.theaters),
      _tile('Roxie Theater', '3117 16th St', Icons.theaters),
      _tile('United Artists Stonestown Twin', '501 Buckingham Way',
          Icons.theaters),
      _tile('AMC Metreon 16', '135 4th St #3000', Icons.theaters),
      const Divider(),
      _tile('K's Kitchen', '757 Monterey Blvd', Icons.restaurant),
      _tile('Emmy's Restaurant', '1923 Ocean Ave', Icons.restaurant),
      _tile(
          'Chaiya Thai Restaurant', '272 Claremont Blvd', Icons.restaurant),
      _tile('La Ciccia', '291 30th St', Icons.restaurant),
    ],
);
}

ListTile _tile(String title, String subtitle, IconData icon) {
return ListTile(
    title: Text(title,
        style: const TextStyle(
          fontWeight: FontWeight.w500,
          fontSize: 20,
        )),
    subtitle: Text(subtitle),
    leading: Icon(
      icon,
      color: Colors.blue[500],
    ),
);
}

Stack

Sử dụng Stack để sắp đặt các widget ở phía trên các widget khác – thường là 1 Image. Stack có thể chiếm toàn thể widget phía dưới nó.

Tóm lược (Stack)

  • Sử dụng cho việc chổng các widget lên nhau.
  • Widget trước nhất trong danh sách của Stack gọi là widget base, các widget tiếp sau trong danh sách widget sẽ được đặt đè lên trên widget Base.
  • Content của Stack chẳng thể cuộn.
  • Bạn có thể chọn cách giảm bớt các widget con để hiển thị quá render box.

Examples (Stack)

Sử dụng Stack để đè 1 Container ( Hiện 1 Text với background màu đen trong suốt) lên phía trên của 1 CirlceAvatar. Địa điểm của Text sử dụng alignment property hoặc Alignments widget .
Sử dụng ‘Stack` để đè 1 gradient lên phía trên hình ảnh. Gradient này bảo đảm cho việc hiển thị icon của toolbar phân tích rõ với hình ảnh bên dưới.
Widget _buildStack() {
return Stack(
    alignment: const Alignment(0.6, 0.6),
    children: [
      const CircleAvatar(
        backgroundImage: AssetImage('images/pic.jpg'),
        radius: 100,
      ),
      Container(
        decoration: const BoxDecoration(
          color: Colors.black45,
        ),
        child: const Text(
          'Mia B',
          style: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.bold,
            color: Colors.white,
          ),
        ),
      ),
    ],
);
}

Card

Card, từ thư viện Material, chứa các thông tin liên can và có thể được tạo từ phần nhiều các widget, nhưng mà thường được sử dụng với ListTile. Card có 1 widget con, nhưng mà widget con của nó có thể là 1 ‘Colum , ‘Row, ListView, GridView hoặc các widget con khác cung ứng list widget. Theo mặc định, 1 Card thu bé kích tấc của nó thành 0 x 0 pixel. Bạn có thể sử dụng SizedBox để giới hạn kích tấc của thẻ.

Trong Flutter, Card có các góc bo tròn và bóng đổ, tạo hiệu ứng 3D. Chỉnh sửa tính chất elevation của Card cho phép bạn kiểm soát hiệu ứng đổ bóng. Thí dụ: đặt elevation lên 24, trực giác nâng Card lên khỏi bề mặt và khiến cho bóng trở thành phân tán hơn. Để biết danh sách các trị giá độ cao được cung ứng, hãy xem Elevation trong nguyên tắc Material. Việc chỉ định 1 trị giá ko được cung ứng sẽ vô hiệu hóa hoàn toàn bóng đổ.

Tóm lược (Card).

  • Khai triển Material card
  • Được sử dụng để thể hiện các thông tin liên can
  • Chấp thuận 1 widget con, nhưng mà phần tử đấy có thể là Colum, Row, ListView, GridView hoặc các widget con khác cung ứng list widget
  • Được hiển thị với các góc bo tròn và bóng đổ
  • Nội dung của Card chẳng thể cuộn
  • Từ thư viện Material

Examples (Card)

1 Card bao gồm 3 ListTiles và giới hạn kích tấc bằng các bọc trong 1 SizedBox. 1 thanh ngăn Divider giúp phân tích 2 ListTiles với nhau.
1 Card bao gồm hình ảnh và text.
Widget _buildCard() {
return SizedBox(
    height: 210,
    child: Card(
      child: Column(
        children: [
          ListTile(
            title: const Text(
              '1625 Main Street',
              style: TextStyle(fontWeight: FontWeight.w500),
            ),
            subtitle: const Text('My City, CA 99984'),
            leading: Icon(
              Icons.restaurant_menu,
              color: Colors.blue[500],
            ),
          ),
          const Divider(),
          ListTile(
            title: const Text(
              '(408) 555-1212',
              style: TextStyle(fontWeight: FontWeight.w500),
            ),
            leading: Icon(
              Icons.contact_phone,
              color: Colors.blue[500],
            ),
          ),
          ListTile(
            title: const Text('costa@example.com'),
            leading: Icon(
              Icons.contact_mail,
              color: Colors.blue[500],
            ),
          ),
        ],
      ),
    ),
);
}

ListTile

Sử dụng ListTile, 1 widget giống Row từ thư viện Material, để dễ ợt tạo 1 hàng chứa tối đa 3 dòng văn bản và các biểu trưng đầu và cuối tùy chọn. ListTile được sử dụng tầm thường nhất trong Card hoặc ListView, nhưng mà có thể được sử dụng ở những nơi khác.

Tóm lược (ListTile)

  • 1 widget giống Row chứa tối đa 3 dòng văn bản và các biểu trưng tùy chọn
  • Ít cấu hình hơn Row, nhưng mà dễ sử dụng hơn
  • Từ thư viện Material

Examples (ListTile)

1 Card bao gồm 3 ListTiles.
Sử dụng ListTile để tạo danh sách gồm 3 button dạng dropdown.

Tổng kết

Trên đây mình đã giới thiệu với các bạn các widget căn bản trong Flutter, cách tạo và sử dụng, liên kết các widget dễ dãi để hình thành những widget phức tạp hơn. Kì vọng các bạn có thể hiểu và nắm được 1 cách tổng quan nhất về layout widget, thành phần hình thành UI của Flutter nhé!

Tham khảo

Bài viết có tham khảo từ https://docs.flutter.dev/


Thông tin thêm

Layouts trong Flutter
14 tháng 04, 2022 – 26 lượt xem
Thiết bị cầm tay Flutter
Đầu mục bài viết
Bài viết liên can
Khoá học hay

#Layouts #trong #Flutter14 #tháng #lượt #xem #động #Flutter #Đầu #mục #bài #viếtBài #viết #liên #quanKhoá #học #hay
[rule_3_plain] #Layouts #trong #Flutter14 #tháng #lượt #xem #động #Flutter #Đầu #mục #bài #viếtBài #viết #liên #quanKhoá #học #hay
Tiêu chí của bài viếtNắm được những widget ( những class) được sử dụng để tạo UI.Widget được sử dụng cho cả layout và thành phần UI.Liên kết những widget dễ dãi để xây dựng những widget phức tạp.Giới thiệuCơ chế mấu chốt để xây dựng nên layout trong Flutter là Widget. Trong Flutter, hầu như tất cả mọi thứ đều là Widget – thậm chí là model layout cũng là Widget. Ảnh, icon, text bạn thấy trong 1 phần mềm Flutter tất cả đều là widget. Nhưng mà những thứ bạn ko thấy cũng là widget, thí dụ như rows, columns, và grid,… những widget này tạo điều kiện cho việc sắp đặt, buộc ràng, căn chỉnh những visible widget (những widget nhưng mà bạn thấy nhìn là thấy). ( Từ đây mình sẽ gọi widget nhận ra được – visible widget, và widget ko nhận ra được – invisible widget; để các bạn có thể tiện theo dõi).Bạn có thể tạo layout bằng cách liên kết những widget với nhau để hình thành những widget phức tạp hơn. Thí dụ dưới đây tạo ra 3 icon với nhãn dán nằm dưới:Dưới đây là diagram của widget tree cho UI trên:Hầu như mọi thứ bạn thấy trên ảnh có vẻ giống như bạn tưởng tượng đúng ko? Nhưng mà bạn thử chú ý về những hình Container ( màu hồng trong ảnh) xem. Container là 1 widget class cho phép bạn có thể tùy chỉnh widget con bên trong nó. Sử dụng Container lúc bạn muốn thêm padding, margin, border, màu nền…Trong thí dụ này, mỗi Text widget được đặt bên trong 1 Container để chúng ta có thể thêm margin, cách 1 khoảng so với Icon phía trên nó. Toàn thể Row được đặt trong Container để thêm padding bao quanh Row.Phần còn lại của UI trong thí dụ này được điều khiển bằng properties. Thí dụ: Chỉnh sửa màu Icon bằng cách sử dụng color property, sử dụng Text.style property để tạo Font chữ, màu, độ đậm nhạt… Column và row có những property cho phép bạn xác định cách những widget con được căn chỉnh dọc hay ngang, hay xác định độ giãn cách giữa các widget con này.Sắp xếp 1 WidgetLàm thế nào để sắp đặt 1 widget trong Flutter? Bài viết này sẽ chỉ ra cách bạn có thể tạo và hiển thị 1 widget dễ dãi và chúng ta sẽ cùng nhau code 1 thí dụ Hello world dễ dãi nhất nhé!Trong Flutter, chúng ta sẽ mất 1 vài bước để đặt text, icon, hoặc Image vào màn hình.1. Cách tuyển lựa layout widgetViệc tuyển lựa layout widget từ 1 tập rất nhiều layout widget ngày nay dựa trên cách nhưng mà bạn muốn căn chỉnh hay buộc ràng visible widget, vì những đặc điểm này thường được chuyển cho widget con.Thí dụ ta sử dụng widget Center trong trường hợp muốn căn giữa content trong nó theo cả chiều dọc và chiều ngang.2. Tạo 1 visible widgetVí dụ, để tạo 1 Text widget:Text(‘Hello World’),
Tạo 1 Image widget:Image.asset(
‘images/lake.jpg’,
fit: BoxFit.cover,
),
Tạo 1 Icon widget:Icon(
Icons.star,
color: Colors.red[500],
),

3. Thêm visible widget vào layout widgetTất cả những layout widget đều có những thứ sau:1 tính chất (property) child nếu nó cần 1 widget con, thí dụ: Center, Container,1 tính chất (property) children nếu nó cần 1 tập danh sách các widget con, thí dụ: Row, Column, ListView, Stack,…Thêm Text widget vào Center widget:const Center(
child: Text(‘Hello World’),
),

4. Thêm layout widget vào trong trang (page) UIBản thân 1 app Flutter cũng là 1 widget, và hầu như đều có method build(). Khởi tạo và trả về 1 widget trong method build() sẽ giúp hiển thị widget.Material appsĐối với 1 Material app, bạn có thể sử dụng Scaffold widget, widget này hỗ trợ 1 banner mặc định, màu nền page, và có API cho việc thêm drawer, snackbar, bottom sheet… Sau đấy bạn có thể thêm Center widget trực tiếp vào body property để căn giữa nội dung hiển thị trong page.class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
title: ‘Flutter layout demo’,
home: Scaffold(
appBar: AppBar(
title: const Text(‘Flutter layout demo’),
),
body: const Center(
child: Text(‘Hello World’),
),
),
);
}
}

Để mắt: Thư viện Material khai triển những widget dựa theo nguyên lý Material Design. Lúc thiết kế UI của bạn, bạn có thể sử dụng những thư viện widget tiêu chuẩn, hoặc bạn cũng có thể sử dụng widget từ thư viện MaterialNon-Material appsĐối với 1 non-Material app, bạn có thể thêm Center widget vào method build():class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Container(
decoration: const BoxDecoration(color: Colors.white),
child: const Center(
child: Text(
‘Hello World’,
textDirection: TextDirection.ltr,
style: TextStyle(
fontSize: 32,
color: Colors.black87,
),
),
),
);
}
}

Mặc định, non-Material ko bao gồm AppBar, tiêu đề hay màu nền. Nếu bạn muốn những tác dụng này trong non-Material, bạn phải tự làm.Sắp xếp các widget theo chiều ngang và dọcMột trong những layout pattern tầm thường nhất là sắp đặt widget theo chiều dọc và ngang. Bạn có thể sử dụng Row widget để sắp đặt widget theo chiều ngang, và dùng Column để sắp đặt theo chiều dọc.Row và Column là 2 trong số những layout pattern được sử dụng tầm thường nhất.Row và Column cần 1 danh sách các widget con.Mỗi widget con có thể là Row hoặc Column, hoặc 1 widget phức tạp nào khác.Bạn có thân xác định cách Row và Column căn chỉnh widget con của nó, theo cả chiều ngang và dọc.Bạn có thể nới rộng hoặc buộc ràng widget con.Bạn có thân xác định cách những widget con sử dụng khoảng trống có sẵn của Row hoặc ColumnVí dụ sau đây chỉ ra cách 1 Row hoặc Column nằm trong Row hoặc Column.Row và Column là các widget nguyên thủy căn bản cho bố cục ngang và dọc — những widget con cấp thấp này cho phép tùy chỉnh tối đa. Flutter cũng hỗ trợ các widget chuyên biệt, cấp cao hơn có thể đủ cho nhu cầu của bạn. Thí dụ: thay vì Row, bạn có thể thích ListTile, 1 tiện ích dễ sử dụng với các tính chất cho các biểu trưng đầu và cuối, và tối đa 3 dòng văn bản. Thay vì Column, bạn có thể thích ListView, 1 bố cục giống như cột nhưng mà tự động cuộn nếu nội dung của nó quá dài để thích hợp với ko gian có sẵn.Aligning widgets ( căn chỉnh widget)Bạn có thể kiểm soát cách 1 Row hoặc Column căn chỉnh con của nó bằng cách sử dụng các tính chất mainAxisAlignment và crossAxisAlignment. Đối với 1 Row, trục chính chạy theo chiều ngang và trục chéo chạy theo chiều dọc. Đối với 1 Column, trục chính chạy theo chiều dọc và trục chéo chạy theo chiều ngang. Bạn có thể nhìn hình vẽ sau để thông suốt hơn:1 thí dụ khác Row và Column sử dụng với Image:Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset(‘images/pic1.jpg’),
Image.asset(‘images/pic2.jpg’),
Image.asset(‘images/pic3.jpg’),
],
);

Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset(‘images/pic1.jpg’),
Image.asset(‘images/pic2.jpg’),
Image.asset(‘images/pic3.jpg’),
],
);

Sizing widgetsKhi bố cục quá bự để vừa với 1 thiết bị, 1 hình sọc màu vàng và đen sẽ hiện ra dọc theo cạnh bị tác động. Đây là 1 thí dụ về Row quá rộng:Các widget con có thể được định kích tấc để vừa với 1 Row hoặc Column bằng cách sử dụng Expanded widget. Để sửa thí dụ trước trong đấy hàng hình ảnh quá rộng đối với mức hiển thị của nó, hãy bọc mỗi hình ảnh bằng 1 Expanded widget.Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Image.asset(‘images/pic1.jpg’),
),
Expanded(
child: Image.asset(‘images/pic2.jpg’),
),
Expanded(
child: Image.asset(‘images/pic3.jpg’),
),
],
);

Nếu bạn muốn 1 widget chiếm ko gian gấp đôi so với các widget anh chị em của nó. Để làm điều này, hãy sử dụng tính chất flex trong Expanded widget, 1 số nguyên xác định hệ số flex cho widget con. Hệ số flex mặc định là 1. Đoạn mã sau đặt hệ số flex của hình ảnh giữa thành 2:Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Image.asset(‘images/pic1.jpg’),
),
Expanded(
flex: 2,
child: Image.asset(‘images/pic2.jpg’),
),
Expanded(
child: Image.asset(‘images/pic3.jpg’),
),
],
);

Packing widgetsTheo mặc định, 1 Row hoặc Column chiếm càng nhiều ko gian dọc theo trục chính của nó càng tốt, nhưng mà nếu bạn muốn kéo các widget con lại gần nhau, hãy đặt mainAxisSize của nó thành MainAxisSize.min. Thí dụ sau sử dụng tính chất này để đóng gói các hình ngôi sao lại với nhau.Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
const Icon(Icons.star, color: Colors.black),
const Icon(Icons.star, color: Colors.black),
],
)

Nesting rows and columnsLayout framework cho phép bạn lồng các hàng và cột vào bên trong các hàng và cột tùy thích. Hãy xem đoạn code cho phần được phác thảo của bố cục sau:Phần được phác thảo được tiến hành thành 2 hàng. Hàng xếp hạng chứa 5 sao và số lượng bình chọn. Hàng biểu trưng chứa 3 cột biểu trưng và văn bản.Widget tree cho Row chứa 5 sao như sau:Và mã code cho Row chứa 5 sao và số lượng bình chọn như sau:var stars = Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
const Icon(Icons.star, color: Colors.black),
const Icon(Icons.star, color: Colors.black),
],
);

final ratings = Container(
padding: const EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
stars,
const Text(
‘170 Reviews’,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: ‘Roboto’,
letterSpacing: 0.5,
fontSize: 20,
),
),
],
),
);

Để hạn chế sự lầm lẫn trực giác có thể do code các layout lồng nhau nhiều, hãy viết các phần của giao diện người mua trong các biến và hàm.Hàng biểu trưng, bên dưới hàng xếp hạng, có 3 cột, mỗi cột chứa 1 biểu trưng và 2 dòng văn bản, như bạn có thể thấy trong widget tree con của nó:Mã code như sau:const descTextStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: ‘Roboto’,
letterSpacing: 0.5,
fontSize: 18,
height: 2,
);

// DefaultTextStyle.merge() allows you phệ create a default text
// style that is inherited by its child and all subsequent children.
final iconList = DefaultTextStyle.merge(
style: descTextStyle,
child: Container(
padding: const EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
Icon(Icons.kitchen, color: Colors.green[500]),
const Text(‘PREP:’),
const Text(’25 min’),
],
),
Column(
children: [
Icon(Icons.timer, color: Colors.green[500]),
const Text(‘COOK:’),
const Text(‘1 hr’),
],
),
Column(
children: [
Icon(Icons.restaurant, color: Colors.green[500]),
const Text(‘FEEDS:’),
const Text(‘4-6’),
],
),
],
),
),
);

Ta có mã code cho phần hình bên trái như sau:final leftColumn = Container(
padding: const EdgeInsets.fromLTRB(20, 30, 20, 20),
child: Column(
children: [
titleText,
subTitle,
ratings,
iconList,
],
),
);

Mã code cho toàn thể UI của chúng ta như sau:body: Center(
child: Container(
margin: const EdgeInsets.fromLTRB(0, 40, 0, 30),
height: 600,
child: Card(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 440,
child: leftColumn,
),
mainImage,
],
),
),
),
),

Common layout widgets – 1 số widget tầm thường thường gặpStandard widgetsContainer: Có thể thêm padding, margins, borders, background color, hoặc decorations vào a widget.GridView: Tạo widgets dạng lưới có bản lĩnh scroll.ListView: Tạo widgets dạng danh sách có bản lĩnh scroll.Stack: Tạo widget có bản lĩnh đè lên trên các widget khác.Material widgetsCard: Tạo 1 widget hình hộp được bo góc và có đổ bóng.ListTile: Tạo widget với 3 dang text, có leading và trailing icon trong 1 dòng.ContainerRất nhiều layout sử dụng Container, Container dùng để padding, thêm viền, margin… Bạn có thể thay màu nền của thiết bị bằng cách đổi toàn thể layout thành Container và đổi màu nền hoặc ảnh.Tóm lược về ContainerThêm padding, margins, bordersĐổi màu background color hoặc imageBao gồm 1 child widget, nhưng mà child có thể là Row, Column, hoặc thậm chi là root của 1 widget treeExamples (Container)Thí dụ dưới tạo 1 Column với 2 Row, mỗi Row lại gồm 2 hình ảnh. Container được sử dụng để đổi màu của Column thành màu xám.Widget _buildImageColumn() {
return Container(
decoration: const BoxDecoration(
color: Colors.black26,
),
child: Column(
children: [
_buildImageRow(1),
_buildImageRow(3),
],
),
);
}

GridViewSử dụng GridView để sắp đặt các widget dưới dạng danh sách 2 chiều. GridView hỗ trợ 2 danh sách tạo sẵn hoặc bạn có thể tạo lưới tùy chỉnh của riêng mình. Lúc GridView phát hiện thấy nội dung của nó quá dài để vừa với render box, nó sẽ tự động cuộn.Tóm lược (GridView)Đặt các widget trong 1 danh sách dạng lướiPhát hiện lúc nội dung vượt quá render box và tự động hỗ trợ tác dụng cuộnTạo lưới tùy chỉnh của riêng bạn hoặc sử dụng 1 trong các lưới được hỗ trợ:GridView.count cho phép bạn chỉ định số lượng cộtGridView.extent cho phép bạn chỉ định chiều rộng pixel tối đa của 1 ôLưu ý: Lúc hiển thị danh sách 2 chiều, trong đấy điều quan trọng là hàng và cột nhưng mà ô chiếm dùng để chứa dữ liệu, hãy sử dụng Bảng hoặc Bảng dữ liệu.Examples (GridView)Sử dụng GridView.extent để tạo danh Sách lưới với các ô có chiều rộng tối đa là 150 pixel.Sử dụng GridView.count để tạo danh sách dạng lưới với 2 ô ở cơ chế dọc và 3 ô ở cơ chế ngang. Tiêu đề được tạo bằng cách đặt tính chất footer cho mỗi GridTile.Widget _buildGrid() => GridView.extent(
maxCrossAxisExtent: 150,
padding: const EdgeInsets.all(4),
mainAxisSpacing: 4,
crossAxisSpacing: 4,
children: _buildGridTileList(30));

// The images are saved with names pic0.jpg, pic1.jpg…pic29.jpg.
// The List.generate() constructor allows an easy way phệ create
// a list when objects have a predictable naming pattern.
List<Container> _buildGridTileList(int count) => List.generate(
count, (i) => Container(child: Image.asset(‘images/pic$i.jpg’)));

ListViewListView, 1 widget giống như Column, nhưng mà tự có bản lĩnh cuộn lúc nội dung quá dài so với render box của nó.Tóm lược (ListView)1 Column được thiết kế cho việc tổ chức 1 danh sách các hộp, tiệm.Có thể đặt theo chiều dọc hoặc ngang.Phát hiện lúc nội dung ko vừa và tự động cuộn.Ít phải cấu hình hơn Column, nhưng mà dễ sử dụng và trợ ô sin scroll.Examples (ListView)Sử dụng ListView để hiển thị danh sách công tác kinh doanh với ListTiles. 1 thanh ngăn Divider giúp chia tách các rạp phim với danh sách nhà hàngSử dụng ListView để hiện danh sách Colors từ Material Design palette.Widget _buildList() {
return ListView(
children: [
_tile(‘CineArts at the Empire’, ’85 W Portal Ave’, Icons.theaters),
_tile(‘The Castro Theater’, ‘429 Castro St’, Icons.theaters),
_tile(‘Alamo Drafthouse Cinema’, ‘2550 Mission St’, Icons.theaters),
_tile(‘Roxie Theater’, ‘3117 16th St’, Icons.theaters),
_tile(‘United Artists Stonestown Twin’, ‘501 Buckingham Way’,
Icons.theaters),
_tile(‘AMC Metreon 16’, ‘135 4th St #3000’, Icons.theaters),
const Divider(),
_tile(‘K’s Kitchen’, ‘757 Monterey Blvd’, Icons.restaurant),
_tile(‘Emmy’s Restaurant’, ‘1923 Ocean Ave’, Icons.restaurant),
_tile(
‘Chaiya Thai Restaurant’, ‘272 Claremont Blvd’, Icons.restaurant),
_tile(‘La Ciccia’, ‘291 30th St’, Icons.restaurant),
],
);
}

ListTile _tile(String title, String subtitle, IconData icon) {
return ListTile(
title: Text(title,
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20,
)),
subtitle: Text(subtitle),
leading: Icon(
icon,
color: Colors.blue[500],
),
);
}

StackSử dụng Stack để sắp đặt các widget ở phía trên các widget khác – thường là 1 Image. Stack có thể chiếm toàn thể widget phía dưới nó.Tóm lược (Stack)Sử dụng cho việc chổng các widget lên nhau.Widget trước nhất trong danh sách của Stack gọi là widget base, các widget tiếp sau trong danh sách widget sẽ được đặt đè lên trên widget Base.Content của Stack chẳng thể cuộn.Bạn có thể chọn cách giảm bớt các widget con để hiển thị quá render box.Examples (Stack)Sử dụng Stack để đè 1 Container ( Hiện 1 Text với background màu đen trong suốt) lên phía trên của 1 CirlceAvatar. Địa điểm của Text sử dụng alignment property hoặc Alignments widget .Sử dụng ‘Stack` để đè 1 gradient lên phía trên hình ảnh. Gradient này bảo đảm cho việc hiển thị icon của toolbar phân tích rõ với hình ảnh bên dưới.Widget _buildStack() {
return Stack(
alignment: const Alignment(0.6, 0.6),
children: [
const CircleAvatar(
backgroundImage: AssetImage(‘images/pic.jpg’),
radius: 100,
),
Container(
decoration: const BoxDecoration(
color: Colors.black45,
),
child: const Text(
‘Mia B’,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
);
}

CardCard, từ thư viện Material, chứa các thông tin liên can và có thể được tạo từ phần nhiều các widget, nhưng mà thường được sử dụng với ListTile. Card có 1 widget con, nhưng mà widget con của nó có thể là 1 ‘Colum , ‘Row, ListView, GridView hoặc các widget con khác cung ứng list widget. Theo mặc định, 1 Card thu bé kích tấc của nó thành 0 x 0 pixel. Bạn có thể sử dụng SizedBox để giới hạn kích tấc của thẻ.Trong Flutter, Card có các góc bo tròn và bóng đổ, tạo hiệu ứng 3D. Chỉnh sửa tính chất elevation của Card cho phép bạn kiểm soát hiệu ứng đổ bóng. Thí dụ: đặt elevation lên 24, trực giác nâng Card lên khỏi bề mặt và khiến cho bóng trở thành phân tán hơn. Để biết danh sách các trị giá độ cao được cung ứng, hãy xem Elevation trong nguyên tắc Material. Việc chỉ định 1 trị giá ko được cung ứng sẽ vô hiệu hóa hoàn toàn bóng đổ.Tóm lược (Card).Khai triển Material cardĐược sử dụng để thể hiện các thông tin liên quanChấp nhận 1 widget con, nhưng mà phần tử đấy có thể là Colum, Row, ListView, GridView hoặc các widget con khác cung ứng list widgetĐược hiển thị với các góc bo tròn và bóng đổNội dung của Card chẳng thể cuộnTừ thư viện MaterialExamples (Card)1 Card bao gồm 3 ListTiles và giới hạn kích tấc bằng các bọc trong 1 SizedBox. 1 thanh ngăn Divider giúp phân tích 2 ListTiles với nhau.1 Card bao gồm hình ảnh và text.Widget _buildCard() {
return SizedBox(
height: 210,
child: Card(
child: Column(
children: [
ListTile(
title: const Text(
‘1625 Main Street’,
style: TextStyle(fontWeight: FontWeight.w500),
),
subtitle: const Text(‘My City, CA 99984’),
leading: Icon(
Icons.restaurant_menu,
color: Colors.blue[500],
),
),
const Divider(),
ListTile(
title: const Text(
‘(408) 555-1212’,
style: TextStyle(fontWeight: FontWeight.w500),
),
leading: Icon(
Icons.contact_phone,
color: Colors.blue[500],
),
),
ListTile(
title: const Text(‘costa@example.com’),
leading: Icon(
Icons.contact_mail,
color: Colors.blue[500],
),
),
],
),
),
);
}

ListTileSử dụng ListTile, 1 widget giống Row từ thư viện Material, để dễ ợt tạo 1 hàng chứa tối đa 3 dòng văn bản và các biểu trưng đầu và cuối tùy chọn. ListTile được sử dụng tầm thường nhất trong Card hoặc ListView, nhưng mà có thể được sử dụng ở những nơi khác.Tóm lược (ListTile)1 widget giống Row chứa tối đa 3 dòng văn bản và các biểu trưng tùy chọnÍt cấu hình hơn Row, nhưng mà dễ sử dụng hơnTừ thư viện MaterialExamples (ListTile)1 Card bao gồm 3 ListTiles.Sử dụng ListTile để tạo danh sách gồm 3 button dạng dropdown.Tổng kếtTrên đây mình đã giới thiệu với các bạn các widget căn bản trong Flutter, cách tạo và sử dụng, liên kết các widget dễ dãi để hình thành những widget phức tạp hơn. Kì vọng các bạn có thể hiểu và nắm được 1 cách tổng quan nhất về layout widget, thành phần hình thành UI của Flutter nhé!Tham khảoBài viết có tham khảo từ https://docs.flutter.dev/
#Layouts #trong #Flutter14 #tháng #lượt #xem #động #Flutter #Đầu #mục #bài #viếtBài #viết #liên #quanKhoá #học #hay
[rule_2_plain] #Layouts #trong #Flutter14 #tháng #lượt #xem #động #Flutter #Đầu #mục #bài #viếtBài #viết #liên #quanKhoá #học #hay
[rule_2_plain] #Layouts #trong #Flutter14 #tháng #lượt #xem #động #Flutter #Đầu #mục #bài #viếtBài #viết #liên #quanKhoá #học #hay
[rule_3_plain]

#Layouts #trong #Flutter14 #tháng #lượt #xem #động #Flutter #Đầu #mục #bài #viếtBài #viết #liên #quanKhoá #học #hay
Tiêu chí của bài viếtNắm được những widget ( những class) được sử dụng để tạo UI.Widget được sử dụng cho cả layout và thành phần UI.Liên kết những widget dễ dãi để xây dựng những widget phức tạp.Giới thiệuCơ chế mấu chốt để xây dựng nên layout trong Flutter là Widget. Trong Flutter, hầu như tất cả mọi thứ đều là Widget – thậm chí là model layout cũng là Widget. Ảnh, icon, text bạn thấy trong 1 phần mềm Flutter tất cả đều là widget. Nhưng mà những thứ bạn ko thấy cũng là widget, thí dụ như rows, columns, và grid,… những widget này tạo điều kiện cho việc sắp đặt, buộc ràng, căn chỉnh những visible widget (những widget nhưng mà bạn thấy nhìn là thấy). ( Từ đây mình sẽ gọi widget nhận ra được – visible widget, và widget ko nhận ra được – invisible widget; để các bạn có thể tiện theo dõi).Bạn có thể tạo layout bằng cách liên kết những widget với nhau để hình thành những widget phức tạp hơn. Thí dụ dưới đây tạo ra 3 icon với nhãn dán nằm dưới:Dưới đây là diagram của widget tree cho UI trên:Hầu như mọi thứ bạn thấy trên ảnh có vẻ giống như bạn tưởng tượng đúng ko? Nhưng mà bạn thử chú ý về những hình Container ( màu hồng trong ảnh) xem. Container là 1 widget class cho phép bạn có thể tùy chỉnh widget con bên trong nó. Sử dụng Container lúc bạn muốn thêm padding, margin, border, màu nền…Trong thí dụ này, mỗi Text widget được đặt bên trong 1 Container để chúng ta có thể thêm margin, cách 1 khoảng so với Icon phía trên nó. Toàn thể Row được đặt trong Container để thêm padding bao quanh Row.Phần còn lại của UI trong thí dụ này được điều khiển bằng properties. Thí dụ: Chỉnh sửa màu Icon bằng cách sử dụng color property, sử dụng Text.style property để tạo Font chữ, màu, độ đậm nhạt… Column và row có những property cho phép bạn xác định cách những widget con được căn chỉnh dọc hay ngang, hay xác định độ giãn cách giữa các widget con này.Sắp xếp 1 WidgetLàm thế nào để sắp đặt 1 widget trong Flutter? Bài viết này sẽ chỉ ra cách bạn có thể tạo và hiển thị 1 widget dễ dãi và chúng ta sẽ cùng nhau code 1 thí dụ Hello world dễ dãi nhất nhé!Trong Flutter, chúng ta sẽ mất 1 vài bước để đặt text, icon, hoặc Image vào màn hình.1. Cách tuyển lựa layout widgetViệc tuyển lựa layout widget từ 1 tập rất nhiều layout widget ngày nay dựa trên cách nhưng mà bạn muốn căn chỉnh hay buộc ràng visible widget, vì những đặc điểm này thường được chuyển cho widget con.Thí dụ ta sử dụng widget Center trong trường hợp muốn căn giữa content trong nó theo cả chiều dọc và chiều ngang.2. Tạo 1 visible widgetVí dụ, để tạo 1 Text widget:Text(‘Hello World’),
Tạo 1 Image widget:Image.asset(
‘images/lake.jpg’,
fit: BoxFit.cover,
),
Tạo 1 Icon widget:Icon(
Icons.star,
color: Colors.red[500],
),

3. Thêm visible widget vào layout widgetTất cả những layout widget đều có những thứ sau:1 tính chất (property) child nếu nó cần 1 widget con, thí dụ: Center, Container,1 tính chất (property) children nếu nó cần 1 tập danh sách các widget con, thí dụ: Row, Column, ListView, Stack,…Thêm Text widget vào Center widget:const Center(
child: Text(‘Hello World’),
),

4. Thêm layout widget vào trong trang (page) UIBản thân 1 app Flutter cũng là 1 widget, và hầu như đều có method build(). Khởi tạo và trả về 1 widget trong method build() sẽ giúp hiển thị widget.Material appsĐối với 1 Material app, bạn có thể sử dụng Scaffold widget, widget này hỗ trợ 1 banner mặc định, màu nền page, và có API cho việc thêm drawer, snackbar, bottom sheet… Sau đấy bạn có thể thêm Center widget trực tiếp vào body property để căn giữa nội dung hiển thị trong page.class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
title: ‘Flutter layout demo’,
home: Scaffold(
appBar: AppBar(
title: const Text(‘Flutter layout demo’),
),
body: const Center(
child: Text(‘Hello World’),
),
),
);
}
}

Để mắt: Thư viện Material khai triển những widget dựa theo nguyên lý Material Design. Lúc thiết kế UI của bạn, bạn có thể sử dụng những thư viện widget tiêu chuẩn, hoặc bạn cũng có thể sử dụng widget từ thư viện MaterialNon-Material appsĐối với 1 non-Material app, bạn có thể thêm Center widget vào method build():class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Container(
decoration: const BoxDecoration(color: Colors.white),
child: const Center(
child: Text(
‘Hello World’,
textDirection: TextDirection.ltr,
style: TextStyle(
fontSize: 32,
color: Colors.black87,
),
),
),
);
}
}

Mặc định, non-Material ko bao gồm AppBar, tiêu đề hay màu nền. Nếu bạn muốn những tác dụng này trong non-Material, bạn phải tự làm.Sắp xếp các widget theo chiều ngang và dọcMột trong những layout pattern tầm thường nhất là sắp đặt widget theo chiều dọc và ngang. Bạn có thể sử dụng Row widget để sắp đặt widget theo chiều ngang, và dùng Column để sắp đặt theo chiều dọc.Row và Column là 2 trong số những layout pattern được sử dụng tầm thường nhất.Row và Column cần 1 danh sách các widget con.Mỗi widget con có thể là Row hoặc Column, hoặc 1 widget phức tạp nào khác.Bạn có thân xác định cách Row và Column căn chỉnh widget con của nó, theo cả chiều ngang và dọc.Bạn có thể nới rộng hoặc buộc ràng widget con.Bạn có thân xác định cách những widget con sử dụng khoảng trống có sẵn của Row hoặc ColumnVí dụ sau đây chỉ ra cách 1 Row hoặc Column nằm trong Row hoặc Column.Row và Column là các widget nguyên thủy căn bản cho bố cục ngang và dọc — những widget con cấp thấp này cho phép tùy chỉnh tối đa. Flutter cũng hỗ trợ các widget chuyên biệt, cấp cao hơn có thể đủ cho nhu cầu của bạn. Thí dụ: thay vì Row, bạn có thể thích ListTile, 1 tiện ích dễ sử dụng với các tính chất cho các biểu trưng đầu và cuối, và tối đa 3 dòng văn bản. Thay vì Column, bạn có thể thích ListView, 1 bố cục giống như cột nhưng mà tự động cuộn nếu nội dung của nó quá dài để thích hợp với ko gian có sẵn.Aligning widgets ( căn chỉnh widget)Bạn có thể kiểm soát cách 1 Row hoặc Column căn chỉnh con của nó bằng cách sử dụng các tính chất mainAxisAlignment và crossAxisAlignment. Đối với 1 Row, trục chính chạy theo chiều ngang và trục chéo chạy theo chiều dọc. Đối với 1 Column, trục chính chạy theo chiều dọc và trục chéo chạy theo chiều ngang. Bạn có thể nhìn hình vẽ sau để thông suốt hơn:1 thí dụ khác Row và Column sử dụng với Image:Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset(‘images/pic1.jpg’),
Image.asset(‘images/pic2.jpg’),
Image.asset(‘images/pic3.jpg’),
],
);

Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset(‘images/pic1.jpg’),
Image.asset(‘images/pic2.jpg’),
Image.asset(‘images/pic3.jpg’),
],
);

Sizing widgetsKhi bố cục quá bự để vừa với 1 thiết bị, 1 hình sọc màu vàng và đen sẽ hiện ra dọc theo cạnh bị tác động. Đây là 1 thí dụ về Row quá rộng:Các widget con có thể được định kích tấc để vừa với 1 Row hoặc Column bằng cách sử dụng Expanded widget. Để sửa thí dụ trước trong đấy hàng hình ảnh quá rộng đối với mức hiển thị của nó, hãy bọc mỗi hình ảnh bằng 1 Expanded widget.Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Image.asset(‘images/pic1.jpg’),
),
Expanded(
child: Image.asset(‘images/pic2.jpg’),
),
Expanded(
child: Image.asset(‘images/pic3.jpg’),
),
],
);

Nếu bạn muốn 1 widget chiếm ko gian gấp đôi so với các widget anh chị em của nó. Để làm điều này, hãy sử dụng tính chất flex trong Expanded widget, 1 số nguyên xác định hệ số flex cho widget con. Hệ số flex mặc định là 1. Đoạn mã sau đặt hệ số flex của hình ảnh giữa thành 2:Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Image.asset(‘images/pic1.jpg’),
),
Expanded(
flex: 2,
child: Image.asset(‘images/pic2.jpg’),
),
Expanded(
child: Image.asset(‘images/pic3.jpg’),
),
],
);

Packing widgetsTheo mặc định, 1 Row hoặc Column chiếm càng nhiều ko gian dọc theo trục chính của nó càng tốt, nhưng mà nếu bạn muốn kéo các widget con lại gần nhau, hãy đặt mainAxisSize của nó thành MainAxisSize.min. Thí dụ sau sử dụng tính chất này để đóng gói các hình ngôi sao lại với nhau.Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
const Icon(Icons.star, color: Colors.black),
const Icon(Icons.star, color: Colors.black),
],
)

Nesting rows and columnsLayout framework cho phép bạn lồng các hàng và cột vào bên trong các hàng và cột tùy thích. Hãy xem đoạn code cho phần được phác thảo của bố cục sau:Phần được phác thảo được tiến hành thành 2 hàng. Hàng xếp hạng chứa 5 sao và số lượng bình chọn. Hàng biểu trưng chứa 3 cột biểu trưng và văn bản.Widget tree cho Row chứa 5 sao như sau:Và mã code cho Row chứa 5 sao và số lượng bình chọn như sau:var stars = Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
const Icon(Icons.star, color: Colors.black),
const Icon(Icons.star, color: Colors.black),
],
);

final ratings = Container(
padding: const EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
stars,
const Text(
‘170 Reviews’,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: ‘Roboto’,
letterSpacing: 0.5,
fontSize: 20,
),
),
],
),
);

Để hạn chế sự lầm lẫn trực giác có thể do code các layout lồng nhau nhiều, hãy viết các phần của giao diện người mua trong các biến và hàm.Hàng biểu trưng, bên dưới hàng xếp hạng, có 3 cột, mỗi cột chứa 1 biểu trưng và 2 dòng văn bản, như bạn có thể thấy trong widget tree con của nó:Mã code như sau:const descTextStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: ‘Roboto’,
letterSpacing: 0.5,
fontSize: 18,
height: 2,
);

// DefaultTextStyle.merge() allows you phệ create a default text
// style that is inherited by its child and all subsequent children.
final iconList = DefaultTextStyle.merge(
style: descTextStyle,
child: Container(
padding: const EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
Icon(Icons.kitchen, color: Colors.green[500]),
const Text(‘PREP:’),
const Text(’25 min’),
],
),
Column(
children: [
Icon(Icons.timer, color: Colors.green[500]),
const Text(‘COOK:’),
const Text(‘1 hr’),
],
),
Column(
children: [
Icon(Icons.restaurant, color: Colors.green[500]),
const Text(‘FEEDS:’),
const Text(‘4-6’),
],
),
],
),
),
);

Ta có mã code cho phần hình bên trái như sau:final leftColumn = Container(
padding: const EdgeInsets.fromLTRB(20, 30, 20, 20),
child: Column(
children: [
titleText,
subTitle,
ratings,
iconList,
],
),
);

Mã code cho toàn thể UI của chúng ta như sau:body: Center(
child: Container(
margin: const EdgeInsets.fromLTRB(0, 40, 0, 30),
height: 600,
child: Card(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 440,
child: leftColumn,
),
mainImage,
],
),
),
),
),

Common layout widgets – 1 số widget tầm thường thường gặpStandard widgetsContainer: Có thể thêm padding, margins, borders, background color, hoặc decorations vào a widget.GridView: Tạo widgets dạng lưới có bản lĩnh scroll.ListView: Tạo widgets dạng danh sách có bản lĩnh scroll.Stack: Tạo widget có bản lĩnh đè lên trên các widget khác.Material widgetsCard: Tạo 1 widget hình hộp được bo góc và có đổ bóng.ListTile: Tạo widget với 3 dang text, có leading và trailing icon trong 1 dòng.ContainerRất nhiều layout sử dụng Container, Container dùng để padding, thêm viền, margin… Bạn có thể thay màu nền của thiết bị bằng cách đổi toàn thể layout thành Container và đổi màu nền hoặc ảnh.Tóm lược về ContainerThêm padding, margins, bordersĐổi màu background color hoặc imageBao gồm 1 child widget, nhưng mà child có thể là Row, Column, hoặc thậm chi là root của 1 widget treeExamples (Container)Thí dụ dưới tạo 1 Column với 2 Row, mỗi Row lại gồm 2 hình ảnh. Container được sử dụng để đổi màu của Column thành màu xám.Widget _buildImageColumn() {
return Container(
decoration: const BoxDecoration(
color: Colors.black26,
),
child: Column(
children: [
_buildImageRow(1),
_buildImageRow(3),
],
),
);
}

GridViewSử dụng GridView để sắp đặt các widget dưới dạng danh sách 2 chiều. GridView hỗ trợ 2 danh sách tạo sẵn hoặc bạn có thể tạo lưới tùy chỉnh của riêng mình. Lúc GridView phát hiện thấy nội dung của nó quá dài để vừa với render box, nó sẽ tự động cuộn.Tóm lược (GridView)Đặt các widget trong 1 danh sách dạng lướiPhát hiện lúc nội dung vượt quá render box và tự động hỗ trợ tác dụng cuộnTạo lưới tùy chỉnh của riêng bạn hoặc sử dụng 1 trong các lưới được hỗ trợ:GridView.count cho phép bạn chỉ định số lượng cộtGridView.extent cho phép bạn chỉ định chiều rộng pixel tối đa của 1 ôLưu ý: Lúc hiển thị danh sách 2 chiều, trong đấy điều quan trọng là hàng và cột nhưng mà ô chiếm dùng để chứa dữ liệu, hãy sử dụng Bảng hoặc Bảng dữ liệu.Examples (GridView)Sử dụng GridView.extent để tạo danh Sách lưới với các ô có chiều rộng tối đa là 150 pixel.Sử dụng GridView.count để tạo danh sách dạng lưới với 2 ô ở cơ chế dọc và 3 ô ở cơ chế ngang. Tiêu đề được tạo bằng cách đặt tính chất footer cho mỗi GridTile.Widget _buildGrid() => GridView.extent(
maxCrossAxisExtent: 150,
padding: const EdgeInsets.all(4),
mainAxisSpacing: 4,
crossAxisSpacing: 4,
children: _buildGridTileList(30));

// The images are saved with names pic0.jpg, pic1.jpg…pic29.jpg.
// The List.generate() constructor allows an easy way phệ create
// a list when objects have a predictable naming pattern.
List<Container> _buildGridTileList(int count) => List.generate(
count, (i) => Container(child: Image.asset(‘images/pic$i.jpg’)));

ListViewListView, 1 widget giống như Column, nhưng mà tự có bản lĩnh cuộn lúc nội dung quá dài so với render box của nó.Tóm lược (ListView)1 Column được thiết kế cho việc tổ chức 1 danh sách các hộp, tiệm.Có thể đặt theo chiều dọc hoặc ngang.Phát hiện lúc nội dung ko vừa và tự động cuộn.Ít phải cấu hình hơn Column, nhưng mà dễ sử dụng và trợ ô sin scroll.Examples (ListView)Sử dụng ListView để hiển thị danh sách công tác kinh doanh với ListTiles. 1 thanh ngăn Divider giúp chia tách các rạp phim với danh sách nhà hàngSử dụng ListView để hiện danh sách Colors từ Material Design palette.Widget _buildList() {
return ListView(
children: [
_tile(‘CineArts at the Empire’, ’85 W Portal Ave’, Icons.theaters),
_tile(‘The Castro Theater’, ‘429 Castro St’, Icons.theaters),
_tile(‘Alamo Drafthouse Cinema’, ‘2550 Mission St’, Icons.theaters),
_tile(‘Roxie Theater’, ‘3117 16th St’, Icons.theaters),
_tile(‘United Artists Stonestown Twin’, ‘501 Buckingham Way’,
Icons.theaters),
_tile(‘AMC Metreon 16’, ‘135 4th St #3000’, Icons.theaters),
const Divider(),
_tile(‘K’s Kitchen’, ‘757 Monterey Blvd’, Icons.restaurant),
_tile(‘Emmy’s Restaurant’, ‘1923 Ocean Ave’, Icons.restaurant),
_tile(
‘Chaiya Thai Restaurant’, ‘272 Claremont Blvd’, Icons.restaurant),
_tile(‘La Ciccia’, ‘291 30th St’, Icons.restaurant),
],
);
}

ListTile _tile(String title, String subtitle, IconData icon) {
return ListTile(
title: Text(title,
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20,
)),
subtitle: Text(subtitle),
leading: Icon(
icon,
color: Colors.blue[500],
),
);
}

StackSử dụng Stack để sắp đặt các widget ở phía trên các widget khác – thường là 1 Image. Stack có thể chiếm toàn thể widget phía dưới nó.Tóm lược (Stack)Sử dụng cho việc chổng các widget lên nhau.Widget trước nhất trong danh sách của Stack gọi là widget base, các widget tiếp sau trong danh sách widget sẽ được đặt đè lên trên widget Base.Content của Stack chẳng thể cuộn.Bạn có thể chọn cách giảm bớt các widget con để hiển thị quá render box.Examples (Stack)Sử dụng Stack để đè 1 Container ( Hiện 1 Text với background màu đen trong suốt) lên phía trên của 1 CirlceAvatar. Địa điểm của Text sử dụng alignment property hoặc Alignments widget .Sử dụng ‘Stack` để đè 1 gradient lên phía trên hình ảnh. Gradient này bảo đảm cho việc hiển thị icon của toolbar phân tích rõ với hình ảnh bên dưới.Widget _buildStack() {
return Stack(
alignment: const Alignment(0.6, 0.6),
children: [
const CircleAvatar(
backgroundImage: AssetImage(‘images/pic.jpg’),
radius: 100,
),
Container(
decoration: const BoxDecoration(
color: Colors.black45,
),
child: const Text(
‘Mia B’,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
);
}

CardCard, từ thư viện Material, chứa các thông tin liên can và có thể được tạo từ phần nhiều các widget, nhưng mà thường được sử dụng với ListTile. Card có 1 widget con, nhưng mà widget con của nó có thể là 1 ‘Colum , ‘Row, ListView, GridView hoặc các widget con khác cung ứng list widget. Theo mặc định, 1 Card thu bé kích tấc của nó thành 0 x 0 pixel. Bạn có thể sử dụng SizedBox để giới hạn kích tấc của thẻ.Trong Flutter, Card có các góc bo tròn và bóng đổ, tạo hiệu ứng 3D. Chỉnh sửa tính chất elevation của Card cho phép bạn kiểm soát hiệu ứng đổ bóng. Thí dụ: đặt elevation lên 24, trực giác nâng Card lên khỏi bề mặt và khiến cho bóng trở thành phân tán hơn. Để biết danh sách các trị giá độ cao được cung ứng, hãy xem Elevation trong nguyên tắc Material. Việc chỉ định 1 trị giá ko được cung ứng sẽ vô hiệu hóa hoàn toàn bóng đổ.Tóm lược (Card).Khai triển Material cardĐược sử dụng để thể hiện các thông tin liên quanChấp nhận 1 widget con, nhưng mà phần tử đấy có thể là Colum, Row, ListView, GridView hoặc các widget con khác cung ứng list widgetĐược hiển thị với các góc bo tròn và bóng đổNội dung của Card chẳng thể cuộnTừ thư viện MaterialExamples (Card)1 Card bao gồm 3 ListTiles và giới hạn kích tấc bằng các bọc trong 1 SizedBox. 1 thanh ngăn Divider giúp phân tích 2 ListTiles với nhau.1 Card bao gồm hình ảnh và text.Widget _buildCard() {
return SizedBox(
height: 210,
child: Card(
child: Column(
children: [
ListTile(
title: const Text(
‘1625 Main Street’,
style: TextStyle(fontWeight: FontWeight.w500),
),
subtitle: const Text(‘My City, CA 99984’),
leading: Icon(
Icons.restaurant_menu,
color: Colors.blue[500],
),
),
const Divider(),
ListTile(
title: const Text(
‘(408) 555-1212’,
style: TextStyle(fontWeight: FontWeight.w500),
),
leading: Icon(
Icons.contact_phone,
color: Colors.blue[500],
),
),
ListTile(
title: const Text(‘costa@example.com’),
leading: Icon(
Icons.contact_mail,
color: Colors.blue[500],
),
),
],
),
),
);
}

ListTileSử dụng ListTile, 1 widget giống Row từ thư viện Material, để dễ ợt tạo 1 hàng chứa tối đa 3 dòng văn bản và các biểu trưng đầu và cuối tùy chọn. ListTile được sử dụng tầm thường nhất trong Card hoặc ListView, nhưng mà có thể được sử dụng ở những nơi khác.Tóm lược (ListTile)1 widget giống Row chứa tối đa 3 dòng văn bản và các biểu trưng tùy chọnÍt cấu hình hơn Row, nhưng mà dễ sử dụng hơnTừ thư viện MaterialExamples (ListTile)1 Card bao gồm 3 ListTiles.Sử dụng ListTile để tạo danh sách gồm 3 button dạng dropdown.Tổng kếtTrên đây mình đã giới thiệu với các bạn các widget căn bản trong Flutter, cách tạo và sử dụng, liên kết các widget dễ dãi để hình thành những widget phức tạp hơn. Kì vọng các bạn có thể hiểu và nắm được 1 cách tổng quan nhất về layout widget, thành phần hình thành UI của Flutter nhé!Tham khảoBài viết có tham khảo từ https://docs.flutter.dev/

Related Articles

Trả lời

Email của bạn sẽ không được hiển thị công khai.

Back to top button