Swift Animations for Flutter - Complete Guide to Declarative Animations

Swift Animations for Flutter - Complete Guide to Declarative Animations

3 min read
flutter animations swift ui

Learn how to create SwiftUI-like declarative animations in Flutter with zero boilerplate. No controllers, no ticker providers required!

Introduction

Creating smooth, beautiful animations in Flutter has traditionally required setting up controllers, managing ticker providers, and writing boilerplate code. But what if you could create animations as easily as in SwiftUI?

Swift Animations is a Flutter package that brings SwiftUI-like declarative animations to Flutter. With zero boilerplate and no mixins required, you can create stunning animations with simple, chainable methods.

Quick start (drop-in example)

import 'package:flutter/material.dart';
import 'package:swift_animations/swift_animations.dart';

class Demo extends StatelessWidget {
  const Demo({super.key});

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(width: 120, height: 120, color: Colors.blue)
          .animate()
          .fadeIn()
          .scale(1.2)
          .springIOS(), // smooth spring preset
    );
  }
}

Tip: Keep animations to <300ms for list items; use .springGentle() for UI polish without jank.

Why Swift Animations?

Traditional Flutter Animation Approach

class MyAnimatedWidget extends StatefulWidget {
  @override
  _MyAnimatedWidgetState createState() => _MyAnimatedWidgetState();
}

class _MyAnimatedWidgetState extends State<MyAnimatedWidget> 
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: Duration(milliseconds: 500),
      vsync: this,
    );
    _animation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller);
    _controller.forward();
  }

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

  @override
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: _animation,
      child: Container(
        width: 100,
        height: 100,
        color: Colors.blue,
      ),
    );
  }
}

That’s a lot of code for a simple fade-in animation!

Swift Animations Approach

Container(
  width: 100,
  height: 100,
  color: Colors.blue,
)
  .animate()
  .fadeIn()
  .scale(1.2)
  .duration(500.ms)

That’s it! No controllers, no mixins, no boilerplate.

Installation

Add swift_animations to your pubspec.yaml:

dependencies:
  swift_animations: ^1.2.2

Then run:

flutter pub get

Core Features

Transformations

Scale Animations

Container(
  width: 100,
  height: 100,
  color: Colors.blue,
)
  .animate()
  .scale(1.5)  // Scale to 150%

You can also scale on specific axes:

.animate()
  .scaleX(1.2)  // Scale only on X axis
  .scaleY(0.8)  // Scale only on Y axis

Rotation

.animate()
  .rotate(180)  // Rotate 180 degrees

Opacity Animations

// Fade in from 0 to 1
.animate()
  .fadeIn()

// Fade out from 1 to 0
.animate()
  .fadeOut()

// Custom opacity
.animate()
  .opacity(0.5)  // 50% opacity

Slide Animations

// Slide in from different directions
.animate()
  .slideInTop()
  .slideInBottom()
  .slideInLeft()
  .slideInRight()

// Custom slide values
.animate()
  .slideX(100)  // Slide 100 pixels on X axis
  .slideY(-50)  // Slide -50 pixels on Y axis

Special Effects

Bounce Animation

Container(
  width: 100,
  height: 100,
  color: Colors.purple,
)
  .animate()
  .fadeIn()
  .scale(1.2)
  .bounce()  // Adds bounce effect

Pulse Animation

.animate()
  .fadeIn()
  .pulse()  // Creates pulsing effect

Combined Effects

.animate()
  .fadeInScale(1.3)  // Fade in + scale simultaneously

Spring Physics

One of the most powerful features is spring physics, which creates natural, iOS-like animations.

Pre-configured Springs

// iOS-style snappy spring
.animate()
  .fadeIn()
  .springIOS()

// Gentle spring with smooth bounce
.animate()
  .fadeIn()
  .springGentle()

// Bouncy spring with high bounce
.animate()
  .fadeIn()
  .springBouncy()

Custom Spring

.animate()
  .fadeIn()
  .spring(
    mass: 1.0,           // Mass of the spring
    stiffness: 100.0,    // Stiffness coefficient
    damping: 10.0,       // Damping coefficient
    initialVelocity: 0.0 // Initial velocity
  )

Duration and Timing

Duration Shorthand

Swift Animations provides convenient duration syntax:

.animate()
  .duration(500.ms)    // 500 milliseconds
  .duration(0.5.s)     // 0.5 seconds
  .duration(5.m)       // 5 minutes
  .duration(".500ms")  // String format

Delay

.animate()
  .fadeIn()
  .delay(200.ms)  // Wait 200ms before starting

