How to change speed of a hero animation in flutter

15,341

Solution 1

To modify the transition speed, you'll have to adjust the PageRoute transition duration (as already pointed out by @diegoveloper).

If you wanna keep the default transition, you can create a class implementing MaterialPageRoute. If you already have your own transition or want to create one you can use the PageRouteBuilder to easily build your own. Simply adjust the transitionDuration.

Here's a small standalone example, using the PageRouteBuilder:

Transition Demo

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Page1(),
    );
  }
}

class Page1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            RaisedButton(
              child: Text('Page2'),
              onPressed: () => Navigator.push(
                  context,
                  PageRouteBuilder(
                      transitionDuration: Duration(seconds: 2),
                      pageBuilder: (_, __, ___) => Page2())),
            ),
            Hero(tag: 'home', child: Icon(Icons.home))
          ],
        ),
      ),
    );
  }
}

class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Hero(
          tag: 'home',
          child: Icon(
            Icons.home,
          ),
        ),
      ),
    );
  }
}

Solution 2

1. A Possible Solution

I don't think the only way of achieving this is through changing the PageRoute transition duration. I think you could also achieve the same effect by using an AnimationController — this answer comes largely from lectures #149 and #150 of Angela Yu's The Complete 2019 Flutter Development Bootcamp with Dart.

  1. Turn your screen into a StatefulWidget.
  2. If you're using only one animation, add with SingleTickerProviderStateMixin to your state class.
  3. Create a controller inside the state class.
  4. If your animation is supposed to appear on the initialization of the screen, use the controller inside the initState method.
    • The controller has a property called duration, so you can change it to your liking.

2. How It Would Look Like

In the end, everything should look a bit like this:

class _NewScreenState extends State<HomeScreen> 
  with SingleTickerProviderStateMixin{

  AnimationController controller;

  @override
  void initState() {
    super.initState();

    controller = AnimationController(
      duration: Duration(seconds: 1),
      vsync: this,
    );

    controller.forward();

    controller.addListener((){
      setState(() {
        
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return ...
  • vsync is a required (@required) parameter that takes the state (instance) object itself (usually).
  • addListener and setState are there if you wish to use the value of the controller (controller.value) at some point in the future — for example, changing the height of the icon with something like height: finalHeight * controller.value.
  • For the transition into this screen, I'm simply using a FlatButton with Navigator.pushNamed, nothing special.

3. Some Additional Important Info

  1. The controller will still be active even if you change screens later. So if you have a looping animation in the background, it's a good idea to dispose it when changing the screen, this way you don't waste phone resources with it anymore. This could be achieved with:
    @override
    void dispose() {
      controller.dispose();
      super.dispose();
    }
    
  2. You could also customize how the animation is run, or how it is executed. One option is to use a CurvedAnimation.
    1. Declare Animation animation; right below your controller.
    2. Below your controller, inside initState, add:
      animation = CurvedAnimation( // the controller can't have upperBound > 1
        parent: controller,        // the controller you created
        curve: Curves.decelerate,
      );
      
  3. Another useful way of animating in Flutter is by using TweenAnimations. For example, if you want to transition between colors, you could use ColorTween (below your controller, inside initState):
    animation = ColorTween(
      begin: Colors.red,
      end: Colors.blue,
    ).animate(controller);
    
Share:
15,341
Admin
Author by

Admin

Updated on June 17, 2022

Comments

  • Admin
    Admin almost 2 years

    I have made simple hero animation following instructions from Flutter's website

    It works as described in the instructions but in my case, I would like it to animate much more slowly from the first to the second screen. do anyone know how to change the speed of this animation?