
"TextSelection" là gì mà GenZ nào cũng phải biết?
Nghe nè mấy đứa, có bao giờ mấy đứa lướt TikTok, thấy cái caption nào đó hay quá, muốn copy gửi crush hoặc làm quote story không? Hay đọc một bài báo, muốn highlight một câu thần chú để nhớ? Đó, cái hành động "chạm giữ, kéo kéo con trỏ xanh xanh đỏ đỏ, rồi bấm Sao chép" đó chính là TextSelection đó! Đơn giản mà "quyền năng" vãi chưởng luôn.
Trong cái thế giới app "mượt mà" của GenZ, TextSelection nó giống như việc mình cho người dùng cái "remote control" để điều khiển nội dung vậy. Chữ nghĩa trên màn hình không còn là "đồ trưng bày" nữa, mà nó trở thành "dữ liệu tương tác" – có thể chọn, có thể copy, có thể cắt, có thể dán. Không có nó, app của mấy đứa sẽ giống như cái tivi bị mất remote, nhìn thì đẹp nhưng không làm ăn được gì nhiều đâu.
Với Flutter, việc "trao quyền" TextSelection cho người dùng dễ như ăn kẹo, không cần phải "đau não" code từng tí một đâu. Mình đi sâu vào xem nó "triển" như nào nhé!
Hướng dẫn "Triển Chiêu" TextSelection trong Flutter
Flutter cung cấp cho chúng ta vài "chiêu" để "triển" TextSelection một cách "ngon lành cành đào":
1. Cơ bản nhất: SelectableText – "Chữ có thể chọn"
Đây là "chiêu thức" đơn giản nhất khi mấy đứa muốn hiển thị một đoạn văn bản chỉ để đọc, nhưng lại muốn người dùng có thể chọn và copy nó. Nó giống như việc mình viết một cuốn sách, ai cũng đọc được, nhưng nếu muốn trích dẫn thì cứ tự nhiên chọn rồi copy.
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: 'TextSelection Demo',
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('TextSelection với SelectableText'),
),
body: const Center(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Đây là một đoạn văn bản bình thường, không thể chọn.',
style: TextStyle(fontSize: 18),
),
SizedBox(height: 20),
SelectableText(
'Đây là đoạn văn bản "siêu cấp pro", có thể chọn và copy thoải mái! Thử bấm giữ và kéo xem nào.',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.deepPurple),
// Có thể tùy chỉnh hành vi chọn tại đây (ví dụ: onSelectionChanged)
onSelectionChanged: (TextSelection selection, SelectionChangedCause? cause) {
print('Vùng chọn đã thay đổi: ${selection.textInside(this.toString())}');
},
),
SizedBox(height: 20),
Text(
'Nhớ là SelectableText chỉ dành cho văn bản "chỉ đọc" thôi nha mấy đứa!',
style: TextStyle(fontStyle: FontStyle.italic),
),
],
),
),
),
);
}
}
Giải thích: Đơn giản là thay Text('...') bằng SelectableText('...'). Thế là xong! Người dùng có thể bấm giữ và kéo để chọn văn bản. Mấy đứa còn có thể dùng onSelectionChanged để "hóng" xem người dùng đang chọn cái gì nữa đó. "Vui phết"!
2. Nâng cao hơn: TextField và TextFormField – "Chữ để nhập và chỉnh sửa"
Khi mấy đứa muốn người dùng không chỉ chọn mà còn nhập liệu, chỉnh sửa (kiểu như chat box, ô tìm kiếm), thì TextField hoặc TextFormField là "chân ái". Mấy widget này mặc định đã có tính năng TextSelection "xịn sò" rồi, không cần làm gì thêm.
Code Ví Dụ:
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: 'TextFormField Selection Demo',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _controller = TextEditingController(text: 'Thầy Creyt đẹp trai quá!');
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('TextSelection với TextFormField'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'Nhập gì đó vào đây, rồi thử chọn, cắt, copy, dán xem!',
style: TextStyle(fontSize: 18),
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
TextFormField(
controller: _controller,
decoration: const InputDecoration(
labelText: 'Cảm nghĩ về thầy Creyt?',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.edit),
),
style: const TextStyle(fontSize: 16),
// Mặc định TextSelection đã được bật. Mấy đứa có thể custom selectionControls nếu muốn thay đổi UI của các nút copy/paste.
// selectionControls: MaterialTextSelectionControls(), // Dùng mặc định của Material Design
onChanged: (text) {
print('Nội dung đang nhập: $text');
},
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// Lấy vùng text đang được chọn (nếu có)
final TextSelection selection = _controller.selection;
if (selection.isValid && selection.textInside(_controller.text).isNotEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Bạn vừa chọn: "${selection.textInside(_controller.text)}"')),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Chưa có gì được chọn cả!')),
);
}
},
child: const Text('Xem Text Đang Chọn'),
),
],
),
),
),
);
}
}
Giải thích: TextField và TextFormField sinh ra là để xử lý nhập liệu, nên việc chọn, cắt, copy, dán văn bản là tính năng cốt lõi của tụi nó. Mấy đứa không cần cấu hình gì thêm đâu, cứ dùng là nó tự động có. Nếu muốn "chơi trội" hơn, mấy đứa có thể custom cái selectionControls để thay đổi giao diện của mấy cái nút "Copy", "Paste" đó, nhưng thường thì dùng mặc định là "chuẩn bài" rồi.

