~/icsd.ir — bash
SYSTEM_ONLINE

انیمیشن‌ها

انیمیشن‌ها UX را به طور قابل‌توجهی بهبود می‌دهند. Flutter ابزارهای قدرتمندی برای انیمیشن دارد — از ساده (Implicit) تا پیچیده (Explicit، Custom).

۱۰.۱ مقدمه

انیمیشن‌ها UX را به طور قابل‌توجهی بهبود می‌دهند. Flutter ابزارهای قدرتمندی برای انیمیشن دارد — از ساده (Implicit) تا پیچیده (Explicit، Custom).

۱۰.۲ Implicit Animations — ساده‌ترین

Widget هایی که با تغییر property به‌صورت خودکار انیمیشن می‌سازند. شروع همه با Animated.


// AnimatedContainer — همه چیز را animate می‌کند
class AnimatedBox extends StatefulWidget {
  @override
  State createState() => _AnimatedBoxState();
}

class _AnimatedBoxState extends State {
  bool _expanded = false;
  
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => setState(() => _expanded = !_expanded),
      child: AnimatedContainer(
        duration: const Duration(milliseconds: 300),
        curve: Curves.easeInOut,
        width: _expanded ? 300 : 100,
        height: _expanded ? 200 : 100,
        decoration: BoxDecoration(
          color: _expanded ? Colors.blue : Colors.red,
          borderRadius: BorderRadius.circular(_expanded ? 50 : 8),
        ),
        child: const Center(child: Text("کلیک کنید")),
      ),
    );
  }
}

// AnimatedOpacity
AnimatedOpacity(
  duration: const Duration(milliseconds: 500),
  opacity: _visible ? 1.0 : 0.0,
  child: const Text("Fade in/out"),
)

// AnimatedPositioned (در Stack)
Stack(
  children: [
    AnimatedPositioned(
      duration: const Duration(milliseconds: 300),
      top: _moved ? 100 : 50,
      left: _moved ? 200 : 50,
      child: Container(width: 50, height: 50, color: Colors.blue),
    ),
  ],
)

// AnimatedSwitcher (تغییر بین widget ها)
AnimatedSwitcher(
  duration: const Duration(milliseconds: 300),
  child: Text(
    "$_count",
    key: ValueKey(_count),  // ⭐ key لازم برای detect تغییر
    style: const TextStyle(fontSize: 32),
  ),
)

// سایر Implicit widgets:
// AnimatedAlign, AnimatedPadding, AnimatedDefaultTextStyle,
// AnimatedCrossFade, AnimatedIcon, AnimatedSize, AnimatedRotation, AnimatedScale
    

TweenAnimationBuilder — سفارشی‌سازی


TweenAnimationBuilder(
  duration: const Duration(seconds: 1),
  tween: Tween(begin: 0, end: 1),
  builder: (context, value, child) {
    return Opacity(
      opacity: value,
      child: Transform.scale(
        scale: value,
        child: child,
      ),
    );
  },
  child: const Text("FadeIn + ScaleIn"),
)

// Tween در رنگ
TweenAnimationBuilder(
  duration: const Duration(seconds: 2),
  tween: ColorTween(begin: Colors.red, end: Colors.blue),
  builder: (context, color, _) => Container(color: color, width: 100, height: 100),
)
    

۱۰.۳ Explicit Animations — کنترل کامل


class FadeInWidget extends StatefulWidget {
  @override
  State createState() => _FadeInWidgetState();
}

class _FadeInWidgetState extends State
    with SingleTickerProviderStateMixin {  // ⭐ Mixin لازم
  late AnimationController _controller;
  late Animation _animation;
  
  @override
  void initState() {
    super.initState();
    
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    );
    
    _animation = CurvedAnimation(
      parent: _controller,
      curve: Curves.easeInOut,
    );
    
    _controller.forward();  // start
  }
  
  @override
  void dispose() {
    _controller.dispose();  // ⚠️ مهم
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: _animation,
      child: const Text("Fade in"),
    );
  }
}
    

