
Chào các dân chơi hệ Flutter! Hôm nay, anh Creyt sẽ "unbox" một widget nghe có vẻ đơn giản nhưng lại là "key" để app của mấy đứa "flex" độ xịn sò về UX. Đó chính là SelectionArea – Nghe tên đã thấy vibe "chọn lựa" rồi đúng không?
Tưởng tượng thế này: App của mấy đứa như một cuốn sách hay ho, nhưng trước giờ, người dùng chỉ có thể đọc thôi. Muốn trích dẫn một câu, một đoạn thơ tâm đắc để share lên story, hay đơn giản là copy cái tên sản phẩm siêu dài để tìm kiếm, thì chịu chết. Giống như mấy đứa xem phim qua màn hình, muốn "chộp" lấy nhân vật ra ngoài để hun một cái cũng không được vậy!
SelectionArea chính là "cây đũa thần" biến cuốn sách tĩnh đó thành một bản PDF mà mấy đứa có thể bôi đen, copy, paste thoải mái. Nó biến nội dung trên app của mấy đứa từ "chỉ để ngắm" thành "có thể chạm và tương tác". Nói ngắn gọn, nó là cái "remote control" cho phép người dùng "photocopy" nội dung từ app của mấy đứa ra thế giới bên ngoài một cách "chill" nhất.
SelectionArea Là Gì Và Để Làm Gì?
Về cơ bản, SelectionArea trong Flutter là một widget được thiết kế để cho phép người dùng chọn (select) văn bản hoặc các widget con khác nằm trong phạm vi của nó. Khi được bọc trong SelectionArea, bất kỳ Text widget nào (hoặc widget hiển thị văn bản) bên trong sẽ tự động có khả năng được chọn bằng cách nhấn giữ (long press) hoặc kéo chuột (trên desktop/web).
Tại sao nó lại quan trọng? Đơn giản thôi: Trải nghiệm người dùng (UX). Trong thế giới số hóa hiện nay, việc copy-paste thông tin là một hành động cơ bản và thiết yếu. Nếu app của mấy đứa mà người dùng không copy được text, họ sẽ cảm thấy khó chịu, giống như đang gõ phím mà bàn phím bị kẹt vậy. Nó làm giảm đi sự tiện lợi, làm mất đi tính "thân thiện" của app. SelectionArea giải quyết triệt để vấn đề này, biến app của mấy đứa từ một "bức tường" thành một "cánh cửa" mở ra sự tương tác.
Code Ví Dụ Minh Hoạ Rõ Ràng
Nói lý thuyết nhiều quá, giờ anh em mình "flex code" cho nó nóng hổi. Để thấy sức mạnh của SelectionArea, mấy đứa chỉ cần bọc những widget mà mấy đứa muốn cho phép chọn text vào trong nó là xong. Đơn giản như ăn kẹo!
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: 'SelectionArea Demo by Creyt',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('SelectionArea - Copy-Paste Thần Thánh'),
),
body: SelectionArea( // Bọc toàn bộ phần thân để mọi text đều có thể chọn
child: SingleChildScrollView(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Chào các bạn Gen Z!',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
const Text(
'Đây là một đoạn văn bản mà trước đây bạn không thể chọn và sao chép. Nhưng giờ đây, nhờ có SelectionArea, bạn có thể dễ dàng bôi đen và copy nó. Hãy thử nhấn giữ (long press) hoặc kéo chuột để chọn nhé!',
style: TextStyle(fontSize: 16),
),
const SizedBox(height: 20),
const Text(
'Một đoạn văn khác với thông tin quan trọng:',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
),
const SizedBox(height: 10),
const Text(
'Flutter là một framework UI mã nguồn mở do Google tạo ra. Nó được sử dụng để phát triển các ứng dụng đa nền tảng cho Android, iOS, Linux, macOS, Windows, Google Fuchsia và web từ một codebase duy nhất.',
style: TextStyle(fontSize: 16),
),
const SizedBox(height: 20),
const Text(
'Địa chỉ liên hệ: 123 Đường Lập Trình, Quận Code, Thành phố Flutterville.',
style: TextStyle(fontSize: 16, fontStyle: FontStyle.italic),
),
const SizedBox(height: 50),
// Ví dụ về một phần không muốn cho phép chọn
Container(
color: Colors.grey[200],
padding: const EdgeInsets.all(15),
child: const Text(
'Phần này được bọc trong một widget khác, nhưng vì nó nằm trong SelectionArea chung, nó vẫn có thể chọn được. Để KHÔNG cho phép chọn, bạn cần bọc nó trong SelectionContainer.disabled.',
style: TextStyle(fontSize: 14, color: Colors.red),
),
),
const SizedBox(height: 20),
// Ví dụ về cách vô hiệu hóa Selection cho một phần cụ thể
SelectionContainer.disabled(
child: Container(
color: Colors.yellow[100],
padding: const EdgeInsets.all(15),
child: const Text(
'Bạn sẽ không thể chọn đoạn văn bản này vì nó được bọc trong SelectionContainer.disabled. Đây là cách để bảo vệ thông tin mà bạn không muốn người dùng copy.',
style: TextStyle(fontSize: 14, color: Colors.blueGrey),
),
),
),
],
),
),
),
);
}
}

