TweenSequenceItem: Hoạt hình Flutter đa chặng, mượt mà như lụa!
Flutter

TweenSequenceItem: Hoạt hình Flutter đa chặng, mượt mà như lụa!

Author

Admin System

@root

Ngày xuất bản

23 Mar, 2026

Lượt xem

1 Lượt

"TweenSequenceItem"

Chào mấy đứa "coder hệ Gen Z"! Hôm nay, "giảng viên Creyt" của mấy đứa sẽ "mổ xẻ" một "bí kíp" cực "chất" trong Flutter để tạo ra những hoạt ảnh (animation) "mượt như bơ", đó chính là TweenSequenceItem. Nghe cái tên thì hơi "khoa học viễn tưởng" một tí, nhưng mà "đảm bảo" sau bài này, mấy đứa sẽ "phê" với những gì nó làm được!

1. TweenSequenceItem là "cái vẹo" gì và để làm gì?

"Thôi được rồi, vào thẳng vấn đề luôn cho "nóng"! Mấy đứa cứ hình dung thế này: Khi mấy đứa muốn "thả thính" một đối tượng nào đó, đâu phải lúc nào cũng "tấn công" một kiểu từ đầu đến cuối đúng không? Lúc thì "nhẹ nhàng", lúc thì "mạnh bạo", lúc lại "lùi một bước tiến ba bước". TweenSequenceItem trong Flutter nó cũng y chang vậy đó!

Nó không phải là một hoạt ảnh độc lập, mà là một "chặng" trong một "chuỗi hành trình" hoạt ảnh lớn hơn (mà cái hành trình lớn đó gọi là TweenSequence). Mỗi TweenSequenceItem giống như một "người chạy tiếp sức" trong đường đua animation vậy. Mỗi người có một quãng đường (được định nghĩa bằng weight) và một phong cách chạy (được định nghĩa bằng tweencurve) riêng. Khi các "người chạy" này kết hợp lại, chúng ta sẽ có một "đoạn phim" hoạt ảnh liền mạch, có nhiều "phân cảnh" khác nhau.

Để làm gì ư? Đơn giản là để mấy đứa tạo ra những animation "phức tạp hóa" mà không phải "vật lộn" với việc tính toán thời gian thủ công hay tạo ra quá nhiều AnimationController. Ví dụ, mấy đứa muốn một cái nút ban đầu màu đỏ, sau đó từ từ chuyển sang vàng, rồi nhanh chóng đổi sang xanh lá, và cuối cùng "nháy" một cái thành xanh dương. Nếu không có TweenSequenceItem, mấy đứa sẽ phải "hack não" lắm đó!

2. Code Ví Dụ Minh Họa: "Thấy tận mắt, sờ tận tay"

"Giờ thì "lý thuyết suông" đủ rồi, "xắn tay áo" vào "thực hành" thôi! Anh sẽ cho mấy đứa xem cách một cái hộp đổi màu "thần kỳ" qua nhiều giai đoạn khác nhau nhé. "Đảm bảo" dễ hiểu hơn "người yêu cũ" của mấy đứa luôn!"

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: 'TweenSequenceItem Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const TweenSequenceItemExample(),
    );
  }
}

class TweenSequenceItemExample extends StatefulWidget {
  const TweenSequenceItemExample({super.key});

  @override
  _TweenSequenceItemExampleState createState() =>
      _TweenSequenceItemExampleState();
}

