Do you remember how we used to do programming before Flutter hooks weren’t part of Flutter? It was a bit difficult and overwhelming, right? Here’s a Flutter tutorial where we will explore pre-hooks and post-hooks Flutter life. We will learn how to use useEffect and useAnimationController in our demo app. Let’s get ready and build an application, then!

Basics of Flutter Animation

In this Flutter Hooks tutorial, we will learn how to install and build an animation demo using hooks in Flutter, and also, we will look at how we used to code before hooks weren’t introduced. Before moving on to the Flutter hooks tutorial, let’s discuss the basics of animation.

We need to do the below things for animation,

  • Animation controller
  • Manage animation
  • Listen for updates
  • Manipulate animation

The default part is the “Animation,” There are two types of animation that Flutter supports.

  • Tween Animation– It is the short form of in-betweening. The animation must define the start and endpoint. The animation will have a start value and then reaches the end value through various intermediate values.
  • Physics-based Animation– It allows you to interact with an app more realistically and interactively.

In simple words, an Animation controller is called whenever its value changes,
Ticker calls tick function every frame. After each tick, it provides a callback function after it is started. In our case, the ticker listener is the controller.

Introduction: What is Flutter Hooks?

Flutter hooks have not received much visibility and acknowledgment, but that won’t make them less awesome. With the help of the flutter_hooks library, we can provide a robust way for managing the lifecycle of widgets by reducing code duplication and increasing code-sharing.

Flutter provides in-built hooks as shown below:

  • useEffect hook fetches data from a server and sets the fetch to the local state
  • useState hook manages local states in apps
  • useMemoized hook memoizes complicated functions to achieve optimal app performance
  • useRef hook creates an object that has one mutable property.
  • useCallback hook cache a function instance.
  • useContext hook obtain the BuildContext of the building HookWidget
  • useValueChanged Hook watches a value and calls a callback whenever the value changes.

In this guide, we’ll use the useEffect hook for redirection after some duration, and useAnimationController hook to create an instance of AnimationController. Flutter, just like ReactJS, also gives you the opportunity of creating your custom hooks. We will discuss that later in the tutorial. Without further ado, let’s get started with the Flutter hooks tutorial.

Pre-Hooks Life: Animation without Flutter Hooks

First of all, let’s see the splash screen animation demo without implementing flutter hooks and using the stateful widget; it needs to be mixed in with a TickerProviderStateMixin.

And don’t forget to dispose of the animation controller.

Copy Text
class SplashScreen extends StatefulWidget {
  const SplashScreen();

  @override
  _SplashScreenState createState() => _SplashScreenState();
}

class _SplashScreenState extends State with TickerProviderStateMixin {
  late AnimationController _animationController;
  late AnimationController controller;
  late Animation< Offset > offset;

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

    startTime();

    _animationController = new AnimationController(vsync: this, duration: Duration(seconds: 3));
    _animationController.repeat(reverse: false);

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

    offset = Tween< Offset >(begin: Offset(0.0, 1.0), end: Offset.zero).animate(controller);
    controller.forward();
  }

  startTime() async {
    var duration = Duration(seconds: 3);
    return Timer(duration, navigatePage);
  }

  Future navigatePage() async {
    Route route = MaterialPageRoute(builder: (context) => HomePage());
    Navigator.of(context).pushReplacement(route);
  }

  @override
  void dispose() {
    _animationController.dispose();
    controller.dispose();
    super.dispose();
  }

...

}

All of the above code is set up for animation. And then we will just apply these instances to our widgets/design. That is just easy to understand.

Post-Hooks Life: Installation and Flutter Hooks Example

How to Install Flutter hooks?

Run the following command for installing flutter hooks

Copy Text
flutter pub add flutter_hooks

The command will update pubspec.yaml file of the dependencies section with flutter_hooks: VERSION_NUMER_HERE.

OR you can directly update pubspec.yaml with flutter_hooks as shown below

