
Chào các dev tương lai, anh Creyt đây! Hôm nay chúng ta sẽ cùng “mổ xẻ” một cái tên nghe hơi “dài dòng” nhưng lại cực kỳ xịn sò trong Flutter: SliverAnimatedOpacity. Nghe thì có vẻ phức tạp, nhưng thực ra nó chỉ là bậc thầy của nghệ thuật “biến hình” nhẹ nhàng thôi.
SliverAnimatedOpacity là gì mà “cool” vậy?
Để dễ hình dung, các em cứ nghĩ thế này: trong thế giới số, đôi khi chúng ta không muốn một thứ gì đó đột ngột biến mất hay xuất hiện như một cú cắt cảnh “thô bạo” của mấy ông đạo diễn phim hành động hạng B. Chúng ta muốn sự mượt mà, uyển chuyển, như cách một DJ chuyên nghiệp fade out (làm mờ dần) một bản nhạc chứ không phải tắt phụt cái rụp.
SliverAnimatedOpacity chính là cái “bàn DJ” đó, nhưng dành cho các Sliver trong Flutter.
Sliver: Nhớ lại cái bài học vềCustomScrollViewkhông?Sliverlà những mảnh ghép thông minh, linh hoạt để xây dựng các vùng cuộn (scrollable areas) hiệu quả hơn. Nó giống như các “modul” được tối ưu hóa để hiển thị nội dung, đặc biệt là khi danh sách của các em dài dằng dặc như danh sách crush của một hot girl vậy.AnimatedOpacity: Còn cái này thì đơn giản là một cái “công tắc điều chỉnh độ sáng” (dimmer switch) cho bất kỳ widget nào. Em muốn widget mờ đi, rõ lên, cứ đưa cho nó một giá trịopacitytừ 0.0 (trong suốt hoàn toàn) đến 1.0 (rõ nét hoàn toàn), nó sẽ tự động làm mượt mà trong một khoảng thời gian nhất định.
Vậy, SliverAnimatedOpacity chính là sự kết hợp hoàn hảo: nó cho phép các em điều chỉnh độ trong suốt của một Sliver con (một mảnh ghép trong danh sách cuộn) một cách mượt mà, có hiệu ứng chuyển động. Thay vì một cái item trong danh sách cuộn “póc” cái biến mất, nó sẽ từ từ mờ dần đi như một ảo thuật gia đang rút lui khỏi sân khấu vậy.
Để làm gì? Đơn giản là để UI (giao diện người dùng) của các em trông “xịn” hơn, “pro” hơn, và mang lại trải nghiệm người dùng mượt mà, dễ chịu hơn. Nó giúp người dùng cảm thấy ứng dụng của các em “sống động” và “có hồn” hơn.
Code Ví Dụ Minh Hoạ: Màn ảo thuật của Creyt
Giờ thì chúng ta cùng xem cách SliverAnimatedOpacity hoạt động trong thực tế nhé. Anh sẽ làm một ví dụ đơn giản với một danh sách cuộn, và một item đặc biệt có thể “biến hình” mờ dần đi hoặc hiện ra.
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: 'SliverAnimatedOpacity Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const SliverAnimatedOpacityScreen(),
);
}
}
class SliverAnimatedOpacityScreen extends StatefulWidget {
const SliverAnimatedOpacityScreen({super.key});
@override
State<SliverAnimatedOpacityScreen> createState() => _SliverAnimatedOpacityScreenState();
}
class _SliverAnimatedOpacityScreenState extends State<SliverAnimatedOpacityScreen> {
bool _isVisible = true; // Biến để kiểm soát trạng thái hiển thị
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('SliverAnimatedOpacity by Creyt'),
backgroundColor: Colors.deepPurple,
foregroundColor: Colors.white,
),
body: CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
// Chúng ta sẽ làm mờ item thứ 5 (index = 4)
if (index == 4) {
return SliverAnimatedOpacity(
opacity: _isVisible ? 1.0 : 0.0, // Opacity thay đổi dựa vào _isVisible
duration: const Duration(milliseconds: 700), // Thời gian chuyển động
curve: Curves.easeInOut, // Kiểu chuyển động (nhanh dần rồi chậm dần)
sliver: SliverToBoxAdapter( // Bọc widget con vào SliverToBoxAdapter
child: Container(
height: 120,
color: Colors.redAccent.shade100,
margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
alignment: Alignment.center,
child: const Text(
'Tui là item biến hình nè!',
style: TextStyle(color: Colors.deepPurple, fontSize: 20, fontWeight: FontWeight.bold),
),
),
),
);
}
// Các item còn lại của danh sách
return Container(
height: 80,
color: index % 2 == 0 ? Colors.blueGrey[50] : Colors.blueGrey[100],
margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
alignment: Alignment.center,
child: Text(
'Item thứ ${index + 1}',
style: TextStyle(fontSize: 16, color: Colors.blueGrey[800]),
),
);
},
childCount: 20, // Tổng số item trong danh sách
),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_isVisible = !_isVisible; // Đổi trạng thái hiển thị
});
},
backgroundColor: Colors.deepPurple,
child: Icon(
_isVisible ? Icons.visibility_off : Icons.visibility,
color: Colors.white,
),
),
);
}
}
Giải thích nhanh:
- Chúng ta dùng
CustomScrollViewđể chứa cácSliver. - Trong
SliverList, chúng ta tạo ra 20Container. - Đặc biệt,
Containerởindex == 4(tức là item thứ 5) được bọc trongSliverAnimatedOpacity. - Khi nhấn
FloatingActionButton, biến_isVisiblesẽ thay đổi, kéo theoopacitycủaSliverAnimatedOpacitythay đổi từ 1.0 xuống 0.0 (hoặc ngược lại) trong 700ms, tạo hiệu ứng mờ dần/hiện ra.