Custom Curves

.animate()
  .fadeIn()
  .curve(Curves.easeInOut)
  .curve(Curves.bounceOut)

Advanced Patterns

Repeating Animations

// Infinite repeat
.animate()
  .fadeIn()
  .scale(1.2)
  .repeat(reverse: true)  // Reverse on each cycle

// Repeat specific number of times
.animate()
  .fadeIn()
  .repeatCount(3, reverse: true)  // Repeat 3 times

Complex Animation Chain

Container(
  width: 120,
  height: 120,
  decoration: BoxDecoration(
    color: Colors.purple,
    borderRadius: BorderRadius.circular(20),
  ),
)
  .animate()
  .fadeIn()
  .scale(1.2)
  .slideInBottom()
  .rotate(180)
  .duration(1.5.s)
  .curve(Curves.easeInOut)
  .repeat(reverse: true)

Gesture Extensions

Liquid Tap Effects

The sGestureDetector extension adds beautiful liquid tap effects with spring physics:

Container(
  width: 100,
  height: 100,
  color: Colors.blue,
)
  .sGestureDetector(
    onPressed: () => print('Tapped'),
    onLongPress: () => print('Long pressed'),
    scaleOnPress: 1.1,  // Scale amount on tap
    longPressDuration: 500.ms,
  )

Configuration Options

.sGestureDetector(
  onPressed: () {},
  scaleOnPress: 1.15,           // Custom scale
  autoScaleBySize: true,         // Auto-scale based on widget size
  stretchSensitivity: 0.5,       // Stretch effect sensitivity
  translateSensitivity: 0.3,     // Translation sensitivity
)

Swift Animations also provides platform-specific navigation animations:

iOS-Style Navigation

swift.push(NextPage())
  .ios()
  .duration(500)
  .curve(Curves.easeInOut)
  .go(context);

Android-Style Navigation

swift.push(NextPage())
  .android()
  .duration(500)
  .curve(Curves.easeInOut)
  .go(context);

Push Replacement

swift.pushReplacement(HomePage())
  .ios()
  .duration(300)
  .go(context);

Push Named Route

swift.pushNamed('/details')
  .android()
  .duration(400)
  .go(context, arguments: {'id': 123});

Real-World Examples

Loading Indicator

CircularProgressIndicator()
  .animate()
  .fadeIn()
  .rotate(360)
  .repeat(reverse: false)
  .duration(1.s)

Card Entrance Animation

Card(
  child: ListTile(
    title: Text('Item'),
  ),
)
  .animate()
  .fadeIn()
  .slideInRight()
  .duration(300.ms)
  .delay((index * 50).ms)  // Staggered animation

Button Press Animation

ElevatedButton(
  onPressed: () {},
  child: Text('Press Me'),
)
  .sGestureDetector(
    onPressed: () {
      // Handle button press
    },
    scaleOnPress: 0.95,
  )

Best Practices

  1. Use Spring Physics for Natural Feel: Spring animations feel more natural than linear animations
  2. Stagger List Animations: Add delays to create cascading effects
  3. Keep Durations Short: 200-500ms is usually optimal for UI animations
  4. Use Appropriate Curves: Match animation curves to the action (e.g., easeOut for entrances)
  5. Test on Real Devices: Animation performance can vary between devices

Common Issues and Solutions

Animation Not Starting

Problem: Animation doesn’t play when widget appears.

Solution: Ensure the widget is visible when animation should start. Swift Animations automatically detects visibility.

Performance Issues

Problem: Animations are laggy.

Solution:

  • Avoid animating too many widgets simultaneously
  • Use persist() if widget rebuilds frequently
  • Consider using RepaintBoundary for complex widgets

Animation Not Reversing

Problem: repeat(reverse: true) doesn’t reverse.

Solution: Ensure you’re using the correct syntax and that the animation has completed its forward cycle.

Conclusion

Swift Animations brings the simplicity and elegance of SwiftUI animations to Flutter. With zero boilerplate and a clean, chainable API, you can create beautiful animations that enhance your app’s user experience.

Key takeaways:

  • ✅ No controllers or mixins required
  • ✅ Clean, declarative API
  • ✅ Spring physics for natural animations
  • ✅ Platform-specific navigation animations
  • ✅ Gesture extensions for interactive effects

Start using Swift Animations in your next Flutter project and experience the difference!

Resources


Happy Animating!

📚 Recommended Resources

Hardware & Equipment

* Some links are affiliate links. This helps support the blog at no extra cost to you.