Remaths

remaths is a flutter package that makes animations and other calculations easier to use. This package is heavily inspired by the react-native reanimated package.

Tweenable

Tweenables are one of the fundamentals of the remaths package. Tweenable carries Tweenable data. This data can be animated with timing or spring. Tweenable uses the default flutter AnimationController under the hood to render animations (performable). Before we start animating with Tweenable lets look at Tweenable Functions

Tweenable Functions

Tweenable functions are used to animate Tweenable values.

withSpring

Starts a spring animation on the Tweenable value.

   x = withSpring(toValue, {
   int  duration,
   double  damping,
   double  stiffness,
   double  mass,
   double  velocity,
   int?  delay,
   void  Function()?  onComplete,
   })
Params default description
toValue * required the destination of the animation
duration 300 the duration in milliseconds
damping 20 spring damping
stiffness 180.0 stiffness
mass 1.0 mass
velocity 0.0 velocity
delay 0.0 duration in milliseconds the animation will delay before starting
onComplete null function called after the animation is complete

withTiming

Start a timing animation in the Tweenable value

x = withTiming(double toValue, {
    double toValue, {
  int duration = _kDuration,
  Curve curve = Curves.easeIn,
  int? delay,
  void Function()? onComplete,
})
Params default description
toValue * required the destination of the animation
duration 300 the duration in milliseconds
curve Curves.easeIn the curve of the animation
delay 0.0 duration in milliseconds the animation will delay before starting
onComplete null function called after the animation is complete

withSequence

Run list of animations sequentially.

 x = withSequence([withTiming(...),6.0,withSpring(...),])

wihSequence takes a list of Tweenable Functions or a double and run them sequentially. When a double is provided, the value is set to that destination without any animation.

Working with Tweenables

Lets take Tweenable as a double value that can be animated with Tweenable Functions.

var x = Tweenable(double value, vsync: this);

Tweenables can also be initialized with num extensions

var x = 12.asTweenable(this);
// In this case 12 is used as an initial value
Params default description
value required the animation position
vsync required TickerProvider

You have to use your stateful object as the vsync by adding SingleTickerProviderStateMixin or TickerProviderStateMixin to the class definition

Animations can be done on Tweenable by setting the Tweenable value to an animated function

When any animation does not end before initializing another animation, the previous animation is stopped and the current animation continues from where the old on stopped to bring a smooth animation experience

Example

x = withTiming(...)
x = withSpring(...)
x = withSequence(...)
x = 45.0 // no animations done here

Note: if a double value to set with the Tweenable, no animation is triggered. The value is just jumped the destination.

Using Tweenables

Tweenable can be used with AnimatedBuilder.

To use Tweenable with AnimationBuilder, you need a helper function mergeTweenables which you can pass the Tweenable which when changed the Widget will rebuild

i.e

// initialization
var x = 10.asTweenable();
var x = 12.asTweenable();

// Usage

AnimatedBuilder(
  animation: mergeTweenables([x,y])
  child: ...
  builder: ...
)
// the widget will rebuild anytime the values of `x` and `y` changed

Interpolation

Maps an input value within a range to an output value within a range. Also supports different types of extrapolation for when the value falls outside the range and mapping to strings. Interpolation is made as an extension on num and Tweenable.

var val = 50;
// or
var val = 50.asTweenable(this);
// usage
var opacity = val.interpolate<double>(
  [20, 100] // input range
  [0,1] // output range
  Extrapolate.EXTEND, // extrapolation
  Extrapolate.EXTEND, // left Extrapolation
);

// COLOR INTERPOLATION
var color = val.interpolate<Color>(
  [20, 10],
  [Colors.red, Colors.green],
)
// The extrapolation in Color interpolation is fixed to Extrapolate.CLAMP even if specified

The third parameter is the is the right extrapolation and the last parameter is the left extrapolation. If the left extrapolation is the specified the right extrapolation is used for the left extrapolation, and if any of the extrapolations is not specified, the default Extrapolate.EXTEND is used for both the left and the right. In Color Interpolation the extrapolation is fixed to Extrapolate.CLAMP even if specified

Helper nodes

 /// Takes two values, and when evaluated, returns their sum.
  double add(dynamic a, dynamic b);
//. Takes two values, and when evaluated, returns their product.
  double multiply(dynamic a, dynamic b);

  /// Takes two values, and when evaluated,  returns the result of dividing their values in the exact order.
  double divide(dynamic a, dynamic b);

  /// Takes two values, and when evaluated, returns the result of subtracting their values
  double sub(dynamic a, dynamic b);

  /// Takes two or more values, and when evaluated, returns the result of first node to the second node power.
  double pow(dynamic a, dynamic b);
  
  /// returns the square root of the number
  double sqrt(dynamic a);

  /// Remainder after division of the first argument by the second one. modulo(a,0) will throw an error.
  double modulo(dynamic a, dynamic b);

  /// The same function as `math.log`
  double log(dynamic a);

  /// The same function as `math.sin`
  double sin(dynamic a);

  /// The same function as `math.tan`
  double tan(dynamic a);

  /// The same function as `math.asin`
  double asin(dynamic a);

  /// The same function as `math.exp`
  double exp(dynamic a);

  /// The same function as `num.round`
  int round(dynamic a);

  /// The same function as `num.floor`
  int floor(dynamic a);

  /// The same function as `num.ceil`
  int ceil(dynamic a);

  /// The same function as `math.atan`
  double atan(dynamic a);

  /// returns the minimum value
  min<T extends num>(T a, T b);

  /// returns the maximum value
  T max<T extends num>(T a, T b);

  /// returns the absolute value
  num abs(dynamic a);

  /// convert [a] in Degrees to Radian
  double toRad(dynamic a);

  /// convert [a] in Radian to Degrees
  double toDeg(dynamic a);

  /// Returns true if the given node evaluates to a "defined" value (that is to something that is non-null, non-undefined and non-NaN).
  /// Returns false otherwise
  bool defined(a);

  bool or(bool a, bool b);

  /// the if the value is valid
  bool truthy(dynamic val);

  /// If [condition] evaluates to "truthy" value the node evaluates [ifBlock] node and returns its value,
  /// otherwise it evaluates [elseBlock] and returns its value. [elseBlock] is optional.
  cond(bool condition, ifBlock, [elseBlock]);

  /// less than `<` comparison
  bool lessThan(a, b);

  /// greater than `>` comparison
  bool greaterThan(a, b);

  /// checks if the two values are equal `==`
  bool eq(a, b);

  /// checks if the two values are `not` equal `!=`
  bool neq(a, b);

  /// less than or equal to `<=` comparison
  bool lessOrEq(a, b);

  /// greater than or equal to `>=` comparison
  bool greaterOrEq(a, b);

  /// Evaluates [Tweenable] and returns a difference between value returned
  ///  at the last time it was evaluated and its value at the current time.
  ///
  /// When evaluating for the first time it returns the [Tweenable] value
  double diff(_InternalShared tweenable, [double initial = 0.0]);

  /// round a number [dec] (decimal)  specified
  /// ```dart
  /// decimalRound(1.34343, 2) // 1.34
  /// ````
  double decimalRound(dynamic a, dynamic dec);

  /// generate a random number from [start] to [end]
  ///
  /// If [decimal] is is specified, a random number is generated
  /// to the [decimal] specified
  /// ```dart
  /// random() // returns number from 0-1
  /// random(5) // returns random number from 0 - 5
  /// random(5,9) // returns random number from 5 to 9
  /// random(5,10,2) //returns a random decimal from 5 to 10 to 2 decimal places
  /// ```
  double random([int start = 0, int end = 1, int decimal = 1]);

  /// Generate a list integers
  /// ```dart
  /// range(3) // [0,1,2]
  /// range(10, start: 5) // [5,6,7,8,9]
  /// range(10, step: 2) // [0,2,4,6,8]
  /// ```
  range(int stop, {int start: 0, int step: 1});

Libraries

remaths