Round corners animation

Aleksei Shcherbakov
2 min readMar 23, 2021

One of my screens has collapsible header with tabs, and designer made rounded corners for tabs. But how it should look in collapsed state? I decided to implement animation, which I saw in bottom sheet in another app. It should look like this:

Layout file:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/purple_200">

<FrameLayout
android:layout_width="match_parent"
android:layout_height="@dimen/header_height"
app:layout_scrollFlags="snap|scroll">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Header"
android:textColor="@color/white"
android:textSize="30sp" />
</FrameLayout>

<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="@dimen/tabs_height"
android:background="@color/white"
app:layout_scrollFlags="noScroll">

<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tab1" />

<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tab2" />
</com.google.android.material.tabs.TabLayout>

</com.google.android.material.appbar.AppBarLayout>

<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="24dp"
android:text="Content"
android:textColor="@color/black"
android:textSize="30sp" />

</androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

We will use MaterialShapeDrawable from Material components library. To import it add this line to build.gradle file:

implementation 'com.google.android.material:material:1.3.0'

Now we create background drawable with 2 round corners for TabLayout.

// Create background drawable for TabLayout
val shapeAppearanceModel = ShapeAppearanceModel()
.toBuilder()
.setTopLeftCornerSize(cornerSize)
.setTopRightCornerSize(cornerSize)
.build()
val materialShapeDrawable = MaterialShapeDrawable(shapeAppearanceModel).apply {
fillColor = ColorStateList.valueOf(Color.WHITE)
}
ViewCompat.setBackground(tabs, materialShapeDrawable)

And finally, we are animating corners. MaterialShapeDrawable will make all job for us. It has interpolation property, which documentation says: “Set the interpolation of the path, between 0 and 1. Ranges between 0 (none) and 1 (fully) interpolated. An interpolation of 1 generally indicates a fully rendered path, while an interpolation of 0 generally indicates a fully healed path, which is usually a rectangle.” So, we’ll change this property in range from 1 for round corners to 0 for rectangle.

// Listen AppBarLayout for scroll
appbar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
val collapsedHeight = appBarLayout.height - tabs.height
val collapsePercent = -verticalOffset.toFloat() / collapsedHeight
// set shape interpolation: 1 is fully rounded, 0 is rectangle
materialShapeDrawable.interpolation = 1 - collapsePercent
})

It’s not so hard when you have right library, right? :)

--

--