SliverAnimatedOpacity: Biến mất mượt mà trong Flutter!
Flutter

SliverAnimatedOpacity: Biến mất mượt mà trong Flutter!

Author

Admin System

@root

Ngày xuất bản

21 Mar, 2026

Lượt xem

7 Lượt

"SliverAnimatedOpacity"

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ề CustomScrollView không? Sliver là 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ị opacity từ 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ác Sliver.
  • Trong SliverList, chúng ta tạo ra 20 Container.
  • Đặc biệt, Containerindex == 4 (tức là item thứ 5) được bọc trong SliverAnimatedOpacity.
  • Khi nhấn FloatingActionButton, biến _isVisible sẽ thay đổi, kéo theo opacity của SliverAnimatedOpacity thay đổ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.
Illustration

Mẹo (Best Practices) của Creyt để "hack não" và dùng thực tế

  1. Thời gian là vàng (và bạc): Chọn duration cho 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.
  2. Đừng quên curve: Thuộc tính curve giúp animation của em có “cảm xúc” hơn. Curves.easeInOut là lựa chọn an toàn, làm chuyển động bắt đầu và kết thúc nhẹ nhàng. Curves.fastOutSlowIn cũng là một lựa chọn tuyệt vời.
  3. Lưu ý quan trọng: SliverAnimatedOpacity không làm mất không gian! Khi opacity về 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ùng Visibility với maintainState: false, maintainAnimation: false, maintainSize: false hoặc loại bỏ widget đó khỏi cây sau khi animation kết thúc).
  4. Kết hợp sức mạnh: SliverAnimatedOpacity có thể kết hợp với các Sliver khá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 SliverAnimatedOpacity với việc loại bỏ widget khỏi cây sau khi animation kết thúc (ví dụ, dùng AnimatedSwitcher hoặc Visibility với các thuộc tính maintainfalse).
  • 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 SliverAnimated khác hoặc tự xây dựng với AnimatedBuilder.

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é!

#tech #cyberpunk #laravel
Chỉnh sửa bài viết

Bình luận (0)

Vui lòng Đăng Nhập để Bình luận

Hỗ trợ Markdown cơ bản
Nguyễn Văn A
1 ngày trước

Tính năng này đỉnh quá ad ơi, chờ mãi mới thấy một blog Tiếng Việt có UI/UX xịn như vầy!