Flutter responsive design: Kích thước không phải (luôn luôn) là vấn đề

Thiết kế một ứng dụng có thể là một cuộc đấu tranh thực sự khi bạn phải sử dụng điện thoại thông minh, máy tính bảng và web. Thông thường, bạn có thể xác định bố cục chung bằng cách truy xuất kích thước màn hình thiết bị thông qua cá thể MediaQueryData.

@override
Widget build(BuildContext context) {
  final screenWidth = MediaQuery.of(context).size.width;
  if (screenWidth < 600.0) {
    return _buildPhoneLayout();
  }
  else if (screenWidth < 1000.0) {
    return _buildTabletLayout();
  }
  else {
    return _buildDesktopLayout();
  }
}

Ví dụ trên đây là một cách đơn giản nhưng thực dụng để bố trí trang ứng dụng của bạn. Điều duy nhất tôi không thích là bạn phải xác định giới hạn cho việc phát hiện thiết bị (thiết bị dưới 600.0 pixel chiều rộng logic được coi là điện thoại trong ví dụ này). Không đơn giản như vậy, vì tôi không thể tìm thấy câu trả lời cụ thể trong tài liệu Flutter…

Sử dụng phương pháp này cho mọi tiện ích con bạn tạo có thể gây lãng phí thời gian, gây ra lỗi trong giao diện người dùng và tất nhiên là khó phát triển. Bạn có thực sự muốn phân tán logic thiết kế đáp ứng vào các widget của mình không? Làm thế nào để bạn đảm bảo tính đồng nhất của mã ?

Một cách tiếp cận tốt là làm cho các widget đáp ứng với kích thước gốc và các ràng buộc của nó, một cách minh bạch (ý tôi là không phát triển bất kỳ mã cụ thể nào xử lý kích thước, kích thước màn hình, v.v. ).

Flutter SDK có câu trả lời cho bạn, dưới dạng một tiện ích: OverflowBar!

Tiện ích con này sẽ hiển thị các con của nó theo chiều ngang, giống như tiện ích Hàng, nếu nó có đủ dung lượng. Nếu không, nó sẽ hiển thị con theo chiều dọc, dưới dạng tiện ích con Cột. Thêm vào đó, một số tham số đầu vào khác cho phép bạn đặt khoảng cách giữa mọi con.

Demonstration

Hãy lấy một ví dụ để minh họa việc sử dụng OveflowBar. Đây là thiết kế chúng tôi chọn:

Có quen thuộc với mẫu bố cục đó không? Chúng tôi thường thấy nó trong "các trang web một trang". Mỗi phần tử tự hiển thị trong một hàng, khi chúng có đủ không gian. Phần tử "hướng" được chuyển từ một phần tử khác, chỉ trong phiên bản máy tính để bàn. Ngược lại, phiên bản di động hiển thị các yếu tố theo chiều dọc, luôn hiển thị hình ảnh trước.

Trong Flutter, hành vi bố cục này rất dễ thực hiện.

Thiết kế widget

Đầu tiên, hãy tạo một widget của riêng chúng ta, chứa tất cả các thuộc tính cần thiết để hiển thị một phần tử như vậy.

class BlogOverview extends StatelessWidget {
  final Widget image;
  final String title;
  final String text;
  final bool reversed;

  BlogOverview({this.title, this.text, this.image, this.reversed = false});

Sau đó, trong phương thức xây dựng, chúng ta sẽ sử dụng OverflowBar để bố trí phần tử của chúng ta.

@override
Widget build(BuildContext context) {
  return OverflowBar(
    overflowAlignment: OverflowBarAlignment.center,
    spacing: 20.0,
    overflowSpacing: 16.0,
    textDirection: reversed ? TextDirection.rtl : TextDirection.ltr,
    children: [
      _buildImageWidget(),
      _buildDescriptionPanel(),
    ],
  );
}

Trong ví dụ này, khoảng cách và tràn ngập Spacing đề cập đến cả khoảng cách giữa hình ảnh và mô tả của chúng tôi. Khoảng cách sẽ được sử dụng khi hiển thị dưới dạng một hàng, trong khi đó, tràn lề sẽ được sử dụng khi các phần tử con được hiển thị dưới dạng cột.

Việc chuyển đổi vị trí con được thực hiện bởi tham số đầu vào textDirection.

Tích hợp Widget trong một listview

Tiện ích đã tạo của chúng tôi sẽ tự thích ứng với không gian có sẵn. Vì vậy, việc thiết kế toàn bộ một màn hình là như bình thường.

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('Flutter OverflowBar Demo'),
    ),
    body: ListView.separated(
      itemCount: 20,
      itemBuilder: (context, index) => _buildBlog(index),
      separatorBuilder: (context, index) => Divider(height: 80.0,),
      padding: EdgeInsets.symmetric(horizontal: 12.0),
    ),
  );
}

Widget _buildBlog(int index) {
  return Container(
    alignment: Alignment.center,
    padding: EdgeInsets.all(10.0),
    child: BlogOverview(
      title: 'Blog Nature #${index+1}',
      text: ...,
      image: ...,
      reversed: index.isOdd,
    ),
  );
}

Điều quan trọng nhất trong đoạn mã đó là không cần biết kích thước màn hình là bao nhiêu!

Phần kết luận

Theo tôi, các ứng dụng đáp ứng tốt nhất không lạm dụng kích thước màn hình.

Về chất lượng mã, bạn đã triển khai yếu tố thiết kế (hình ảnh + mô tả) dưới dạng một widget duy nhất, rất ngắn gọn và dễ hiểu (không có thuật toán bố cục phức tạp).

Về mặt bảo trì ứng dụng, không có phép tính kỳ lạ nào xác định xem chúng ta phải bố trí các phần tử theo chiều ngang hay chiều dọc. Các OverflowBar làm điều đó bản thân và quan trọng nhất, khi kích thước được biết đến (trong làm cho đối tượng của nó).

Về thiết kế, bạn có thể đảm bảo hướng bố cục bằng cách xác định kích thước cho các vật dụng. Trong ví dụ này, kích thước hình ảnh là 300x300 pixel logic và chiều rộng mô tả bị giới hạn ở 300. Do đó, chúng tôi có thể đảm bảo rằng đối với chiều rộng thiết bị thấp hơn 600 (chúng tôi coi chúng là điện thoại thông minh), tiện ích con sẽ bố trí theo chiều dọc.

Bạn sẽ có thể tìm thấy mã được phát triển cho bài viết này tại đây:

GONZALEZD/flutter_demos

 

Tìm hiểu thêm về khóa học flutter tại Techmaster

Bài viết gốc tại đây