class _TweenSequenceItemExampleState extends State<TweenSequenceItemExample>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<Color?> _colorAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 4), // Tổng thời gian của toàn bộ sequence
      vsync: this,
    );

    // Đây là "trái tim" của chúng ta: TweenSequence chứa các TweenSequenceItem!
    _colorAnimation = TweenSequence<Color?>([
      // Chặng 1: Đỏ -> Vàng (chiếm 25% tổng thời gian, tức 1 giây)
      TweenSequenceItem(
        tween: ColorTween(begin: Colors.red, end: Colors.yellow).chain(CurveTween(curve: Curves.easeIn)),
        weight: 0.25, 
      ),
      // Chặng 2: Vàng -> Xanh lá (chiếm 50% tổng thời gian, tức 2 giây)
      TweenSequenceItem(
        tween: ColorTween(begin: Colors.yellow, end: Colors.green).chain(CurveTween(curve: Curves.bounceOut)),
        weight: 0.5,
      ),
      // Chặng 3: Xanh lá -> Xanh dương (chiếm 25% tổng thời gian, tức 1 giây)
      TweenSequenceItem(
        tween: ColorTween(begin: Colors.green, end: Colors.blue).chain(CurveTween(curve: Curves.fastOutSlowIn)),
        weight: 0.25,
      ),
    ]).animate(_controller);

    _controller.repeat(reverse: true); // Lặp lại animation, đi tới rồi đi lui
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("TweenSequenceItem Demo")), 
      body: Center(
        child: AnimatedBuilder(
          animation: _colorAnimation,
          builder: (context, child) {
            return Container(
              width: 200,
              height: 200,
              color: _colorAnimation.value, // Màu của container sẽ thay đổi theo animation
              child: const Center(
                child: Text(
                  "Màu sắc chuyển đổi",
                  style: TextStyle(color: Colors.white, fontSize: 18),
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

"Mấy đứa thấy không? Chỉ cần định nghĩa các TweenSequenceItem với tween (giá trị bắt đầu và kết thúc của chặng đó) và weight (độ dài của chặng đó so với tổng thời gian), "phép thuật" sẽ tự động xảy ra! Anh đã thêm chain(CurveTween(curve: ...)) vào mỗi tween để mỗi chặng có một "cảm xúc" riêng đó."

Illustration

3. Mẹo "hack não" và "chiến thuật" thực tế từ "Creyt"

"Để mấy đứa "nâng tầm" kỹ năng animation của mình, "giảng viên Creyt" có vài "bí kíp" muốn "truyền thụ" đây:

  • weight là "trọng số", không phải "thời gian tuyệt đối": Nhớ kỹ điều này nhé! weight là tỉ lệ phần trăm của tổng thời lượng animation. Tổng weight của tất cả TweenSequenceItem phải bằng 1.0. Nếu tổng lớn hơn hoặc nhỏ hơn 1.0, Flutter sẽ tự điều chỉnh để phù hợp. Ví dụ, nếu tổng là 0.5, thì 0.25 sẽ chiếm 50% của tổng thời gian animation.
  • Mỗi Item một "cá tính" riêng: Đừng ngại "custom" mỗi TweenSequenceItem với một Curve khác nhau. Điều này giúp animation của mấy đứa trông "sống động" và "có hồn" hơn nhiều. Ví dụ, một chặng thì Curves.easeIn, chặng sau lại Curves.bounceOut để tạo hiệu ứng "nhảy bật".
  • "Mix & Match" các loại Tween: Mấy đứa không chỉ giới hạn ở ColorTween đâu nhé. Có thể dùng SizeTween, RectTween, AlignmentTween, hay thậm chí Tween<double> để điều khiển bất cứ thứ gì có thể "tween" được. "Sáng tạo" lên!
  • chain() là "cầu nối": Để thêm Curve vào một Tween trong TweenSequenceItem, mấy đứa sẽ dùng .chain(CurveTween(curve: yourCurve)). Nó giúp "kết nối" Curve với Tween một cách "mượt mà" nhất.

4. "Ứng dụng thực tế" – Khi "code" không chỉ là "code"

"Mấy đứa nghĩ "animation" chỉ để "làm màu" thôi à? "Sai lầm" rồi đó! TweenSequenceItem được ứng dụng "rộng rãi" trong rất nhiều app "xịn xò" mà mấy đứa đang dùng hàng ngày:

  • Màn hình Loading/Splash Screen: Các hiệu ứng logo "xuất hiện", "biến mất" hoặc "nhảy múa" theo nhiều giai đoạn khác nhau để giữ chân người dùng trong lúc chờ đợi.
  • Onboarding App: Các hiệu ứng chuyển động của các thành phần UI khi giới thiệu tính năng mới, thường là các icon "bay lượn", text "xuất hiện" dần dần theo từng bước.
  • Game UI/UX: Khi một vật phẩm "rơi xuống", "nảy lên" rồi "biến mất", hoặc các hiệu ứng khi nâng cấp đồ vật, mở khóa tính năng.
  • Ứng dụng "e-commerce" (mua sắm online): Hiệu ứng khi thêm sản phẩm vào giỏ hàng, nút "thêm vào giỏ" có thể "nhảy" một cái, rồi "phóng to" ra, rồi "biến mất" vào giỏ hàng.
  • Mạng xã hội (ví dụ TikTok, Instagram): Các hiệu ứng chuyển cảnh giữa các Story, hoặc khi tương tác với nút Like/Share có thể có nhiều trạng thái chuyển động.

5. "Thử nghiệm đã từng" và "nên dùng cho case nào"

"Anh Creyt" đã từng "đau đầu" với việc tạo animation phức tạp bằng cách nối thủ công từng Tween một. Nó giống như việc "xây nhà" bằng cách "từng viên gạch" mà không có "bản thiết kế" vậy. Kết quả là "code" thì "rối như tơ vò", "maintain" thì "khó như lên trời", và "bug" thì "nhiều như quân Nguyên"!

Nên dùng TweenSequenceItem khi:

  • Mấy đứa cần một chuỗi hoạt ảnh có nhiều giai đoạn riêng biệt, mỗi giai đoạn có tốc độ, đường cong (curve) hoặc giá trị bắt đầu/kết thúc khác nhau.
  • Mấy đứa muốn kiểm soát chặt chẽ tỉ lệ thời gian của từng phần trong tổng thể animation.
  • Mấy đứa muốn tạo ra animation "liền mạch" và "mượt mà" qua nhiều trạng thái mà không cần phải quản lý nhiều AnimationController riêng lẻ.

Không nên dùng TweenSequenceItem khi:

  • Chỉ cần một animation đơn giản từ A đến B (ví dụ: một cái nút chỉ cần "phóng to" rồi "thu nhỏ"). Lúc này, dùng một TweenAnimationController thông thường là đủ, không cần "đao to búa lớn".

"Tóm lại, TweenSequenceItem là một công cụ "đắc lực" giúp mấy đứa "làm chủ" thế giới animation "đầy màu sắc" của Flutter. Hãy "thử nghiệm" và "sáng tạo" với nó nhé! Chúc mấy đứa "code" vui vẻ và "lên trình" vù vù!"

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!