Custom Tween

To create a custom Tween class, first, we need to define our value object. Here, we have opted for grouping the transformation values:

class ButtonTransformation {
final double scale;
final double angle;
final Offset offset;

// this none getter returns a initial state of transformation
// with default scale, no rotation or translation
static ButtonTransformation get none => ButtonTransformation(
scale: 1.0,
angle: 0.0,
offset: Offset.zero,
);
}

And then, we extend the Tween class with our defined type:

class CustomTween extends Tween<ButtonTransformation> {

CustomTween({ButtonTransformation begin, ButtonTransformation end} ):
super(begin: begin, end: end,);

@override
lerp(double t) {
return super.lerp(t);
}
}

We need to define our custom Tween lerp() method (lerp stands for linear interpolation), which is responsible for returning the intermediate ButtonTransformation value between begin and end, based on the t value.

By taking a look into the default Tween class's lerp() implementation, we can see it is very simple:

// part of tween.dart Tween class

@protected
T lerp(double t) {
assert(begin != null);
assert(end != null);
return begin + (end - begin) * t;
}

It calculates the lerp() value by using the +, -, and * operators on the type T objects. This means we can simply implement those operators in our ButtonTransformation and Tween will work as it does with any other type:

class ButtonTransformation {
...
ButtonTransformation operator -(ButtonTransformation other) =>
ButtonTransformation(
scale: scale - other.scale,
angle: angle - other.angle,
offset: offset - other.offset,
);

ButtonTransformation operator +(ButtonTransformation other) =>
ButtonTransformation(
scale: scale + other.scale,
angle: angle + other.angle,
offset: offset + other.offset,
);

ButtonTransformation operator *(double t) => ButtonTransformation(
scale: scale * t,
angle: angle * t,
offset: offset * t,
);
}

Now, the Tween class is able to generate intermediate ButtonTransformation values as well. We can then use the generated animation values just like before:

  createCustomTweenAnimation() {
var controller = AnimationController(
vsync: this,
debugLabel: "animations demo",
duration: Duration(seconds: 3),
);

var animation = controller.drive(CustomTween(
begin: ButtonTransformation.none, // initial state of the animation
end: ButtonTransformation(
angle: 360.0,
offset: Offset(70, 200),
scale: 2.0,
)));

animation.addListener(() {
setState(() {
_buttonTransformation = animation.value;
});
});

return controller;
}

As you can see, the big difference is in the usage of our CustomTween property. Note that we always need to define begin and end values, as Tweens are based on a range defined by the corresponding interpolation.

With those examples, we have seen how to use and apply the most important animations in Flutter. In the next sections, we will see alternative ways of applying animations to our widgets.

We can build multiple simultaneous animations using separate Animation objects, typically, by setting the same AnimationController as their parent. They are guaranteed to be in sync as we will be using the same Ticker object.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.23.127.197