
Hôm nay, anh Creyt sẽ 'bóc tách' cho tụi em một cái 'magic trick' cực đỉnh trong Flutter, giúp UI của tụi em từ 'bình thường' hóa 'phi thường' chỉ trong một nốt nhạc: đó chính là ShaderMask (và đằng sau nó là ShaderMaskLayer).
Tưởng tượng thế này: em có một bức tranh (child widget), và em muốn 'che' một phần của nó đi, hoặc tô màu cho nó theo một kiểu 'gradient' siêu ngầu, hoặc thậm chí là dùng một bức ảnh khác làm 'khuôn' để cắt cái bức tranh gốc. ShaderMask chính là cái 'khuôn thần kỳ' đó!
Nó không chỉ đơn thuần là cắt hình vuông, hình tròn đâu nha. Cái 'khuôn' này có thể là một dải màu chuyển sắc (gradient), một tấm ảnh mờ ảo, hay thậm chí là một hiệu ứng 'glitch' do em tự code ra. Về cơ bản, nó dùng một Shader (bộ tô màu) để làm mặt nạ. Chỗ nào cái Shader này 'tô' màu rõ, thì cái widget con của em sẽ hiện ra. Chỗ nào nó 'tô' trong suốt, thì widget con sẽ biến mất. Đơn giản là vậy!
Và ShaderMaskLayer? À, đó là 'công nhân' cần mẫn phía sau hậu trường, là cái 'bàn vẽ' mà Flutter dùng để thực hiện tất cả các phép màu về mặt nạ này. Tụi em dùng ShaderMask trên bề mặt, còn ShaderMaskLayer là cái 'công cụ' mà Flutter gọi ra để vẽ vời, xử lý pixel các kiểu con đà điểu.
Code Ví Dụ: Chữ Gradient Siêu Ngầu
Nói nhiều lý thuyết khô khan quá đúng không? Thôi, mình 'nhảy' thẳng vào code để thấy nó 'cool' cỡ nào nè. Ví dụ kinh điển nhất, và cũng là cái tụi em hay thấy trên mấy cái app 'xịn xò' là: Chữ chuyển màu gradient.
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: 'Creyt\'s ShaderMask Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const GradientTextScreen(),
);
}
}
class GradientTextScreen extends StatelessWidget {
const GradientTextScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('ShaderMask: Chữ Gradient Siêu Ngầu'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Đây là màn trình diễn của ShaderMask
ShaderMask(
// Cái này là 'bộ lọc màu' hay 'khuôn' của mình nè
shaderCallback: (bounds) {
return const LinearGradient(
colors: [Colors.purple, Colors.pink, Colors.red], // Dải màu chuyển sắc
begin: Alignment.topLeft, // Bắt đầu từ góc trên bên trái
end: Alignment.bottomRight, // Kết thúc ở góc dưới bên phải
).createShader(bounds); // Tạo shader từ dải màu đó
},
blendMode: BlendMode.srcIn, // Cách mà shader hòa trộn với widget con
// Đây là 'bức tranh' mà mình muốn áp dụng mặt nạ
child: const Text(
'Creyt\'s Code Vibes',
style: TextStyle(
fontSize: 48,
fontWeight: FontWeight.bold,
// Màu ở đây không quan trọng lắm vì sẽ bị ShaderMask thay thế
color: Colors.white, // Mặc định là trắng, nhưng shader sẽ override
),
),
),
const SizedBox(height: 30),
ShaderMask(
shaderCallback: (bounds) {
return const RadialGradient(
colors: [Colors.yellow, Colors.orange, Colors.red],
center: Alignment.center,
radius: 0.8,
).createShader(bounds);
},
blendMode: BlendMode.srcIn,
child: const Icon(
Icons.star,
size: 100,
color: Colors.white, // Cũng sẽ bị override
),
),
const SizedBox(height: 30),
// Thử với một Image làm mask (hoặc áp dụng mask lên Image)
ShaderMask(
shaderCallback: (bounds) {
// Tưởng tượng bạn có một hình ảnh đen trắng,
// phần màu trắng sẽ cho phép child hiện ra,
// phần màu đen sẽ che đi. Ở đây mình dùng gradient giả lập.
return const LinearGradient(
colors: [Colors.transparent, Colors.black, Colors.transparent],
stops: [0.0, 0.5, 1.0],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
).createShader(bounds);
},
blendMode: BlendMode.dstIn, // DstIn: hiển thị nơi cả mask và child đều có pixel
child: Image.network(
'https://picsum.photos/200', // Một hình ảnh bất kỳ
width: 200,
height: 200,
fit: BoxFit.cover,
),
),
],
),
),
);
}
}
Trong ví dụ này, anh dùng LinearGradient để tạo ra một dải màu chuyển sắc từ tím, hồng đến đỏ. Cái dải màu này chính là Shader của chúng ta, và nó được dùng làm 'mặt nạ' cho widget Text con. Kết quả là, chữ 'Creyt's Code Vibes' sẽ được tô màu gradient siêu ngầu!