Copy Text
  dependencies:
       flutter:
           sdk: flutter
       flutter_hooks:

Save the file, and Flutter will install the dependency. Now, import the flutter_hooks library.

Copy Text
import 'package:flutter_hooks/flutter_hooks.dart';

How to Implement Animation using Flutter Hooks?

The first change to make is to replace the Stateful Widget with Hook Widget. And then, to initialize the animation controllers, we will use the useAnimationController() method, a default method provided by the flutter_hook library. And we can remove all boilerplate code from initState and dispose method.

Copy Text
class SplashScreen extends HookWidget {
  @override
  Widget build(BuildContext context) {
    AnimationController _animationController = useAnimationController(duration: Duration(seconds: 4), initialValue: 1);
    _animationController.repeat(reverse: false);

    AnimationController controller = useAnimationController(duration: Duration(seconds: 3), initialValue: 1);
    controller.repeat(reverse: false, period: Duration(seconds: 4));

    controller = useAnimationController(duration: Duration(seconds: 3), initialValue: 1);
    controller.repeat(reverse: false, period: Duration(seconds: 4));

    Animation< Offset > offset = Tween< Offset >(begin: Offset(0.0, 1.0), end:     Offset.zero).animate(controller);
    controller.forward();

    useEffect(() {
      Timer.periodic(Duration(seconds: 4), (time) {
        Route route = MaterialPageRoute(builder: (context) => HomePage());
        Navigator.of(context).pushReplacement(route);
      });
    });

    return SafeArea(
        child: Scaffold(
      body: Container(
        decoration: BoxDecoration(
          gradient: LinearGradient(
            colors: [Color(0xFFFFFFFF), Color(0xffE3F3FF)],
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter,
          ),
        ),
        child: Stack(
          children: [
            FadeTransition(
                  opacity: _animationController,
                  child: Center(
                    child: FlutterLogo(
                      size: 50,
                    )),
             ),
            Align(
                alignment: Alignment.bottomCenter,
                child: SlideTransition(
                  position: offset,
                  child: Image.asset(
                    'assets/images/splash_bg.png',
                    width: MediaQuery.of(context).size.width,
                    fit: BoxFit.fill,
                  ),
                ))
          ],
        ),
      ),
    ));
  }
}

But the problem with the above code is there is no way to dispose the animation controller instances; we have a solution for this, called custom hooks.

Flutter Hooks Tutorial to Create Custom Hooks

The custom AnimationController hooks in Flutter will instantiate an AnimationController and return the ScrollController to use it from the UI. It will help in holding all the code, practically, which was previously stored in the State object of a StatefulWidget.

The most basic hook can be just a simple function. Let’s create one under hooks/controller_for_animation.dart. And also one for Animation< Offset >.

Copy Text
// hooks/controller_for_animation.dart.

AnimationController useControllerForAnimation() {
  return use(_AnimControllerForAnimationHook());
}
 
class _AnimControllerForAnimationHook extends Hook {
  @override
  _AnimControllerForAnimationHookState createState() => _AnimControllerForAnimationHookState();
}
 
class _AnimControllerForAnimationHookState extends HookState {
  late AnimationController _animController;
 
  @override
  void initHook() {
    _animController = useAnimationController(duration: Duration(seconds: 4), initialValue: 1);
    _animController.repeat(reverse: false);
  }
 
  @override
  AnimationController build(BuildContext context) => _animController;
 
  @override
  void dispose() => _animController.dispose();
}
 
Animation< Offset > useOffsetHook() {
  return use(_AnimOffsetForAnimationHook());
}
 
class _AnimOffsetForAnimationHook extends Hook> {
  @override
  _AnimOffsetForAnimationHookState createState() => _AnimOffsetForAnimationHookState();
}
 
class _AnimOffsetForAnimationHookState extends HookState, _AnimOffsetForAnimationHook> {
  late AnimationController _controller;
  late Animation< Offset > offset;
 