کنترل دستی


_controller.forward();              // 0 → 1
_controller.reverse();              // 1 → 0
_controller.repeat();               // loop
_controller.repeat(reverse: true);  // 0→1→0→1...
_controller.stop();
_controller.reset();
_controller.value = 0.5;            // مستقیم

// Listen to value
_controller.addListener(() {
  print(_controller.value);
});

// Listen to status
_controller.addStatusListener((status) {
  if (status == AnimationStatus.completed) {
    print("done!");
  }
});
    

Animation Widgets


// FadeTransition
FadeTransition(opacity: animation, child: ...)

// SlideTransition
SlideTransition(
  position: Tween(
    begin: const Offset(-1, 0),  // از سمت چپ
    end: Offset.zero,
  ).animate(_controller),
  child: ...,
)

// ScaleTransition
ScaleTransition(scale: animation, child: ...)

// RotationTransition
RotationTransition(turns: animation, child: ...)

// SizeTransition
SizeTransition(sizeFactor: animation, child: ...)

// AnimatedBuilder — برای custom
AnimatedBuilder(
  animation: _controller,
  builder: (context, child) {
    return Transform.rotate(
      angle: _controller.value * 2 * pi,
      child: child,
    );
  },
  child: const FlutterLogo(size: 100),
)
    

۱۰.۴ Curves

Curve منحنی speed انیمیشن را تعیین می‌کند.

  • Curves.linear — یکنواخت
  • Curves.easeIn — آرام شروع، سریع پایان
  • Curves.easeOut — سریع شروع، آرام پایان
  • Curves.easeInOut — هر دو
  • Curves.bounceOut — جهش در پایان
  • Curves.elasticOut — کش‌سان
  • Curves.fastOutSlowIn — Material استاندارد

Custom Cubic


const Cubic(0.25, 0.1, 0.25, 1.0)  // مثل CSS cubic-bezier
    

۱۰.۵ Hero Animation

(از فصل ۵) — انیمیشن یک widget بین دو صفحه.


// در صفحه ۱
Hero(
  tag: "product-1",
  child: Image.network("..."),
)

// در صفحه ۲ (همان tag)
Hero(
  tag: "product-1",
  child: Image.network("..."),
)
    

۱۰.۶ Staggered Animations

چند animation که در زمان‌های مختلف شروع می‌شوند.


class StaggeredDemo extends StatefulWidget {
  @override
  State createState() => _StaggeredDemoState();
}

class _StaggeredDemoState extends State
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation _opacity;
  late Animation _scale;
  late Animation _slide;
  
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    );
    
    // 0% - 33% : Opacity
    _opacity = Tween(begin: 0, end: 1).animate(
      CurvedAnimation(
        parent: _controller,
        curve: const Interval(0.0, 0.33, curve: Curves.easeIn),
      ),
    );
    
    // 33% - 66% : Scale
    _scale = Tween(begin: 0.5, end: 1.0).animate(
      CurvedAnimation(
        parent: _controller,
        curve: const Interval(0.33, 0.66, curve: Curves.easeOut),
      ),
    );
    
    // 66% - 100% : Slide
    _slide = Tween(begin: const Offset(0, 0.5), end: Offset.zero).animate(
      CurvedAnimation(
        parent: _controller,
        curve: const Interval(0.66, 1.0, curve: Curves.easeOut),
      ),
    );
    
    _controller.forward();
  }
  
  @override
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: _opacity,
      child: ScaleTransition(
        scale: _scale,
        child: SlideTransition(
          position: _slide,
          child: const Card(child: Padding(
            padding: EdgeInsets.all(20),
            child: Text("Staggered"),
          )),
        ),
      ),
    );
  }
}
    

۱۰.۷ Lottie و Rive

Lottie — انیمیشن‌های After Effects


flutter pub add lottie
    

import "package:lottie/lottie.dart";

// از asset
Lottie.asset("assets/animations/loading.json")

// از URL
Lottie.network("https://assets.lottiefiles.com/...")