Mẹo (Best Practices) của Creyt để "hack não" và dùng thực tế
- Thời gian là vàng (và bạc): Chọn
durationcho animation thật hợp lý. Quá nhanh thì người dùng chưa kịp nhận ra hiệu ứng, trông sẽ bị giật. Quá chậm thì họ lại phải chờ đợi, gây khó chịu. Thông thường, 300-700ms là khoảng thời gian “vàng” cho các hiệu ứng mờ dần. - Đừng quên
curve: Thuộc tínhcurvegiúp animation của em có “cảm xúc” hơn.Curves.easeInOutlà lựa chọn an toàn, làm chuyển động bắt đầu và kết thúc nhẹ nhàng.Curves.fastOutSlowIncũng là một lựa chọn tuyệt vời. - Lưu ý quan trọng:
SliverAnimatedOpacitykhông làm mất không gian! Khiopacityvề 0.0, widget con bên trong vẫn chiếm chỗ trong layout. Nó chỉ trong suốt thôi, chứ không phải biến mất hoàn toàn khỏi cây widget. Nếu em muốn nó biến mất hoàn toàn và giải phóng không gian, em cần kết hợp thêm logic khác (ví dụ: dùngVisibilityvớimaintainState: false, maintainAnimation: false, maintainSize: falsehoặc loại bỏ widget đó khỏi cây sau khi animation kết thúc). - Kết hợp sức mạnh:
SliverAnimatedOpacitycó thể kết hợp với cácSliverkhác nhưSliverAppBar,SliverGridđể tạo ra những hiệu ứng phức tạp và đẹp mắt hơn nhiều.
Ứng dụng thực tế: Ai đã dùng "bùa" này?
- Feed mạng xã hội (Facebook, Instagram): Khi em ẩn một bài viết, hoặc khi một thông báo mới xuất hiện, nó thường không “nhảy bổ” vào màn hình mà mờ dần xuất hiện, hoặc mờ dần biến mất khi em tương tác với nó.
- Ứng dụng quản lý tác vụ (Trello, Todoist): Khi em đánh dấu một nhiệm vụ là hoàn thành, thay vì biến mất ngay lập tức, nhiệm vụ đó có thể mờ dần đi, tạo cảm giác “từ từ hoàn tất” chứ không phải “biến mất không dấu vết”.
- E-commerce (Shopee, Lazada): Khi một sản phẩm hết hàng hoặc không còn khả dụng, nó có thể mờ đi một chút để báo hiệu cho người dùng mà không cần loại bỏ hoàn toàn khỏi danh sách sản phẩm.
- Loaders/Placeholders: Khi nội dung thực tế đang tải, một placeholder có thể mờ dần đi để nhường chỗ cho nội dung đã tải xong.
Thử nghiệm và Nên dùng cho case nào?
Anh Creyt đã từng thử nghiệm: Rất nhiều lần! Đặc biệt là khi làm các ứng dụng có danh sách dài và cần tương tác động với các phần tử. Ví dụ, khi người dùng xóa một item khỏi danh sách yêu thích, việc item đó mờ dần rồi biến mất tạo cảm giác tự nhiên và ít gây sốc hơn là “póc” cái item biến mất luôn.
Nên dùng cho case nào?
- Hiển thị/ẩn các thông báo ngắn gọn trong danh sách: Ví dụ, một banner “Bạn có tin nhắn mới” xuất hiện ở đầu danh sách và mờ dần đi sau vài giây.
- Tương tác với các phần tử trong danh sách: Khi người dùng “swipe to dismiss” (vuốt để bỏ qua) một item, nó có thể mờ dần trước khi bị loại bỏ hoàn toàn.
- Thay đổi trạng thái của item: Một item trong danh sách chuyển từ trạng thái “đang xử lý” sang “hoàn thành” có thể có hiệu ứng mờ nhẹ để báo hiệu sự thay đổi.
- Load dữ liệu động: Khi một phần dữ liệu mới được tải vào danh sách cuộn, nó có thể mờ dần xuất hiện.
Không nên dùng đơn độc khi:
- Em muốn widget biến mất hoàn toàn khỏi layout và giải phóng không gian. Trong trường hợp này, hãy kết hợp
SliverAnimatedOpacityvới việc loại bỏ widget khỏi cây sau khi animation kết thúc (ví dụ, dùngAnimatedSwitcherhoặcVisibilityvới các thuộc tínhmaintainlàfalse). - Em cần các loại animation phức tạp hơn như thay đổi kích thước, vị trí, hay xoay. Lúc đó, em sẽ cần đến các widget
SliverAnimatedkhác hoặc tự xây dựng vớiAnimatedBuilder.
Nhớ nhé các dev, animation không chỉ là “làm màu” mà nó còn là một phần quan trọng để tạo ra một trải nghiệm người dùng tuyệt vời. SliverAnimatedOpacity là một trong những công cụ mạnh mẽ giúp các em làm được điều đó. Cứ thực hành đi, rồi các em sẽ thấy nó “nghiện” như thế nào! Hẹn gặp lại trong bài học tiếp theo của anh Creyt!
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é!