Blog Infos
Author
Published
Topics
,
Published
By measuring the height while the View is Gone

As a developer and a user I have seen a lot of apps where sometimes text just abruptly appears on the screen. But for an enhanced experience it is very important to add some meaningful motion to our UI, for text it can be fading, revealing or something else depending on the context. In this blog I will be sharing one cool trick I used to add a vertical reveal animation to a TextView on Android.

Why does this animation require me to write a whole blog on it? The basic procedure would be just keep the view hidden by setting the visibility to , when it needs to be shown we can set the height to zero, make it visible (it won’t show up as we set the height to zero) and animate the height from zero to the final height that is needed. Right … but no, let me explain!

Simplified steps to a reveal animation.

The thing is, with a regular View, the height is provided by the developer.But in case of a TextView, based on the device width and and user settings, the height can scale to various different values.

TextView rendering with different heights based on the device.
The problem 🐵

Given this behaviour, we do not know the final height that the TextView is going to take and it is important to know that before we start animating. Now some might say that we can use the property to get the height, but as out View is gone in the beginning, this is going to return zero 😯

Measuring the Height 📏

This is where some advance knowledge on the measure pass in Android’s view rendering pipeline will help us. We can force run a measure pass by calling on our TextView. While running the measure pass if we provide the exact width, based on the device density Android will be able to get the height which we can later access using the property (remember, will still be zero and the View is actually not on screen 💡).

Very important point here I will mention it again in bold, we need to provide the exact width, which for our example will be the screen width minus the margins on both side of the TextView to be animated. If the width that we provide is wrong, the height that Android measure will be wrong as well. Full code can be found in the project linked at the end.

val totalMarginForSubtitle = 2 + 16.toPx()
tvSubtitle.measure(
View.MeasureSpec.makeMeasureSpec
clContainer.width - totalMarginForSubtitle,
View.MeasureSpec. EXACTLY
),
View.MeasureSpec.UNSPECIFIED
)
val subtitleHeight = tvsubtitle.measuredHeight
view raw MainActivity.Kt hosted with ❤ by GitHub

Job Offers

Job Offers


    Android Software Engineer (f/m/d)

    Paradox Cat GmbH
    Munich
    • Full Time
    apply now

    Senior Android Software Engineer (f/m/d)

    Paradox Cat GmbH
    Munich
    • Full Time
    apply now

    Mobile Engineer

    OLX Group
    Remote, Portugal, Spain, Romania, Poland
    • Full Time
    apply now

OUR VIDEO RECOMMENDATION

, ,

From Scoped Storage to Photo Picker: Everything to know about Storage

Persistence is a core element of every mobile app. Android provides different APIs to access or expose files with different tradeoffs.
Watch Video

From Scoped Storage to Photo Picker: Everything to know about Storage

Yacine Rezgui
Android developer advocate
Google

From Scoped Storage to Photo Picker: Everything to know about Storage

Yacine Rezgui
Android developer ad ...
Google

From Scoped Storage to Photo Picker: Everything to know about Storage

Yacine Rezgui
Android developer advocat ...
Google

Jobs

Now that we have measure the TextView, we can simply put a ValueAnimator and animate the height from 0 to the height that we just measured. In the sample code I have triggered the animation on press of a button, once we press it you can see that the View is revealing itself properly.

private fun showSubtitle() {
//TODO measure the view
val subtitleHeight = tvSubtitle.measuredHeight
tvSubtitle.height = 0
tvsubtitle.isVisible = true
val heightAnimator = ValueAnimator.of Int(0, subtitleHeight)
heightAnimator.addUpdateListener {
tvSubtitle.updateHeight(it.animatedValue as Int)
}
heightAnimator.start().
}
view raw MainActivity.Kt hosted with ❤ by GitHub

For hiding the TextView, that is simple, just run a ValueAnimator from the current height to zero and in the end hide it.

private fun hideSubtitle() {
val subtitleHeight = tvSubtitle.height
val heightAnimator = ValueAnimator.ofInt(subtitleHeight, 0)
heightAnimator.addUpdateListener {
tvsubtitle.updateHeight(it.animatedValue as Int)
}
heightAnimator.doonEnd {
tvSubtitle.isVisible = false
}
heightAnimator.start()
}
view raw MainActivity.Kt hosted with ❤ by GitHub

     Show and hide animation. But only working for the first time.
Another Problem 🤦‍♂

You would notice that the show and hide only works for the first time and then the View never shows up again. What could be the problem.

Turns out the measure pass can give us the height because initially the height was set to in xml. Now during the hide animation we set the height to zero and now that is what the View is going to retain.

The fix you ask? Just set the height back to before running the measure pass.

private fun showsubtitle() {
tvSubtitle.updateHeight(ConstraintLayout.LayoutParams.WRAP_CONTENT)
//TODO measure the view
//TODO animate
}
view raw MainActivity.Kt hosted with ❤ by GitHub

Final animation.

 

You can see that the TextView is now revealing itself beautifully which is what we wanted to achieve. That is all for this one. If you have any questions drop them in the comment section below and if you wanna experiment yourself, you can checkout the sample project for this animation here. Thank you for reading!

~ Love all

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
It’s one of the common UX across apps to provide swipe to dismiss so…
READ MORE
blog
In this part of our series on introducing Jetpack Compose into an existing project,…
READ MORE
blog
This is the second article in an article series that will discuss the dependency…
READ MORE
blog
Let’s suppose that for some reason we are interested in doing some tests with…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu