@@ -43,6 +43,44 @@ class SpringDescription {
4343 double ratio = 1.0 ,
4444 }) : damping = ratio * 2.0 * math.sqrt (mass * stiffness);
4545
46+ /// Creates a [SpringDescription] based on a desired animation duration and
47+ /// bounce.
48+ ///
49+ /// This provides an intuitive way to define a spring based on its visual
50+ /// properties, [duration] and [bounce] . Check the properties' documentation
51+ /// for their definition.
52+ ///
53+ /// This constructor produces the same result as SwiftUI's
54+ /// `spring(duration:bounce:blendDuration:)` animation.
55+ ///
56+ /// {@tool snippet}
57+ /// ```dart
58+ /// final SpringDescription spring = SpringDescription.withDurationAndBounce(
59+ /// duration: const Duration(milliseconds: 300),
60+ /// bounce: 0.3,
61+ /// );
62+ /// ```
63+ /// {@end-tool}
64+ ///
65+ /// See also:
66+ /// * [SpringDescription] , which creates a spring by explicitly providing
67+ /// physical parameters.
68+ /// * [SpringDescription.withDampingRatio] , which creates a spring with a
69+ /// damping ratio and other physical parameters.
70+ factory SpringDescription .withDurationAndBounce ({
71+ Duration duration = const Duration (milliseconds: 500 ),
72+ double bounce = 0.0 ,
73+ }) {
74+ assert (duration.inMilliseconds > 0 , 'Duration must be positive' );
75+ final double durationInSeconds = duration.inMilliseconds / Duration .millisecondsPerSecond;
76+ const double mass = 1.0 ;
77+ final double stiffness = (4 * math.pi * math.pi * mass) / math.pow (durationInSeconds, 2 );
78+ final double dampingRatio = bounce > 0 ? (1.0 - bounce) : (1 / (bounce + 1 ));
79+ final double damping = dampingRatio * 2.0 * math.sqrt (mass * stiffness);
80+
81+ return SpringDescription (mass: mass, stiffness: stiffness, damping: damping);
82+ }
83+
4684 /// The mass of the spring (m).
4785 ///
4886 /// The units are arbitrary, but all springs within a system should use
@@ -78,6 +116,43 @@ class SpringDescription {
78116 /// driving the [SpringSimulation] .
79117 final double damping;
80118
119+ /// The duration parameter used in [SpringDescription.withDurationAndBounce] .
120+ ///
121+ /// This value defines the perceptual duration of the spring, controlling
122+ /// its overall pace. It is approximately equal to the time it takes for
123+ /// the spring to settle, but for highly bouncy springs, it instead
124+ /// corresponds to the oscillation period.
125+ ///
126+ /// This duration does not represent the exact time for the spring to stop
127+ /// moving. For example, when [bounce] is 1, the spring oscillates
128+ /// indefinitely, even though [duration] has a finite value. To determine
129+ /// when the motion has effectively stopped within a certain tolerance,
130+ /// use [SpringSimulation.isDone] .
131+ ///
132+ /// Defaults to 0.5 seconds.
133+ Duration get duration {
134+ final double durationInSeconds = math.sqrt ((4 * math.pi * math.pi * mass) / stiffness);
135+ final int milliseconds = (durationInSeconds * Duration .millisecondsPerSecond).round ();
136+ return Duration (milliseconds: milliseconds);
137+ }
138+
139+ /// The bounce parameter used in [SpringDescription.withDurationAndBounce] .
140+ ///
141+ /// This value controls how bouncy the spring is:
142+ ///
143+ /// * A value of 0 results in a critically damped spring with no oscillation.
144+ /// * Values between 0 and 1 produce underdamping, where the spring oscillates a few times
145+ /// before settling. A value of 1 represents an undamped spring that
146+ /// oscillates indefinitely.
147+ /// * Negative values indicate overdamping, where the motion is slow and
148+ /// resistive, like moving through a thick fluid.
149+ ///
150+ /// Defaults to 0.
151+ double get bounce {
152+ final double dampingRatio = damping / (2.0 * math.sqrt (mass * stiffness));
153+ return dampingRatio < 1.0 ? (1.0 - dampingRatio) : ((1 / dampingRatio) - 1 );
154+ }
155+
81156 @override
82157 String toString () =>
83158 '${objectRuntimeType (this , 'SpringDescription' )}(mass: ${mass .toStringAsFixed (1 )}, stiffness: ${stiffness .toStringAsFixed (1 )}, damping: ${damping .toStringAsFixed (1 )})' ;
0 commit comments