John N Blanchard
Updated: Jan 30, 2019
I wrote a small project, my goal is to show you how to do pretty animations like the one above. With Flutter it is really easy to prototype new UI, and ultimately create meaningful interactions that dazzle your Android and iOS users.
As an iOS developer, I may elect to use UIView and transform, or layout constraints to achieve the same animations above. As my user messed with the textfield first-responder, I would compute label locations and constraint constants to later wrap in an animation block.
With Flutter, I found the declarative features interact uniquely with animations, but I still built the initial state first. My Scaffold wraps a stack inside an Align widget with a top-middle layout. The last widget in the stack is on top of the other children, BillCenter is the Container that holds the TextField so we list it last. This Scaffold is an initial skeleton of the tip calculator app, and represents the first screen state using its lower widgets.
The row builder expects a parameter animation that helps create our current row state. The last parameter is used to show the row above or below the textfield.
These suggestion row are wrapped with Transform.scale widgets that work incredibly similar to CGAffineTransform(scaleX: CGFloat, scaleY: CGFloat). Below notice our scale parameter is animation.value; this value will change with the progress of our animation controller.
Our suggested row is ready for animating from nothing to something. But we need to define the animation itself, how long will it last, and which curve will it follow. The home screen defines its animation inside initState(). We declare the values for our transform here, animation.value will be 0 to 1.
Then any widget that will interact with these animation value changes, just has to declare itself a listener.
For this animation, I have it connected to the textfield. The TextField widget has an onChanged parameter that takes a listener. When that thing has a value, I check if it is a valid bill and choose the correct animation path.
Our animation controller will be pushed forward if it is currently dismissed, but we can also push it forward while we are in the process of animating dismissal. It gives this nice reactive feeling to your app animations and interactions. We also handle a case for being visible and animating to hidden in a similar fashion.
In the Flutter environment, it is easy to reload the sim/em and see changes, I invite you to explore the repo. It was way too easy to create professional animations for cheap.
As a last note, I broke the gesture detector on the row buttons by wrapping them in multiple Transforms, I think this is a bug.