Mẹo Vặt Từ Lão Làng Creyt (Best Practices)
Mấy đứa nghe kỹ đây, đây là mấy cái 'mẹo vặt' từ lão làng Creyt mà tụi em nên 'bỏ túi' để dùng ShaderMask cho 'chuẩn bài' nè:
- Hiểu
BlendMode: Cái thuộc tínhblendModetrongShaderMaskquan trọng lắm nha. Nó quyết định cáchShader(mask) vàchild(nội dung) hòa trộn với nhau.BlendMode.srcIn: Thường dùng nhất. Nó sẽ chỉ hiển thị phầnchildnằm trong vùng 'có màu' củashader. Như ví dụ chữ gradient ấy.BlendMode.dstIn: Hiển thị phầnchildnơi cảshadervàchildđều có pixel. Thường dùng khishaderlà một hình ảnh 'texture' để tạo hiệu ứng 'cắt gọt' chochild.- Cứ thử nghiệm mấy cái
blendModekhác nhau để xem hiệu ứng nào 'hợp gu' nhất.
- Performance (Hiệu suất):
ShaderMaskkhá 'ngốn' tài nguyên, đặc biệt nếuShadercủa em phức tạp (ví dụ, dùngImageShadervới ảnh lớn, hoặc custom shader phức tạp). Nên dùng có chọn lọc, đừng lạm dụng quá mức nếu không cần thiết. - Kết hợp với các Widget khác:
ShaderMaskthường đi kèm với các widget khác nhưClipRRectđể tạo ra những hiệu ứng mặt nạ trên các hình dạng đặc biệt, hoặcAnimatedBuilderđể tạo hiệu ứng động choShader. - Thử nghiệm với các loại
Gradient: Đừng chỉ dừng lại ởLinearGradient. Hãy thửRadialGradient(chuyển màu từ tâm ra) haySweepGradient(chuyển màu xoay tròn) để tạo ra các hiệu ứng độc đáo hơn. - Custom Shader (Level Up): Nếu muốn 'đỉnh của chóp', em có thể tự viết
CustomShaderbằng ngôn ngữ GLSL rồi nhúng vào Flutter. Cái này thì hơi 'khoai' một chút nhưng kết quả thì 'ảo diệu' khỏi bàn! (Cái này thì để dành cho buổi học khác nha, hôm nay mình 'nhẹ nhàng' thôi).
Ứng Dụng Thực Tế: Ai Đã Dùng?
Tụi em có biết mấy cái app 'hot hit' mà tụi em dùng hàng ngày đã ứng dụng cái 'chiêu' này như thế nào không?
- Spotify: Thường xuyên sử dụng gradient cho các tiêu đề bài hát, tên nghệ sĩ, hoặc các nút bấm để tạo cảm giác hiện đại, 'chill' và thu hút thị giác.
ShaderMasklà một trong những công cụ để họ làm điều đó. - Instagram/TikTok: Mặc dù không phải
ShaderMasktrực tiếp, nhưng concept 'filter' ảnh/video mà tụi em dùng hàng ngày chính là ứng dụng củaShader(bộ tô màu). Tưởng tượngShaderMasklà một 'filter' cho các widget UI của em. - Các ứng dụng ngân hàng/tài chính: Đôi khi họ dùng gradient để làm nổi bật số dư, các chỉ số quan trọng, tạo cảm giác 'sang chảnh' và đáng tin cậy.
- Game UI: Các thanh máu, thanh mana trong game thường có hiệu ứng gradient hoặc texture fill. Khi thanh máu giảm, phần gradient cũng có thể thay đổi để tạo hiệu ứng thị giác mạnh mẽ hơn.
ShaderMaskcó thể giúp tạo ra những hiệu ứng này một cách linh hoạt.
Khi Nào Nên Dùng và Tránh Dùng?
Anh Creyt đã 'chinh chiến' với ShaderMask này không ít lần rồi, và đây là vài lời khuyên 'xương máu' từ kinh nghiệm thực tế:
- Nên dùng khi nào?
- Tạo điểm nhấn thương hiệu (Branding): Khi muốn logo, tiêu đề, hoặc các yếu tố quan trọng của app có một dải màu gradient đặc trưng, 'không đụng hàng'.
- Hiệu ứng thị giác 'sang chảnh': Các button, card, hoặc text cần một vẻ ngoài cao cấp, hiện đại, thu hút ánh nhìn.
- UI động (Dynamic UI): Khi em muốn hiệu ứng chuyển màu thay đổi theo trạng thái (ví dụ, thanh tiến trình, thanh máu thay đổi màu khi gần hết).
- Masking ảnh/widget với hình dạng phức tạp: Mặc dù
ClipRRecthayClipPathcũng làm được, nhưngShaderMaskcho phép em dùng mộtImageShaderđể tạo mặt nạ dựa trên độ trong suốt của một bức ảnh khác, mở ra nhiều khả năng sáng tạo hơn.
- Khi nào thì 'tạm dừng' và suy nghĩ lại?
- Khi chỉ cần một màu solid: Đừng 'lấy dao mổ trâu giết gà' khi chỉ cần tô một màu đơn giản. Dùng
TextStyle(color: ...)hoặcContainer(color: ...)là đủ. - Hiệu suất là ưu tiên hàng đầu: Nếu em đang làm một app mà mỗi mili giây đều quý giá, và em muốn áp dụng
ShaderMaskcho rất nhiều element cùng lúc, hãy cẩn thận. Test kỹ hiệu suất trên các thiết bị yếu hơn trước khi 'nhảy' vào. - Khi chỉ cần bo góc đơn giản:
ClipRRectsẽ là lựa chọn tốt hơn nhiều so vớiShaderMasknếu mục đích chỉ là bo tròn các góc của một widget.
- Khi chỉ cần một màu solid: Đừng 'lấy dao mổ trâu giết gà' khi chỉ cần tô một màu đơn giản. Dùng
Tóm lại, ShaderMask là một công cụ cực kỳ mạnh mẽ trong 'kho vũ khí' của một 'dev' Flutter để tạo ra những UI 'đỉnh cao' và có tính thẩm mỹ. Hãy 'nghịch' nó thật nhiều, 'vọc' nó thật kỹ, và em sẽ thấy UI của mình 'lên một tầm cao mới'!
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é!