How to animate BottomSheet content using Jetpack Compose
source link: https://proandroiddev.com/how-to-animate-bottomsheet-content-using-jetpack-compose-3eab972b3bdc
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
How to animate BottomSheet content using Jetpack Compose
Note: Everything in this post related to Compose 1.0.1 and maybe in the future Google will introduce a new API and approaches like Compose MotionLayout š°
Early this year I started a new pet project for listening to random radio from over the world. The UI at the beginning was very simple and clear, just a logo with the station name and necessary controls. The main functionality is integration with Android Auto, but it is a topic for a separate story (just ask in the comments if you are interested in this theme).
Using the application, it became necessary to see user liked stations, other categories separated by genre and country. The idea is to make a Home screen with a list of different information and player which can be shown and hidden on the screen.
Find available solutions
As a normal developer, I started to research existing compose projects to find already implemented functionality.
The official and community samples contain only the UI part and donāt include any interaction.
For example, the Spotify UI demo application for me implies a presence player screen, but in source code, itās just a Row with content.
Another interesting repository I found is a Podcast App. According to the gif looks like what I was looking for.
After inspecting the source code I understood how it works. The PodcastPlayerScreen is a Root composable for the player and it added to the composition of the main screen. By default, itās not visible for users.
Then if the user clicks on some podcast item it changes the showPlayerFullScreen boolean. Recomposition triggers the AnimatedVisibility logic and the player appears.
Further interaction refers to listening swipe offset and move the player along the Y-axis on the screen.
From my perspective, it's not an ideal solution, because it is tied to the ViewModel state, the unobvious showPlayerFullScreen variable which can be changed in different places, also we need manually operate with offset, and so on.
Letās stop research and try to make a more simple and clear solution.
BottomSheet story
Out of the box, Compose contains two types of BottomSheet implementations:
To make a simple screen with ModalBottomSheetLayout we just need to initialize rememberModalBottomSheetState with initial Hidden state, create coroutine scope for future interaction with visibility and that's all.
ModalBottomSheetLayout exampleUnfortunately, ModalBottomSheetLayout doesnāt have the ability to set peekHeight.
peekHeight ā he height of the bottom sheet when it is collapsed. Simply speaking bottom sheet will be on the screen permanently, but in the collapsed state.
BottomSheetScaffold is trying to solve this issue and introduce this customization. The simple screen setup is pretty the same, but we are able to set peekHeight as a parameter.
BottomSheetScaffold exampleImportant note:
In different posts I saw wrong initialization of rememberBottomSheetScaffoldState without remember block for bottomSheetState.
It can lead unexpected bottomsheet behaviour after recomposition like non responding to touches, able to drag in different direction and so on.
The correct one should be:
Working with BottomSheetScaffold
In the sample project, I have added the demo UI for the radio player with collapsed and expanded state. The main goal now is to animate from one state to another one.
collapsed and enabled stateAt the first step, we need to know the current BottomSheet state.
The good news for us is that BottomSheetState inherited from SwipeableState and we can try to access fields currentValue andtargetValue.
BottomSheetState source codeThe code will look pretty simple, we just read the necessary data from bottomSheetState and show it on the screen.
Well, now we know the state of our screen and animation direction. But thatās not enough for animation, we need intermediate values between Collapsed and Expanded states.
Digging through the source code I found that Swipeable storing information about the ongoing swipe or animation in a special progress field.
Swipeable source codeSwipeProgress is a class with from/to parameters and fraction. The fraction represents the current position between from and to.
SwipeProgress source codeLetās use this. Updated DebugScreen will look like this.
Looks nice, but unusable now. If you look closely you will see that fraction starts from 0 every time and finishes with 1.
For beautiful animation, we should definitely assign fraction for states:
- Expanded ā 1f
- Collapsed ā 0f
A little math and we get this extension.
Super, this is already 90% of the result. Now we can apply the calculated fraction to any composable function and dynamically change the alpha.
In this code snippet, I change the alpha of the root collapsed element relatively to a fraction.
Looks pretty, doesnāt it?
Bonus
We can try to animate BottomSheet corner radius relatively to a fraction.
For example, for the Collapsed state, we wonāt have any rounding, but for Expanded we want to have 30.dp.
The below code allows achieving dynamic corner radius change.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK