这是indexloc提供的服务,不要输入任何密码

motor 1.0.0-dev.4 copy "motor: ^1.0.0-dev.4" to clipboard
motor: ^1.0.0-dev.4 copied to clipboard

A unified motion system for Flutter - physics-based springs and duration-based curves under one API.

Motor #

Pub Version Coverage lintervention_badge Bluesky

A unified motion system that brings together physics-based springs, duration-based curves, and Flutter's animation system under one consistent API.

Title animation

Features 🎯 #

  • 🎨 Unified Motion API - One consistent interface for springs, curves, and custom motions
  • 💡 Physics & Duration Based - Choose between spring physics or traditional duration/curve animations
  • 🍎 Apple Design System - Built-in CupertinoMotion presets matching iOS animations
  • 🎨 Material Design 3 - MaterialSpringMotion tokens following Google's motion guidelines
  • 📱 Multi-dimensional - Animate complex types like Offset, Size, and Rect with independent physics per dimension
  • 🔄 Interactive Widgets - Motion-driven draggable widgets with natural return animations
  • 🎯 Flutter Integration - Works seamlessly with existing Flutter animation patterns

Try it out #

Open Example

Installation 💻 #

❗ In order to start using Motor you must have the Dart SDK installed on your machine.

Add to your pubspec.yaml:

dependencies:
  motor: ^1.0.0-dev.0

Or install via dart pub:

dart pub add motor

Usage 💡 #

Motion #

The core of Motor's unified motion system is the Motion class. It represents the type of motion that will drive your animation, whether physics-based or duration-based.

// Duration-based motion (traditional Flutter approach)
final linear = LinearMotion(Duration(seconds: 1));

final withCurve = CurvedMotion(
  duration: Duration(seconds: 1), 
  curve: Curves.easeInOut,
);

// Physics-based motion (natural, responsive)
final spring = CupertinoMotion.bouncy();
final material = MaterialSpringMotion.standardSpatialDefault;

Motor provides several motion types out of the box, with the ability to create custom motions by implementing the Motion interface:

  • CurvedMotion - Traditional duration-based motion with curves. Perfect for predictable, timed animations.
  • LinearMotion - Like CurvedMotion but always linear.
  • SpringMotion - Physics-based motion using Flutter SDK's SpringDescription. Provides natural, responsive animations that feel alive.
  • CupertinoMotion - Predefined spring configurations matching Apple's design system.
  • MaterialSpringMotion - Material Design 3 spring motion tokens for expressive animations.

This unified approach means you can easily switch between physics and duration-based animations without changing your widget code.

CupertinoMotion #

CupertinoMotion is a subclass of SpringMotion that provides predefined spring configurations matching Apple's design system. These motions are designed to feel natural and familiar to iOS users, as they mirror the spring animations used throughout Apple's platforms.

CupertinoMotion offers several predefined constants that correspond to SwiftUI's animation presets:

  • CupertinoMotion() - The default iOS spring with smooth motion and no bounce
  • CupertinoMotion.smooth() - A smooth spring animation with no bounce, ideal for subtle transitions
  • CupertinoMotion.bouncy() - A bouncy spring with higher bounce, perfect for playful interactions
  • CupertinoMotion.snappy() - A snappy spring with small bounce that feels responsive
  • CupertinoMotion.interactive() - An interactive spring with lower response, designed for user-driven animations

You can also create custom CupertinoMotion instances:

final customMotion = CupertinoMotion(
  duration: Duration(milliseconds: 600),
  bounce: 0.3,
);

Since CupertinoMotion extends SpringMotion (which extends Motion), you can use it directly wherever a Motion is expected.

MaterialSpringMotion #

MaterialSpringMotion provides Material Design 3 spring motion tokens for creating expressive and natural animations that follow Google's design guidelines. The tokens are organized into two main categories with three speed variants each:

