Git Product home page Git Product logo

heartbeatappbar's Introduction

Heartbeat AppBar

Animation

This is a flutter app that utilizies its animation and painting API to make a very modern, smooth, animation. This was a real challenge to build, specially because it was my first time learning how to use flutter's CustomPainter.

Big thanks to Tubik @dribble for making this awesome design and inspiring me to do this app!

An overview of how the code works

This is a pretty advanced app, so I'll assume you know the basics of flutter.

The first thing I want to talk about is the HeartBeatAppBarContent widget. As you can see, it's a StatefulWidget inside of the HeartBeatAppBar widget, and its state uses the SingleTickerProviderStateMixin. For those of you who don't know, this is what allows us to animate widgets in flutter. We have one AnimationController and 3 Animations<double>:

  • The controller itself is what's going to control the animation values

  • The _activatingOpacity will animate the opacity of one of the icons so it becomes brighter (indicating it being activated)

  • The _deactivatingOpacity will animate the opacity of one of the icons so it becomes dimmer (indicating it being deactivated)

  • The _heartBeatAnimation is what's going to allow us to control the percentage of the animationg, defining the beginning and ending points of the path of the Painter, so we actually see the line of the heartbeat moving.

We have 3 properties in the HeartBeatAppBarContent's state.

  • _activated allows us to keep track of what is the activated icon so that, when we click one of them, we can animate from the _activated to the _nextActivated

  • _nextActivated allows us to keep track of what's the next icon that is going to be activated so that we can make the heartbeat path from the _activated X position, to the _nextActivated X position. Its default value is 0, and its immediately changed when the animation is called

  • _positions is a List of doubles which allows us to know what is the position in the X axis of each icon. This was hardcoded but it can and should be responsive to the width of the device.

When an animation is called, _nextActivated gets the value of the clicked button (if the first icon was clicked, then _nextActivated is set to 1, since the default value is 0). Now, we give the HeartBeatPainter its beginning property of _positions[_activated] and its ending property of _positions[_nextActivated].In other words, the HeartBeatPath will start at the position of the activated icon, and will go to the position of the next activated icon. Once the animation ends, _activated is set to _nextActivated and _nextActivated is set back to 0.

The CustomPaint

This is where things get a little hairy, but I'll try to keep it very simple. HeartBeatPainter extends CustomPainter. That means that it needs two methods: paint and shouldRepaint. Since we're using an animation coming from its parent widget, we are not going to need shouldRepaint, so it just returns false.

We have 3 properties:

  • beginning is the starting X position of the HeartBeatPath, and its coming from _positions[_activated].
  • ending is the ending X position of the HeartBeatPath, and its coming from _positions[_nextActivated].
  • animation is an Animation<double> which is what allows us to know how much of the animation has passed. So if its value is 0.5, that means 50% of the animation has gone through, and that's useful to determine what is the current state of the path itself. This will be passed to the super constructor as the repaint attribute.

Then we are defining 3 functions. lerp, sigmoid and parabola, which are used to determine some of the values. I'm not going to go through the math of this, but this allows us to have smoother animations.

We also have a bool inversed a List<Offset> _points. The first one is important to determine if the path will have to go from left to right, or from right to left. The second will contain all of the points that are going to be used to make our heartbeat path. That means _points[0] is the first point of the path, and the last value of _points is last point of the path.

In _points, we hard coded a bunch of values:

  • The ones that start with beginning + a * PERCENTAGE allows us to make a lot of points in between the beginning of the path, and the heartbeat wave (which is always in the middle). If we didn't have this, the path would be "skippy", and the animation would not look smooth at all.
  • The same goes for the ones that start with startingPoint + 30 + b * PERCENTAGE. This makes a bunch of points in between the ending of the heartbeat wave, and the ending point of the whole path.
  • All of the other points are the heartbeat wave being hard coded
  • startingPoint is the X position of the beginning of the heartbeat wave.

As you can see from the code, _positions changes depending on the _inversed value, and therefore, on the direction of the heartbeat animation.

Now here comes the main part. We have a variable start that indicates what is the first point of our path, and this changes depending on the _animation.value. Hence, if _animation.value is closer to 1, the start value will be greater, which makes the back of the path start to move when the animation starts progressing. We also have a percentage variable, which is what controls the front of the path, since this will define the last point of our path.

From there, we are calling a for loop, that goes from the start point (first), to percentage point (last), and adds all of the points in between to the path.

The color of the path (which is a gradient) and the circle (which is the indicator of the current icon) also animate and get its properties depending on the inverse value.

heartbeatappbar's People

Contributors

bernardi23 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.