  @override
  void initHook() {
    _controller = useAnimationController(duration: Duration(seconds: 3), initialValue: 1);
    _controller.repeat(reverse: false, period: Duration(seconds: 4));
 
    offset = Tween(begin: Offset(0.0, 1.0), end: Offset.zero).animate(_controller);
    _controller.forward();
  }
 
  @override
  Animation< Offset > build(BuildContext context) => offset;
  @override
  void dispose() => _controller.dispose();
}

All we did was move logic to this new class; also, there is one dispose method from which we can also dispose that controller, and now simply use that useControllerForAnimation. The method inside build method of the splash screen.

Copy Text
class SplashScreen extends HookWidget {
  @override
  Widget build(BuildContext context) {
    AnimationController _animationController = useControllerForAnimation();
    Animation< Offset > offset = useOffsetHook();
…….
  }

Also, create one hook widget inside hook/timer_widget.dart to redirect to a home screen after some duration.

Copy Text
// hook/timer_widget.dart 
 
import 'dart:async';
 
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_hooks_demo/home_page.dart';
 
bool useTimerToNavigate() {
  return use(const _NavigateTimer());
}
 
class _NavigateTimer extends Hook {
  const _NavigateTimer();
 
  @override
  ___NavigateTimerState createState() => ___NavigateTimerState();
}
 
class ___NavigateTimerState extends HookState {
  late Timer _timer;
  bool isRedirect = false;
 
  @override
  void initHook() {
    super.initHook();
    _timer = Timer(Duration(seconds: 4), () {
      Route route = MaterialPageRoute(builder: (context) => HomePage());
      Navigator.of(context).pushReplacement(route);
    });
  }
 
  @override
  bool build(BuildContext context) {
    return isRedirect;
  }
 
  @override
  void dispose() {
    _timer.cancel();
    super.dispose();
  }
}

And here is the final Splash Screen code!

Copy Text
// splash_screen.dart
 
class SplashScreen extends HookWidget {
  @override
  Widget build(BuildContext context) {
    AnimationController _animationController = useControllerForAnimation();
    Animation< Offset > offset = useOffsetHook();
    useTimerToNavigate();
 
    return SafeArea(
        child: Scaffold(
      body: Container(
        decoration: BoxDecoration(
          gradient: LinearGradient(
            colors: [Color(0xFFFFFFFF), Color(0xffE3F3FF)],
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter,
          ),
        ),
        child: Stack(
          children: [
            FadeTransition(
                opacity: _animationController,
                child: Center(
                  child: FlutterLogo(
                    size: 50,
                  ),
                  // child: Image.asset('assets/images/splashlogo.png'),
                )),
            Align(
                alignment: Alignment.bottomCenter,
                child: SlideTransition(
                  position: offset,
                  child: Image.asset(
                    'assets/images/splash_bg.png',
                    width: MediaQuery.of(context).size.width,
                    fit: BoxFit.fill,
                  ),
                ))
          ],
        ),
      ),
    ));
  }
}

The entire source is available on the github: flutter-hooks-demo.

Conclusion

We can conclude that with the help of flutter hooks we can reuse that AnimationController and Animation< Offset > just by adding one line!
AnimationController _animationController = useControllerForAnimation();

So, this is how we can reduce the boilerplate code and make a smaller size code for the widget. And also make clean, easy and maintainable code. I hope the Flutter hooks tutorial was helpful to you. For more such Flutter Tutorials, feel free to visit the Flutter tutorials page and clone the github repository to play around with the code.

If you are looking for Flutter experts who can help you with your projects, contact us to hire Flutter developer. Since our developers have great problem-solving skills, we assure you of the absolute code quality and optimum application performance.

Flutter Tutorials

Connect Now

Get In Touch

[email protected]

Your Success Is Guaranteed !

We accelerate the release of digital product and guaranteed their success

We Use Slack, Jira & GitHub for Accurate Deployment and Effective Communication.