Spatial Motion - For animating position, size, and layout changes:

  • MaterialSpringMotion.standardSpatialFast - Quick spatial animations (damping: 0.9, stiffness: 1400)
  • MaterialSpringMotion.standardSpatialDefault - Balanced spatial animations (damping: 0.9, stiffness: 700)
  • MaterialSpringMotion.standardSpatialSlow - Gentle spatial animations (damping: 0.9, stiffness: 300)
  • MaterialSpringMotion.expressiveSpatialFast - Dynamic spatial with bounce (damping: 0.6, stiffness: 800)
  • MaterialSpringMotion.expressiveSpatialDefault - Moderate expressive spatial (damping: 0.8, stiffness: 380)
  • MaterialSpringMotion.expressiveSpatialSlow - Gentle expressive spatial (damping: 0.8, stiffness: 200)

Effects Motion - For animating visual properties like opacity and color:

  • MaterialSpringMotion.standardEffectsFast - Quick effects animations (damping: 1, stiffness: 3800)
  • MaterialSpringMotion.standardEffectsDefault - Balanced effects animations (damping: 1, stiffness: 1600)
  • MaterialSpringMotion.standardEffectsSlow - Gentle effects animations (damping: 1, stiffness: 800)
  • MaterialSpringMotion.expressiveEffectsFast - Quick expressive effects (damping: 1, stiffness: 3800)
  • MaterialSpringMotion.expressiveEffectsDefault - Moderate expressive effects (damping: 1, stiffness: 1600)
  • MaterialSpringMotion.expressiveEffectsSlow - Gentle expressive effects (damping: 1, stiffness: 800)

You can also create custom MaterialSpringMotion instances:

final customMaterial = MaterialSpringMotion(
  damping: 0.8,
  stiffness: 500,
);

These motion tokens follow the Material Design 3 Motion Guidelines and are designed to create consistent, expressive animations across Material Design applications.

Simple Animation #

Use SingleMotionBuilder for basic, one-dimensional animations:

1D Hover example gif

SingleMotionBuilder(
  motion: CupertinoMotion.bouncy(),
  value: targetValue, // Changes trigger smooth spring animation
  builder: (context, value, child) {
    return Container(
      width: value,
      height: value,
      color: Colors.blue,
    );
  },
)

If you want to animate more complex types, such as Offset, Size, or Rect, you can use MotionBuilder and pass a so-called MotionConverter to it:

2D Redirection example gif

MotionBuilder(
  motion: CupertinoMotion.bouncy(),
  value: const Offset(100, 100),
  from: Offset.zero,
  converter: OffsetMotionConverter(),
  builder: (context, value, child) {
    return Transform.translate(
      offset: value,
      child: child,
    );
  },
  child: Container(
    width: 100,
    height: 100,
    color: Colors.blue,
  ),
)

For Material Design applications, you can use MaterialSpringMotion tokens:

MotionBuilder(
  motion: MaterialSpringMotion.expressiveSpatialDefault,
  value: const Offset(100, 100),
  from: Offset.zero,
  converter: OffsetMotionConverter(),
  builder: (context, value, child) {
    return Transform.translate(
      offset: value,
      child: child,
    );
  },
  child: Container(
    width: 100,
    height: 100,
    color: Colors.green,
  ),
)

MotionConverter #

One of Motor's key advantages is its ability to animate complex types with independent motion per dimension. While Flutter's basic animation system typically uses single animations with Tweens, Motor's unified motion system can simulate each dimension independently.

This is crucial for natural-feeling animations. For example, when animating a draggable icon, the user might fling it horizontally (high horizontal velocity) while it settles vertically (low vertical velocity). Traditional single-animation approaches would lose this dimensional independence, making the motion feel artificial.

MotionConverters solve this by breaking any type into multiple dimensions, allowing each dimension to follow the same motion pattern but with independent physics simulation.

This works with any motion type - whether you're using spring physics or duration-based curves, each dimension animates independently for maximum fidelity.

For often-used Flutter types, these are already implemented:

  • OffsetMotionConverter
  • SizeMotionConverter
  • RectMotionConverter
  • AlignmentMotionConverter

