Migration to compose
Let’s creating an app using compose instead of xml
Compose is part of the Jetpack Library released by Android last spring. Create Android UI faster and more powerfully and by declaring composable functions. I was in a situation where I had to start reorganizing the Android app structure that I was servicing, and I applied it to the Toy project first to think about introducing Compose. So I applied it to the Harry Potter app that I made.
Write UI ✈️
Let’s get a look at how looking at the example of changed. This is the xml that made up the MainActivity
.
LottiAnimationView
was used for background animation and had logo images and horizontal scroll views(using RecyclerView adapter). Let’s look at how it changed in Compose.
Box
work as a FrameLayout
, stacking them up in the order they are written. So I wrote a Lotti for compose(composable function wrapped to infinitely animate) and used a Column
. A Column
is a widget that has a vertical structure of an existing LinearLayout
. It replaced the xml margin written on top by a Spacer
margin in the Column
.
Now let’s look at how you replaced the existing horizontal scroll view. I replaced the existing horizontal scroll view with the Appcompanist-Pager without using the LazyColumn
because it contained a snap function.
⚠️ Accompanist Pager is experimental. The API may be changed in the future.
As you can see from the name, Pager
are more like traditional ViewPager
. By calculating the offset of the current page in the graphics Layer
, the existing scale animation effect was reproduced. graphicsLayer
can be used to apply effects to content, such as scaling, rotation, opacity, shadow, and clipping.
In addition, if you read the state inside the block with animation value, no recomposition and relayout are executed, only the properties of the layer are updated.
When showing a compose in the activity, simply declare it within the setContent
block 😮
Manage State 👀
Now let’s take a look at the DetailScreen
. The DetailScreen
contains a list of HarryPotter characters, and a dialog appears when you click the item. and this screen It contain a little animation.
On the 6 line, the viewModel
is injected through the Hilt, and on the 8 to 15 lines, the State
is passed to the variable.
getLifecycleAwareState
Block is extension method that initiates consumption and production of flows when the current lifecycle state of the compose is Lifecycle.State.STARTED
and stops when it is in the background state. also remember
composable can be used inside the composable function to store objects in memory. The original look is as follows.
The selectedCharacter
of the DetailViewModel
is SharedFlow
, which triggers the received value when an event occurs. In addition, the isLoadingFlow
state of the DetailViewModel
is StateFlow
, which receives the value and changes it to State
. See this post for information on how to safely collect Flow
in the lifecycle.
RecyclerView ♺
Let’s talk about it again DetailScreen
. I had to use GridLayoutManager
in traditional RecyclerView
because I used grid-formatted lists . So it replaced it with LazyVerticalGrid
compose.
⚠️ This foundation API is experimental and is likely to change or be removed in the future.
Lazy composables makes it easier to create a list that behaves the same as a RecyclerView
without an adapter!😮
ConstraintLayout ⛓
How did the ConstraintLayout
, which was previously useful? It’s easier to use than you think.✨ I used the ConstraintLayout
on the list item.
After declaring a ConstraintLayout
, create a reference variable through a createRefs()
inside the block. And pass it over to the parameter of Modifier.constrainAs()
and create a constraint through linkTo
method.
You can also dynamically specify the height
and width
by using Dimension
(preferredWrapContent
, wrapContent
, fillToConstraints
). Each Dimension
is described as follows.
-
preferredWrapContent
: ADimension
with suggested wrap content behavior. The wrap content size will be respected unless the constraints in theConstraintSet
do not allow it. To make the value fixed (respected regardless theConstraintSet
),wrapContent
should be used instead.-
wrapContent
: ADimension
with fixed wrap content behavior. The size will not change according to the constraints in theConstraintSet
.-
fillToConstraints
: ADimension
that spreads to match constraints. Links should be specified from both sides corresponding to this dimension, in order for this to work.
Dialog ☎️
Dialog
is show
and dismiss
through Effect. If you look at the internal code first, it looks like this. Among the parameters, callbacks of dismiss
events are available through onDismissRequest
, and use DialogProperties
to can control the dismissOnBackPress
, dismissOnClickOutside
.
I put the event of the DetailViewModel
in onDismissRequest
so that the dialog can be dismiss normally.
Conclusion
Although there are features and bugs that have not been used all the functions in the Compose and are not supported because they are still in beta, this nevertheless seems quite good. It felt that xml was not needed and very easy to reuse and maintain. The official version, which will be released in July, is expected to be more stable and convenient.
Thank you for reading my post and feedback is always welcome 🙌 All source code can be found at the link below!👇