Expanded: nó là gì và cách hoạt động trong Flutter

Tác giả: IT Sectr Đã đăng: 2026-07-03 Thời gian đọc: 6 phút

Expanded là một widget Flutter buộc phần tử con lấp đầy tất cả không gian có sẵn trong một container Flex. Khi Row hoặc Column phân phối không gian giữa các phần tử con, Expanded lấy không gian trống sau khi tính đến các phần tử không linh hoạt. Theo tài liệu chính thức của Flutter (2026), Expanded là một trong những widget bố cục được sử dụng nhiều nhất: nó được áp dụng trong các giao diện dựa trên tỷ lệ phần trăm, xây dựng thẻ, danh sách và bảng điều khiển. Ưu điểm chính của nó là tự động tính toán chiều rộng hoặc chiều cao dựa trên hệ số flex mà không cần chỉ định kích thước một cách rõ ràng.

Những điểm chính

  • Expanded là một widget bố cục mở rộng phần tử con để lấp đầy tất cả không gian có sẵn trong Row, Column hoặc Flex
  • Hệ số flex xác định phần không gian trống mà mỗi Expanded nhận được
  • Expanded khác với Flexible ở chỗ nó buộc phải lấp đầy tất cả không gian có sẵn
  • Stack không hỗ trợ Expanded, chỉ có Row, Column và Flex
  • Lỗi khi sử dụng Expanded bên ngoài container Flex gây ra LayoutException

Expanded là gì

Expanded là một widget bao bọc lấy một phần tử con và buộc nó mở rộng để lấp đầy không gian có sẵn trong container Flex (Row, Column, Flex). Expanded không có biểu diễn trực quan riêng — nó chỉ quản lý các ràng buộc (constraints) được truyền cho phần tử con.

Cốt lõi của Expanded là cơ chế Flex do framework Flutter cung cấp. Khi Row hoặc Column tính toán kích thước của các phần tử con, trước tiên chúng phân bổ không gian cho các phần tử không linh hoạt (widget thông thường có kích thước cố định), sau đó phân phối không gian còn lại giữa các phần tử con Expanded và Flexible theo tỷ lệ với hệ số flex của chúng.

Expanded sử dụng Flexible.fit = FlexFit.tight. Điều này có nghĩa là phần tử con của Expanded phải chiếm tất cả không gian được phân bổ, ngay cả khi kích thước riêng của nó nhỏ hơn. Không giống như Flexible với Fit.loose, nơi phần tử con có thể nhỏ hơn vùng được phân bổ, Expanded buộc phải mở rộng nội dung.

Tóm lại: Expanded là công cụ chính để tạo bố cục tỷ lệ trong Flutter. Sử dụng nó khi bạn cần một phần tử đảm bảo lấp đầy tất cả chiều rộng hoặc chiều cao có sẵn.

Expanded vs Flexible: khác biệt chính

ExpandedFlexible đều phân phối không gian trong container Flex, nhưng hoạt động khác nhau về cơ bản. Sự khác biệt nằm ở thuộc tính fit, xác định liệu phần tử con có thể nhỏ hơn không gian có sẵn hay không.

Expanded có mô hình hành vi nghiêm ngặt: fit của nó bằng FlexFit.tight. Điều này có nghĩa là widget con nhận được các ràng buộc bằng với không gian có sẵn — không hơn, không kém. Nếu phần tử con nhỏ hơn, nó sẽ được kéo dãn. Nếu lớn hơn, nó sẽ co lại. Flexible sử dụng FlexFit.loose, cho phép phần tử con có bất kỳ kích thước nào trong không gian được phân bổ.

Trong thực tế: nếu một Row chứa hai Expanded với flex=1, mỗi cái sẽ chiếm chính xác một nửa chiều rộng. Nếu bạn thay thế chúng bằng Flexible với fit.loose, mỗi phần tử con có thể nhỏ hơn một nửa nếu kích thước riêng của nó nhỏ hơn — không gian còn lại sẽ trống.