Mẹo Vặt (Best Practices) Từ Anh Creyt
Để dùng SelectionArea một cách "pro" và hiệu quả, mấy đứa cần nhớ mấy tips sau đây, đây là "kinh nghiệm xương máu" của anh Creyt đó:
- Bọc càng cao càng tốt: Thường thì, mấy đứa nên bọc
SelectionAreaở một cấp độ cao trong widget tree của mình, ví dụ như bọc toàn bộScaffold'sbodyhoặc thậm chí làMaterialAppnếu muốn toàn bộ app đều có thể chọn. Điều này đảm bảo mọi văn bản trong app đều có khả năng tương tác. - Kiểm soát vùng chọn với
SelectionContainer.disabled: Đôi khi, có những đoạn văn bản mấy đứa không muốn cho người dùng copy (ví dụ: mã bảo mật, thông tin nhạy cảm, hoặc đơn giản là một phần UI không phải là nội dung). Lúc này, hãy dùngSelectionContainer.disabledđể bọc riêng phần đó lại. Nó giống như đặt một tấm kính cường lực lên một phần của cuốn sách vậy, vẫn nằm trong SelectionArea lớn nhưng không cho phép chọn. - Tùy chỉnh giao diện chọn (
selectionControls): Mặc định,SelectionAreasẽ dùng giao diện chọn mặc định của nền tảng (Material hoặc Cupertino). Nhưng mấy đứa hoàn toàn có thể tùy chỉnh các "tay cầm" (handles) để chọn, các menu popup (copy, paste, share) bằng cách cung cấp mộtSelectionControlscustom choSelectionArea. Cái này thì hơi "advanced" một chút, nhưng khi cần "flex" UI độc đáo thì nó là "vũ khí bí mật" đó. - Hiệu suất: Đừng lo lắng quá về hiệu suất khi dùng
SelectionAreavới văn bản thông thường. Nó được tối ưu khá tốt. Tuy nhiên, nếu mấy đứa có hàng ngànTextwidget bên trong mộtSelectionAreakhổng lồ và phức tạp, thì cũng nên cân nhắc một chút. Nhưng với các ứng dụng thông thường, cứ "quất" đi! - Nested SelectionAreas: Mấy đứa có thể có nhiều
SelectionArealồng nhau. Khi đó, vùng chọn sẽ được xử lý bởiSelectionAreagần nhất với widget được chọn. Nhưng tốt nhất là nên có mộtSelectionArealớn duy nhất và dùngSelectionContainer.disabledđể vô hiệu hóa các vùng nhỏ.
Ứng Dụng Thực Tế
Mấy đứa nghĩ xem, những app nào mà mấy đứa hay copy-paste nhất?
- App đọc báo, đọc truyện, đọc sách (e.g., Kindle, Medium, VNExpress): Chắc chắn rồi! Người dùng cần trích dẫn, lưu lại những câu văn hay, những tin tức quan trọng.
- App ghi chú (e.g., Notion, Google Keep): Mấy đứa ghi chú thì đương nhiên phải copy nội dung từ chỗ này sang chỗ khác để sắp xếp, chỉnh sửa chứ.
- App tài liệu, hướng dẫn (e.g., Google Docs, Wikipedia): Nơi mà thông tin là vàng, việc copy-paste để nghiên cứu, học tập là cực kỳ cần thiết.
- Các trang web thương mại điện tử (e.g., Shopee, Lazada): Mấy đứa muốn copy tên sản phẩm, mã SKU, hoặc mô tả sản phẩm để tìm kiếm hoặc chia sẻ.
SelectionArea chính là cái "linh hồn" thầm lặng giúp những app này trở nên "friendly" hơn rất nhiều.
Thử Nghiệm Của Anh Creyt Và Khi Nào Nên Dùng
Anh Creyt đã từng "vật lộn" với việc này hồi xưa, khi Flutter chưa có SelectionArea "chuẩn chỉ". Hồi đó, muốn copy text là phải tự "hack" bằng cách dùng GestureDetector rồi Clipboard.setData, mà nó "cùi bắp" lắm, không có cái thanh kéo chọn hay menu popup "xịn sò" như bây giờ đâu. Mãi đến khi SelectionArea ra đời, anh em lập trình viên mới được "giải thoát".
Nên dùng cho case nào?
- Content-heavy apps: Bất kỳ app nào mà nội dung text là trung tâm (news, blogs, docs, e-books).
- Forms with pre-filled information: Khi mấy đứa hiển thị thông tin mà người dùng có thể muốn copy để dùng ở nơi khác (ví dụ: mã đơn hàng, địa chỉ giao hàng).
- Debugging/Logging displays: Trong các công cụ debug nội bộ, việc cho phép chọn và copy log rất hữu ích.
Không nên dùng cho case nào (hoặc cần cân nhắc):
- Các phần UI mà việc chọn text không có ý nghĩa: Ví dụ: các nút bấm, icon, hình ảnh (trừ khi mấy đứa muốn copy alt text của hình ảnh, nhưng đó là câu chuyện khác).
- Thông tin nhạy cảm/bảo mật: Như đã nói, dùng
SelectionContainer.disabledđể vô hiệu hóa chọn cho những phần này. Đừng để người dùng vô tình copy mật khẩu hay mã OTP trên màn hình của họ nhé!
Tóm lại, SelectionArea là một "người bạn đồng hành" không thể thiếu để nâng tầm trải nghiệm người dùng trong app Flutter của mấy đứa. Hãy dùng nó một cách thông minh và linh hoạt để app của mấy đứa không chỉ đẹp mà còn tiện lợi nữa!
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é!