// با controller
class LottieDemo extends StatefulWidget {
  @override
  State createState() => _LottieDemoState();
}

class _LottieDemoState extends State
    with TickerProviderStateMixin {
  late final AnimationController _controller;
  
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this);
  }
  
  @override
  Widget build(BuildContext context) {
    return Lottie.asset(
      "assets/animations/like.json",
      controller: _controller,
      onLoaded: (composition) {
        _controller
          ..duration = composition.duration
          ..forward();
      },
    );
  }
  
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

// انیمیشن‌های رایگان: lottiefiles.com
    

Rive — انیمیشن‌های تعاملی


flutter pub add rive
    

import "package:rive/rive.dart";

RiveAnimation.asset("assets/animations/character.riv")

// با state machine
StateMachineController? _controller;
SMITrigger? _bumpTrigger;

void _onRiveInit(Artboard artboard) {
  _controller = StateMachineController.fromArtboard(artboard, "State Machine 1");
  artboard.addController(_controller!);
  _bumpTrigger = _controller!.findInput("bump") as SMITrigger;
}

ElevatedButton(
  onPressed: () => _bumpTrigger?.fire(),
  child: const Text("Bump!"),
)
    

۱۰.۸ Page Transitions سفارشی


// با go_router
GoRoute(
  path: "/profile",
  pageBuilder: (context, state) {
    return CustomTransitionPage(
      key: state.pageKey,
      child: const ProfilePage(),
      transitionsBuilder: (_, animation, __, child) {
        return SlideTransition(
          position: Tween(
            begin: const Offset(1, 0),
            end: Offset.zero,
          ).animate(animation),
          child: child,
        );
      },
    );
  },
)

// با Navigator
Navigator.push(
  context,
  PageRouteBuilder(
    pageBuilder: (_, animation, __) => const NextPage(),
    transitionsBuilder: (_, animation, __, child) {
      return FadeTransition(opacity: animation, child: child);
    },
    transitionDuration: const Duration(milliseconds: 500),
  ),
)
    

۱۰.۹ animate_do — انیمیشن سریع

پکیج ساده با انیمیشن‌های آماده شبیه Animate.css.


flutter pub add animate_do
    

import "package:animate_do/animate_do.dart";

FadeIn(child: Text("سلام"))
FadeInUp(child: Text("از پایین"))
SlideInLeft(child: Text("از چپ"))
ZoomIn(child: Icon(Icons.star))
Bounce(child: Image.asset("..."))
Pulse(infinite: true, child: Icon(Icons.favorite))

// با delay و duration
FadeInUp(
  delay: const Duration(milliseconds: 200),
  duration: const Duration(milliseconds: 800),
  child: const Text("..."),
)
    

۱۰.۱۰ بهترین تجربیات

  1. Implicit برای ساده. Explicit برای کنترل.
  2. dispose AnimationController. همیشه.
  3. Curve مناسب. easeInOut برای اکثر موارد.
  4. Duration کوتاه. 200-500ms معمولاً کافی است.
  5. RepaintBoundary. برای performance.
  6. const widgets. در child که animate نمی‌شود.
  7. Hero با tag unique.
  8. Lottie برای splash screen.
  9. تست با Flutter Inspector. Slow Animations.
  10. کاربر را اذیت نکنید. انیمیشن کمکی، نه آزاردهنده.

۱۰.۱۱ خلاصه فصل

  • Implicit Animations: AnimatedContainer، AnimatedOpacity
  • Explicit Animations با AnimationController
  • Curves برای کنترل speed
  • Hero animations
  • Staggered animations با Interval
  • Lottie و Rive برای انیمیشن پیشرفته
  • Page transitions سفارشی
  • animate_do برای سرعت توسعه
در فصل بعد: قابلیت‌های Platform — Camera، Notification، Permission.

نمایش سایت

رنگ سایت
حالت نمایش
اندازهٔ متن
خوانایی

این تنظیمات فقط روی مرورگر شما ذخیره می‌شود.