Tóm lại: sử dụng Expanded cho bố cục tỷ lệ nghiêm ngặt, Flexible khi phần tử con có thể nhỏ hơn không gian có sẵn. Nếu không chắc chắn — hãy bắt đầu với Expanded, nó mang lại hành vi dễ dự đoán hơn.

Hệ số flex: cách không gian được phân bổ

Hệ số flex (tham số flex) là một giá trị số xác định phần không gian có sẵn mà một Expanded sẽ nhận được. Mặc định flex=1, có nghĩa là phân phối đồng đều giữa tất cả các phần tử con Expanded.

Thuật toán phân phối hoạt động theo ba bước. Đầu tiên: Flutter tính toán kích thước nội tại của tất cả các phần tử con không linh hoạt. Thứ hai: không gian còn lại được chia cho tổng của tất cả các hệ số flex. Thứ ba: mỗi Expanded nhận được một phần bằng hệ số flex của nó nhân với kích thước của một đơn vị flex.

Ví dụ: một Row rộng 300px chứa hai Expanded: cái đầu tiên với flex=2, cái thứ hai với flex=1. Không gian trống (300px trừ các phần tử con không linh hoạt) được chia thành 3 phần. Cái đầu tiên nhận 2/3, cái thứ hai nhận 1/3. Nếu không có phần tử con không linh hoạt, cái đầu tiên nhận 200px, cái thứ hai nhận 100px.

Hệ số flex có thể là bất kỳ số nguyên dương nào. Giá trị 0 là một trường hợp đặc biệt: Expanded với flex=0 hoạt động như một widget không linh hoạt thông thường, chiếm không gian tối thiểu theo kích thước của phần tử con. Hành vi này tương đương với việc không có Expanded.

Tóm lại: hệ số flex là chìa khóa để xây dựng bố cục linh hoạt. Sử dụng tỷ lệ 1:1 cho các cột bằng nhau, 2:1 cho bảng điều khiển có vùng chính và vùng bên, 3:1 cho giao diện có điều hướng hẹp.

Ví dụ mã với Expanded

Ví dụ 1 minh họa cách sử dụng cơ bản của Expanded trong Row để tạo ba cột bằng nhau.

dart
Row(
  children: [
    Expanded(
      child: Container(
        color: Colors.red,
      ),
    ),
    Expanded(
      child: Container(
        color: Colors.green,
      ),
    ),
    Expanded(
      child: Container(
        color: Colors.blue,
      ),
    ),
  ],
)

Trong ví dụ này, ba Expanded với flex=1 (mặc định) chia đều chiều rộng của Row. Các container mở rộng đến toàn bộ chiều cao do Row đặt và chiếm các phần bằng nhau. Cách tiếp cận này thuận tiện cho việc tạo bố cục dựa trên cột với phân phối tỷ lệ.

Ví dụ 2 cho thấy cách sử dụng các hệ số flex khác nhau để tạo bố cục với thanh bên và nội dung chính.

dart
Row(
  children: [
    Expanded(
      flex: 1,
      child: Container(
        color: Colors.grey.200,
        child: const Center(
          child: Text('Thanh bên'),
        ),
      ),
    ),
    Expanded(
      flex: 3,
      child: Container(
        color: Colors.white,
        child: const Center(
          child: Text('Vùng nội dung'),
        ),
      ),
    ),
  ],
)

Ví dụ thứ hai tạo một bố cục điển hình với thanh bên (25%) và vùng nội dung chính (75%). flex=1 và flex=3 cho tỷ lệ 1:3. Khi chiều rộng màn hình thay đổi, tỷ lệ được giữ nguyên tự động — đây là nền tảng của giao diện thích ứng.

Tóm lại: Expanded với các hệ số flex khác nhau là một công cụ tiêu chuẩn để xây dựng bố cục thích ứng. Sự kết hợp của Expanded trong Column cho phép tạo cả bố trí tỷ lệ ngang và dọc.

Lỗi thường gặp khi sử dụng Expanded

