
Viewport Flutter: 'Cửa Sổ' Nhìn Ra Thế Giới App Của Bạn!
Chào các gen Z mê code, nay Creyt sẽ bật mí một khái niệm cực kỳ cơ bản nhưng lại là 'xương sống' của mọi ứng dụng đẹp đẽ, linh hoạt: Viewport.
Viewport Là Gì? 'Khung Ảnh' Mà App Của Bạn Được Phép Vẽ Lên!
Bạn hình dung thế này, cái màn hình điện thoại, tablet hay máy tính của bạn giống như một cái cửa sổ vậy. Ứng dụng của bạn, nó được phép 'vẽ' lên một phần của cái cửa sổ đó. Cái phần mà ứng dụng được phép vẽ, được phép hiển thị nội dung, chính là Viewport.
Nói cách khác, Viewport chính là khu vực hiển thị hiện tại của ứng dụng trên màn hình thiết bị. Nó không phải là toàn bộ màn hình, mà là phần màn hình mà app của bạn đang chiếm dụng, đã trừ đi các thanh trạng thái (status bar), thanh điều hướng (navigation bar) hay các vùng 'tai thỏ', 'notch' khó chịu.
Để làm gì? 'Người Quản Lý Không Gian' Tối Thượng!
Viewport sinh ra để làm 'người quản lý không gian' cho app của bạn. Nó cung cấp thông tin tối quan trọng cho các widget biết:
- Mình có bao nhiêu không gian để bung lụa? (Chiều rộng, chiều cao)
- Mình đang ở đâu trên màn hình? (Nếu cần)
- Mình có nên cuộn không? (Nếu nội dung quá dài so với viewport)
Chính nhờ Viewport mà ứng dụng Flutter của bạn có thể 'co giãn' thần kỳ, tự động điều chỉnh bố cục để trông đẹp mắt trên mọi thiết bị – từ cái iPhone mini bé xíu đến cái tablet to đùng, hay thậm chí là khi bạn chia đôi màn hình (split screen). Nếu không có Viewport, app của bạn sẽ như một bức tranh cố định, bị cắt xén hoặc thừa thãi khi hiển thị trên các kích thước màn hình khác nhau.
Code Ví Dụ: Gọi Tên Viewport Qua MediaQuery
Trong Flutter, Viewport không phải là một widget bạn 'kéo thả' trực tiếp. Nó là một khái niệm được quản lý ngầm bởi framework và được cung cấp thông tin thông qua các widget như MediaQuery hoặc LayoutBuilder.
MediaQuery.of(context) là 'thầy bói' chuẩn xác nhất, nó sẽ cho bạn biết mọi thứ về Viewport hiện tại: kích thước, mật độ điểm ảnh, hướng màn hình... Hãy xem ví dụ đơn giản này để thấy cách chúng ta 'bắt mạch' Viewport:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Khám Phá Viewport Cùng Creyt',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const ViewportInfoScreen(),
);
}
}
class ViewportInfoScreen extends StatelessWidget {
const ViewportInfoScreen({super.key});
@override
Widget build(BuildContext context) {
// Lấy thông tin về màn hình hiện tại thông qua MediaQuery
final mediaQueryData = MediaQuery.of(context);
final screenWidth = mediaQueryData.size.width; // Chiều rộng của viewport
final screenHeight = mediaQueryData.size.height; // Chiều cao của viewport
final orientation = mediaQueryData.orientation; // Hướng màn hình (dọc/ngang)
final devicePixelRatio = mediaQueryData.devicePixelRatio; // Tỷ lệ pixel của thiết bị
final paddingTop = mediaQueryData.padding.top; // Vùng an toàn trên cùng (thanh trạng thái, notch)
final paddingBottom = mediaQueryData.padding.bottom; // Vùng an toàn dưới cùng (thanh điều hướng)
return Scaffold(
appBar: AppBar(
title: const Text('Thông Tin Viewport'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Chiều rộng Viewport: ${screenWidth.toStringAsFixed(2)} px'),
Text('Chiều cao Viewport: ${screenHeight.toStringAsFixed(2)} px'),
Text('Hướng màn hình: ${orientation == Orientation.portrait ? 'Dọc' : 'Ngang'}'),
Text('Tỷ lệ Pixel (DPR): ${devicePixelRatio.toStringAsFixed(2)}'),
Text('Padding Top (Safe Area): ${paddingTop.toStringAsFixed(2)} px'),
Text('Padding Bottom (Safe Area): ${paddingBottom.toStringAsFixed(2)} px'),
const SizedBox(height: 20),
// Ví dụ về cách dùng kích thước viewport để điều chỉnh widget
Container(
width: screenWidth * 0.8, // 80% chiều rộng viewport
height: screenHeight * 0.2, // 20% chiều cao viewport
color: Colors.deepPurple,
child: const Center(
child: Text(
'Widget này chiếm 80% Rộng & 20% Cao của Viewport',
style: TextStyle(color: Colors.white, fontSize: 14),
textAlign: TextAlign.center,
),
),
),
],
),
),
),
);
}
}
Trong ví dụ trên, chúng ta dùng MediaQuery.of(context) để lấy các thông số của Viewport. Bạn sẽ thấy screenWidth và screenHeight chính là kích thước của khu vực mà app có thể vẽ. Khi bạn xoay điện thoại, các giá trị này sẽ thay đổi, và widget Container của chúng ta sẽ tự động điều chỉnh kích thước theo tỷ lệ đã định.
Ngoài ra, các widget có khả năng cuộn như SingleChildScrollView, ListView, GridView cũng sử dụng thông tin từ Viewport để biết liệu nội dung có tràn ra ngoài hay không, và từ đó quyết định có hiển thị thanh cuộn (scroll bar) hay không.

