The Flutter animation framework gives many choices when building animations. One of the most flexible ones is the AnimatedBuilder: this widget describes animations as part of a build method for another widget. It takes an animation, a child, and a builder. The optional child exists independently of the animation. An AnimatedBuilder listens to the notifications from an Animation object and calls its builder for each value provided by an Animation, only rebuilding its descendants: this is an efficient way of dealing with animations.
In the moveBall method, there is no need to call setState, as redrawing the ball is a task that the AnimatedBuilder performs automatically.
The repeat method, appended to the AnimationController, runs this animation from start to end and restarts the animation as soon as it completes.
When you set the reverse parameter to true, when the animation completes, instead of always restarting from its beginning value (min) it starts from its ending...