However, you might want your very custom type to be animated as well. For this, you can implement your own MotionConverter and pass it to the MotionBuilder constructor.

class My3DMotionConverter implements MotionConverter<Vector3> {
  @override
  List<double> normalize(Vector3 value) => [value.x, value.y, value.z];

  @override
  Vector3 denormalize(List<double> values) => Vector3(values[0], values[1], values[2]);
}

Widget build(BuildContext context) {
  return MotionBuilder(
    motion: CupertinoMotion.bouncy(),
    value: Vector3(100, 100, 100),
    converter: My3DMotionConverter(),
    // ...
  );
}

Or, just use MotionConverter directly and pass the converter functions to its constructor:

final converter = MotionConverter(
  normalize: (value) => [value.x, value.y, value.z],
  denormalize: (values) => Vector3(values[0], values[1], values[2]),
);

Motion Draggable #

Motor includes a MotionDraggable widget that demonstrates the power of the unified motion system. You can drag widgets around the screen and watch them return with any motion type - from bouncy springs to smooth curves.

It works just like Flutter's Draggable widget and supports native DragTargets, but with motion-driven return animations and enhanced physics simulation.

Spring Draggable example gif

MotionDraggable(
  motion: CupertinoMotion.bouncy(),
  child: Container(
    width: 100,
    height: 100,
    color: Colors.blue,
  ),
  data: 'my-draggable-data',
)

Low-level Motion Control #

For maximum control, Motor provides MotionController for complex types and SingleMotionController for one-dimensional animations. These controllers work with any motion type in the unified system.

final controller = MotionController(
  motion: CupertinoMotion.bouncy(), // or Motion.duration(), etc.
  vsync: this,
);

Motion controllers work similarly to Flutter's AnimationController but with key advantages:

  • Motion-agnostic: Switch between springs and curves without changing controller code
  • Velocity preservation: Maintains velocity when changing targets (crucial for natural motion)
  • Multi-dimensional: Each dimension can have independent physics simulation

Bounded vs. Unbounded Motion

In Flutter, the AnimationController can be either bounded or unbounded. MotionControllers come in both flavors as well, but they differ in key ways:

MotionController:
  • By default, MotionControllers are unbounded.
  • Unbounded MotionControllers don't have forward or reverse methods, since they don't make sense in multi-dimensional space.
BoundedMotionController:
  • requires you to specify a lowerBound and upperBound in the constructor.
  • exposes forward and reverse methods, which internally animate towards the upperBound and lowerBound respectively.
  • will clamp the animation value to be within the bounds, but they can still overshoot as part of their Motion simulation.

Custom Springs 🔧 #

For predefined spring configurations, see the CupertinoMotion section above.

You can also create completely custom springs:

// Using CupertinoMotion constructor
final mySpring = CupertinoMotion(
  duration: Duration(milliseconds: 500),
  bounce: 0.2,   // Bounce amount (-1 to 1)
);

// Or using Flutter SDK's SpringDescription directly
final customSpring = SpringMotion(
  SpringDescription.withDurationAndBounce(
    duration: Duration(milliseconds: 500),
    bounce: 0.2,
  ),
);

Acknowledgements #

Motor's unified motion system builds upon excellent work from the Flutter community:

  • Spring physics implementation was partially adapted from and heavily inspired by fluid_animations
  • CupertinoMotion presets are designed to match Apple's SwiftUI animation system
  • The Motion abstraction unifies concepts from Flutter's animation framework with modern physics-based approaches
33
likes
150
points
803
downloads

Publisher

verified publisherwhynotmake.it

Weekly Downloads

A unified motion system for Flutter - physics-based springs and duration-based curves under one API.

Homepage
Repository (GitHub)
View/report issues

Topics

#animation #motion #physics #spring #curve

Documentation

API reference

License

MIT (license)

Dependencies

flutter, meta

More

Packages that depend on motor