Lỗi 1: sử dụng Expanded bên ngoài Row, Column hoặc Flex. Nếu bạn đặt Expanded trực tiếp trong Stack, ListView hoặc container không phải Flex khác, Flutter sẽ ném LayoutException với thông báo "Expanded widgets must be placed inside Flex widgets". Giải pháp: kiểm tra widget cha — chỉ Row, Column hoặc Flex.

Lỗi 2: đặt Expanded bên trong ListView mà không chỉ định shrinkWrap. ListView theo mặc định có chiều cao vô hạn theo hướng cuộn và Expanded không thể tính toán phần của nó. Giải pháp: sử dụng shrinkWrap: true hoặc bọc ListView trong một SizedBox với chiều cao cố định.

Lỗi 3: nhiều Expanded với tổng flex vượt quá không gian có sẵn. Nếu một Row có chiều rộng giới hạn chứa Expanded cũng như các widget có kích thước nội tại lớn, có thể xảy ra tràn. Giải pháp: kiểm tra kích thước tối thiểu của các phần tử con không linh hoạt và sử dụng FittedBox hoặc Flex fit nếu cần.

Lỗi 4: Expanded lồng nhau trong Column bên trong Row. Nếu một Expanded bên trong Column chứa một Expanded khác bên trong Row, có thể xảy ra xung đột ràng buộc. Giải pháp: giới hạn độ sâu lồng ghép hoặc sử dụng ConstrainedBox để đặt kích thước rõ ràng ở các cấp trung gian.

Tóm lại: Expanded yêu cầu ngữ cảnh cha chính xác. Luôn kiểm tra rằng Expanded được đặt trực tiếp trong Row, Column hoặc Flex và tránh lồng ghép mà không có kích thước rõ ràng.

Câu hỏi thường gặp

Expanded khác SizedBox.expand như thế nào?

SizedBox.expand buộc phần tử con mở rộng đến kích thước do các ràng buộc bên ngoài đặt ra, nhưng không tham gia vào phân phối flex. Expanded chỉ hoạt động bên trong container Flex và xem xét hệ số flex khi phân phối không gian trống giữa các phần tử con.

Có thể sử dụng Expanded bên trong Stack không?

Không. Stack không phải là container Flex và việc sử dụng Expanded bên trong nó sẽ gây ra LayoutException. Để mở rộng phần tử con trong Stack, hãy sử dụng Positioned.fill hoặc BoxConstraints.expand.

Điều gì xảy ra nếu không chỉ định hệ số flex?

Mặc định flex=1. Tất cả Expanded không có flex rõ ràng nhận được các phần bằng nhau của không gian trống. Nếu một Row có ba Expanded không có flex, mỗi cái chiếm chính xác một phần ba không gian có sẵn.

Làm thế nào để Expanded chỉ theo chiều rộng mà không theo chiều cao?

Đặt Expanded trong một Row để kéo dãn theo chiều ngang. Để kéo dãn theo chiều dọc, sử dụng Expanded bên trong Column. Nếu cần giới hạn kích thước, hãy bọc Expanded hoặc phần tử con của nó trong SizedBox.

Expanded có hoạt động với Wrap hoặc widget Flex không?

Expanded hoạt động với Flex, bao gồm Row và Column như các lớp con của nó. Wrap không phải là container Flex và không hỗ trợ Expanded. Để phân phối không gian trong Wrap, hãy sử dụng các phương pháp khác như RunAlignment.

Tổng kết

  • Expanded là widget để buộc mở rộng phần tử con nhằm lấp đầy tất cả không gian có sẵn trong container Flex
  • Hệ số flex xác định tỷ lệ phân phối không gian trống giữa nhiều Expanded
  • Khác biệt với Flexible: Expanded sử dụng tight fit (lấp đầy bắt buộc), Flexible sử dụng loose fit (tùy chọn)
  • Lỗi khi đặt Expanded bên ngoài Row, Column hoặc Flex gây ra LayoutException
  • Thích ứng: tỷ lệ bố cục được giữ nguyên tự động khi thay đổi kích thước màn hình
  • Khuyến nghị: sử dụng Expanded như công cụ chính cho bố cục cột và bảng điều khiển trong Flutter

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm