An expanded floating action button used to call out sharing

Part 1 of this post is linked below:

It’s been a little over a year since the post above, and a lot of things can change in a year. Specifically, I’ve since moved to Kotlin as my primary language for Android development, and I’ve found a cleaner and more aesthetically pleasing way to create an expandable floating action button in Android; let’s talk more about the latter.

I’ll start by extolling the virtues of the Jetpack DynamicAnimations library; animations are inherently stateful, transforming your View in one way or the other, and to maintain visual aesthetics, it’s important that animations are:

Smooth

Continuous

Reentrant

Which DynamicAnimations does with aplomb. If you haven’t already, please read Nick Butcher’s post on the same topic for more detail, it’s the inspiration behind the rewriting of the expandable FAB to use DynamicAnimations :

One of the benefits of DynamicAnimations is that whenever an animation is running to some end value, you can change that end value to some other arbitrary value, and the implementation will take care of adjusting parameters so that this change satisfies the 3 tenets above. The implementation of DynamicAnimations for FAB expansion and collapse will be the SpringAnimation , and again I’ll refer you to to another excellent post on the library and it’s internal workings, this time by Rebecca Frank:

Returning to the FAB, to use a SpringAnimation , the first thing that needs to be done is to define the property of the View , in this case a MaterialButton , to animate. Since the size of the FAB regardless of the ViewGroup it’s in is dependent on it’s LayoutParams , it makes sense to choose the LayoutParams as the property to mutate with the animation; specifically, its LayoutParams.width and LayoutParams.height .

At first glance, it may appear that since both the height and the width of the FAB will change with extension and collapse, two SpringAnimations will be needed, but we can be cleverer than that. When collapsed, the FAB is a perfect circle, and so the width and height are identical. When extended however, the height of the FAB is flattened a bit, but it’s still fully deterministic; the only real variable is the width of the FAB as it changes to match the length of the text displayed within it. Going further, it is possible to express the height of the FAB as a function of it’s width with the classic equation of a straight line:

y = f(x) = mx + c

The line must go through the points:

x1 , y1 ; where x1 = y1 = collapsedFabSize

, ; where = = collapsedFabSize x2 , y2 ; where y2 = expandedFabHeight, and x2 is TBD as it depends on the length of the text.

, ; where = expandedFabHeight, and is TBD as it depends on the length of the text. m is the slope of the line

is the slope of the line c is the y intercept

How is x2 determined then? Fortunately, it’s as easy as setting the text in the MaterialButton and asking it to measure itself. When all the above it put together, the property for animating the collapse and expansion of the FAB takes the form:

Using this is as simple as calling:

Animating a FAB with a spring

It is also important to remove the default insets of the MaterialButton and to give it a cornerRadius equal to the collapsedFabSize . You can change the cornerRadius programatically if you wish, unfortunately however, there isn’t a way to change the insets this way.

Remember to remove the insets for the MaterialButton

By setting different damping ratios and stiffness on the spring, it is possible to achieve results from restrained, to exaggerations of cartoonish proportions.