Mẹo Hay Từ Creyt: 'Bí Kíp' Sống Sót Với Viewport!
Đây là vài 'bí kíp' từ Creyt để bạn làm chủ Viewport và tạo ra những ứng dụng Flutter 'đỉnh của chóp':
-
Đừng 'Hardcode' Kích Thước: Tuyệt đối tránh việc gán các giá trị cố định như
width: 300hayheight: 500cho các widget quan trọng. Luôn dùngMediaQuery.of(context).size.widthhoặcheightđể tính toán kích thước tương đối (ví dụ:width: screenWidth * 0.7). Điều này đảm bảo app của bạn 'responsive' trên mọi màn hình. -
Làm Quen Với Widget Cuộn: Hiểu rõ cách
SingleChildScrollView,ListView,GridView,CustomScrollViewhoạt động. Chúng là những 'người bạn thân' của Viewport, giúp nội dung của bạn được hiển thị đầy đủ ngay cả khi nó dài hơn Viewport. -
Dùng
SafeAreaNhư 'Áo Giáp': Luôn bọc các widget chính của bạn trongSafeArea. Widget này sẽ tự động thêm padding để nội dung không bị che khuất bởi các thanh trạng thái, 'tai thỏ', hay thanh điều hướng vật lý. Nó giúp nội dung của bạn luôn nằm trong Viewport 'an toàn'. -
Expanded,Flexible,LayoutBuilderLà 'Đồng Minh': Khi muốn các widget con tự động co giãn theo không gian còn lại trong Viewport, hãy nghĩ ngay đếnExpandedvàFlexible(trongRowhoặcColumn). CònLayoutBuildercho phép bạn xây dựng UI khác nhau tùy thuộc vào kích thước của widget cha (hoặc Viewport mà nó đang nằm trong).
Ai Đã Dùng Viewport? 'Ông Kẹ' Nào Cũng Cần!
Bạn có thể không nhận ra, nhưng gần như mọi ứng dụng bạn dùng hàng ngày đều đang 'bóc lột' Viewport một cách triệt để:
- TikTok, Instagram, Facebook: Khi bạn cuộn feed vô tận, các bài đăng mới được tải và hiển thị mượt mà, luôn vừa vặn với Viewport của bạn, dù bạn đang xem trên điện thoại hay tablet. Họ dùng Viewport để tính toán khi nào cần tải thêm nội dung.
- Netflix, YouTube: Khi bạn xoay ngang màn hình để xem phim, giao diện tự động điều chỉnh để video chiếm toàn bộ Viewport, và các nút điều khiển cũng tự sắp xếp lại cho phù hợp. Tương tự khi bạn dùng ứng dụng trên Smart TV hay máy tính bảng.
- Các ứng dụng đọc báo, truyện tranh: Nội dung văn bản, hình ảnh được căn chỉnh lại để bạn đọc thoải mái nhất, không bị tràn hay quá nhỏ, dù bạn dùng màn hình cỡ nào.
Thử Nghiệm Ngay & Dùng Khi Nào?
Thử nghiệm:
- Chạy ứng dụng ví dụ trên điện thoại của bạn.
- Xoay ngang điện thoại: Bạn sẽ thấy các giá trị
screenWidthvàscreenHeightthay đổi, vàContainermàu tím cũng tự động điều chỉnh kích thước. - (Nếu có thể) Dùng chế độ chia đôi màn hình (Split Screen) trên Android hoặc iPad: Xem cách Viewport của ứng dụng thay đổi và các widget phản ứng thế nào. Đây là bài kiểm tra 'khắc nghiệt' nhất cho tính responsive.
Dùng khi nào?
Nói thẳng ra là bạn luôn luôn phải quan tâm đến Viewport khi phát triển giao diện người dùng trong Flutter. Cụ thể hơn:
- Khi thiết kế Responsive UI: Để app của bạn trông đẹp và hoạt động tốt trên mọi kích thước màn hình và mọi thiết bị.
- Khi cần cuộn nội dung: Để đảm bảo nội dung dài được hiển thị đầy đủ và người dùng có thể tương tác dễ dàng.
- Khi cần căn chỉnh các thành phần UI: Dùng Viewport để tính toán vị trí và kích thước tương đối của các widget một cách linh hoạt.
- Khi xử lý các vùng an toàn (Safe Area): Để tránh nội dung bị che khuất bởi các phần cứng của thiết bị (notch, camera, thanh điều hướng).
Nắm vững Viewport là bạn đã có trong tay chìa khóa để tạo ra những ứng dụng Flutter không chỉ đẹp mà còn cực kỳ linh hoạt và thân thiện với người dùng. Hãy thực hành và 'nghịch' nó thật nhiều vào nhé!
Thuộc Series: Flutter
Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!