1

How can I create an animation to move an image from the center to the top of the screen? The client asked that the splash screen has the icon in the center of the screen and that when the login screen is displayed the icon will be moved to the top of the screen and display the fields for the login. Can someone help me?

1 Answers1

2

This seems like a perfect candidate for using a hero animation, as most of the work is already done for you. There are a few things I should point out though.

  1. The splash screen that is shown while the app is starting on both android & iOS is defined directly in iOS and android, and must be static.

  2. It is not possible to define this splash screen using flutter.

What I would recommend instead, is specifying a simple splash screen in iOS and android directly. Then create a page in flutter which looks identical to this screen. That way, you get to go from

native splash screen -> flutter splash screen ----animate---> login screen.

I've created a quick mockup of what this could look like.

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: SplashPage(),
    );
  }
}

enum SplashHeroes { icon }

class SplashPage extends StatefulWidget {
  @override
  SplashPageState createState() {
    return new SplashPageState();
  }
}

class SplashPageState extends State<SplashPage> {
  @override
  void initState() {
    super.initState();
    Future.delayed(Duration(seconds: 1), _toNext);
  }

  _toNext() {
    Navigator.push(
      context,
      PageRouteBuilder(
        pageBuilder: (context, _, __) => LoginPage(),
        transitionsBuilder: (context, animation, secondaryAnimation, child) => FadeTransition(
              opacity: animation,
              child: child,
            ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.blue,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Hero(
            tag: SplashHeroes.icon,
            createRectTween: (rect1, rect2) => RectTween(begin: rect1, end: rect2),
            child: Icon(
              Icons.airport_shuttle,
              size: 100.0,
              color: Colors.white,
            ),
          ),
          FlatButton(
            child: Text("Next"),
            onPressed: _toNext,
          ),
        ],
      ),
    );
  }
}

class LoginPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: <Widget>[
          Hero(
            createRectTween: (rect1, rect2) => RectTween(begin: rect1, end: rect2),
            tag: SplashHeroes.icon,
            child: Icon(
              Icons.airport_shuttle,
              color: Colors.white,
            ),
          ),
        ],
      ),
      backgroundColor: Colors.deepPurple,
      body: Center(
        child: Column(
          children: <Widget>[
            Text("Username"),
            TextField(),
            Text("Password"),
            TextField(),
          ],
        ),
      ),
    );
  }
}

There's a few things to note in this code.

  1. It uses a PageRouteBuilder which only does a very basic job of making a fading transition. You can add to this or make your own override of PageRoute. I also assumed that you'd want a fade transition rather than the normal material transition as it tends to look better for the splash screen -> first screen transition.

  2. In debug mode, the first time you do the animation it will actually skip the frames that you're wanting to animate. Either build in release mode or wait for the automatic transition to happen, press back, then press next.

  3. I added a createRectTween so that the animation goes directly from the center to the corner. If you don't define this is uses a curved route instead. Your choice.

  4. Icons have a set size and I didn't bother overriding anything to make it so that the size animates from corner to middle. If you use a picture I believe the size will animate too, although I'm not 100% sure about that.

  5. I just put the icon into the 'actions' of the app bar as an example. You can put the icon anywhere you want (and not even use an app bar if you don't want to) -- the hero transition will work wherever you put the icon.

  6. The enum SplashHeroes is important, because flutter needs a way to be able to match up different heroes. In this case there's only one, but you could theoretically have a few each with their own transition types. Using the enum tells flutter that the hero contains the same widget (or at least a widget you want to be transitioned to/from).

Note that I didn't really answer your question directly ('how to implement a flutter animation' but rather what you explained your problem was) so if this helps, I'll change the title to something more appropriate so someone else doesn't stumble on it looking how to set up a general flutter animation.

rmtmckenzie
  • 37,718
  • 9
  • 112
  • 99