"Mẹo Vặt" Của Thầy Creyt: Dùng TextSelection cho "Chất"
- "Tối ưu" trải nghiệm người dùng (UX): Đừng biến việc chọn văn bản thành một "cuộc thi nhanh tay lẹ mắt". Đảm bảo vùng chọn dễ thấy, các "tay cầm" (selection handles) dễ kéo. Flutter mặc định đã làm khá tốt điều này, nhưng nếu mấy đứa custom UI thì nhớ để ý nha.
- "Khi nào thì cấm chọn?": Không phải cái gì cũng cho chọn đâu nha. Ví dụ, mấy cái mã OTP, mật khẩu, hay thông tin nhạy cảm của người dùng thì nên cấm TextSelection. Đừng để người dùng vô tình copy rồi làm lộ thông tin.
- "Hiệu suất" cho văn bản "siêu dài": Nếu mấy đứa có một đoạn
SelectableTextdài "dằng dặc" (kiểu như một cuốn tiểu thuyết), thì đôi khi việc render và xử lý vùng chọn có thể hơi "ngốn" tài nguyên. Hãy cân nhắc xem có thật sự cầnSelectableTextcho toàn bộ đoạn đó không, hay chỉ một phần thôi. - "Phản hồi" khi chọn: Dùng
onSelectionChangedđể cung cấp phản hồi cho người dùng, ví dụ như hiển thị số ký tự đã chọn, hoặc một popup nhỏ với các tùy chọn khác (như chia sẻ, tìm kiếm...). "Ngầu" hơn nữa là tích hợp với các tính năng dịch thuật tức thì khi người dùng chọn một đoạn văn bản tiếng nước ngoài.
"Học Hỏi" Từ Các Ứng Dụng "Đỉnh Cao"
- Zalo/Messenger/Facebook: Mấy cái app chat này là "bậc thầy" của TextSelection. Mấy đứa có thể bấm giữ tin nhắn để copy, hoặc trong ô nhập liệu thì thoải mái chọn, cắt, dán. Họ còn có thêm các tùy chọn như "Trả lời", "Chuyển tiếp" khi bạn chọn tin nhắn nữa đó. Đây là cách họ biến TextSelection từ một tính năng cơ bản thành một "công cụ" tương tác mạnh mẽ.
- Các trình duyệt web (Chrome, Safari): Đây là nơi TextSelection "lên ngôi". Mấy đứa đọc báo, xem tin tức, muốn lưu lại một đoạn nào đó thì cứ việc chọn, copy. Họ còn có tính năng "tìm kiếm nhanh" hoặc "chia sẻ" trực tiếp từ vùng chọn nữa. "Bá đạo" chưa?
- Các ứng dụng đọc sách/ghi chú: Kindle, Google Docs, Notion... đều dùng TextSelection để người dùng highlight, ghi chú, hoặc tìm kiếm từ khóa trong văn bản. Đây là những ví dụ điển hình về việc TextSelection được tích hợp sâu vào trải nghiệm đọc và làm việc.
"Thử Nghiệm & Ứng Dụng Thực Tế": Khi nào "Show Hàng"?
-
Dùng
SelectableTextkhi nào?- Hiển thị điều khoản sử dụng, chính sách bảo mật mà người dùng có thể muốn copy một phần.
- Các đoạn quote, trích dẫn, câu nói hay trong app của mấy đứa.
- Thông báo, hướng dẫn sử dụng mà người dùng có thể muốn sao chép để tra cứu sau.
- Nội dung bài viết, tin tức (nếu không có chức năng chỉnh sửa).
-
Dùng
TextField/TextFormFieldkhi nào?- Tất nhiên là khi mấy đứa cần ô nhập liệu rồi! Từ ô tìm kiếm, ô chat, đến form đăng ký, đăng nhập. Bất cứ nơi nào người dùng cần nhập và chỉnh sửa văn bản.
- Trong các ứng dụng ghi chú, soạn thảo văn bản.
-
Khi nào thì không nên dùng hoặc cần cân nhắc đặc biệt?
- Nội dung nhạy cảm: Đã nói ở trên, mật khẩu, OTP, mã thẻ tín dụng... đừng bao giờ cho phép chọn và copy dễ dàng.
- Hiệu suất: Với các đoạn văn bản cực kỳ dài và phức tạp, hãy cân nhắc cách render hoặc chia nhỏ nội dung để tránh giật lag.
- Giao diện quá phức tạp: Đôi khi, việc có quá nhiều tính năng chọn/copy có thể làm rối giao diện. Hãy giữ mọi thứ đơn giản và trực quan nhất có thể.
Thấy chưa, TextSelection không chỉ là một cái tính năng "nhỏ nhặt" đâu, nó là một phần quan trọng để làm cho app của mấy đứa "sống động" và "thân thiện" hơn với người dùng đó. Cứ "nghịch" nhiều vào, rồi mấy đứa sẽ thấy nó "lợi hại" đến mức nào!
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é!