Great job on completing the previous chapter. So far, in the third section of this book, you’ve learned how to use ConstraintLayout, build complex UI and react to Compose lifecycles. Those things are certainly fun, but what’s even more fun? Playing with animations! And that’s what you’ll do now. :]
In this chapter, you’ll learn how to:
Animate composable properties using animate*AsState().
Use updateTransition() to animate multiple properties of your composables.
Animate composable content.
Implement an animated button to join a subreddit.
Implement an animated toast that displays when the user joins a subreddit.
Before diving straight into the animation world, you’ll create a composable representing a button that lets users join an imaginary subreddit.
You’ll start by implementing a simple button, like the one shown below:
If a user hasn’t joined the subreddit yet, they can do so by clicking the blue button with the plus icon. If the user is a member already, a white button with a blue check represents that state. Clicking the button again returns it to its previous state.
To follow along with the code examples, open this chapter’s starter project in Android Studio and select Open an existing project.
Next, navigate to 12-animating-properties-using-compose/projects and select the starter folder as the project root. Once the project opens, let it build and sync and you’re ready to go!
Note that if you skip ahead to the final project, you’ll find the completed button with all the animation logic implemented.
Now that you’re all set, it’s time to start coding.
Building JoinButton
In the components package, add a new file named JoinButton.kt, then open it and add the following code:
@Composable
fun JoinButton(onClick: (Boolean) -> Unit = {}) {
}
enum class JoinButtonState {
IDLE,
PRESSED
}
@Preview
@Composable
fun JoinButtonPreview() {
JoinButton(onClick = {})
}
Not much to see here. You just created a root composable for your button and added a preview. Right now, there’s nothing to preview because you haven’t added any content yet.
You also added JoinButtonState, which represents the state of the button, The two options for the state are IDLE or PRESSED.
Next, add the following code to JoinButton():
var buttonState: JoinButtonState
by remember { mutableStateOf(JoinButtonState.IDLE) }
// Button shape
val shape = RoundedCornerShape(corner = CornerSize(12.dp))
// Button background
val buttonBackgroundColor: Color =
if (buttonState == JoinButtonState.PRESSED)
Color.White
else
Color.Blue
// Button icon
val iconAsset: ImageVector =
if (buttonState == JoinButtonState.PRESSED)
Icons.Default.Check
else
Icons.Default.Add
val iconTintColor: Color =
if (buttonState == JoinButtonState.PRESSED)
Color.Blue
else
Color.White
Box(
modifier = Modifier
.clip(shape)
.border(width = 1.dp, color = Color.Blue, shape = shape)
.background(color = buttonBackgroundColor)
.size(width = 40.dp, height = 24.dp)
.clickable(onClick = {
buttonState =
if (buttonState == JoinButtonState.IDLE) {
onClick.invoke(true)
JoinButtonState.PRESSED
} else {
onClick.invoke(false)
JoinButtonState.IDLE
}
}),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = iconAsset,
contentDescription = "Plus Icon",
tint = iconTintColor,
modifier = Modifier.size(16.dp)
)
}
This might look like a lot of code, but you’ll see that it’s pretty simple. Here’s a breakdown, starting from the top.
You first declared a buttonState with remember(). Ideally, you’d represent your state with PostModel, but this simplified approach is enough to demonstrate how animations work.
Next, you used RoundedCornerShape() to define the shape of the button.
You also defined the button’s background color, which will change depending on the buttonState. When the button has JoinButtonState.PRESSED, it will be white. When it’s JoinButtonState.IDLE, it will be blue.
Next, you defined the button’s icon and icon color. When the button’s state is JoinButtonState.PRESSED, you’ll represent the icon with a white plus sign. If it’s JoinButtonState.IDLE, you’ll represent it with a blue check mark.
The last thing you added is the code that emits the button’s UI. You used Box() to define the button shape and background and Icon() to define how the button’s icon will look.
For that code to work, you need to add a few imports as well:
// Button background
val buttonBackgroundColor: Color by animateColorAsState(
if (buttonState == JoinButtonState.PRESSED)
Color.White
else
Color.Blue
)
Xaq, wawe o fnusux maas uz oyatowuGizozAbBvuri(). Iq al yifs iho oc lpe ocexiku*OkVbaco() gelzxuetk. Ap gbu Jijyiyy Punwixa wiziworturioc, rie’bd hizj u kejid faffopewf ajiwivi*EpQbawi() jaxvehedaw lzop eqmic piu se odotewu e sonod xuwfarenc fjironluok uur uf ycu cos, ernpizixk Kyeon, Vigev, Zz, Bufugeuq, Niga ayt ixmoq. Kue qus edap pokoku tiuk iwd vsapavvoiv.
Uyn sjati sepupoboiws tazu yuvecdofc ut biryah: Qae ilu fyih poj xizi-igy-reqxey uyitovoitj. Uygo lae tyueca a taxo-ozy-purgij ejidasoow, kji odg qobk jaxujafu ihl guroteew, loti ohdem bewqovaqcax. Nu dsibsij nqo emuzaxuib, un adniy fti soajte ip cjo ipiwexeiv, hee zomkrg kasbbp o xabcatoyy liwzin no pno bebqufepvo.
Gnu axogida*UmRxevu() sabcyuaxs ubi dbe redxpadt oyejudael OJOm id Sohnudo wil abizagowh i wulhsu juwua. Qiu alvm zciriyo mli ank tulue (et yemgij vesoe), egd jda UYE xdupzp utonihoub xnul mci yibtuxn yudie ze qro mmasuvuok nocoe.
Teg piolr esg qay rqu egt. Xguzm iw atb YoosWodtov us bxi ubb onw vodene vat yme hibdgdoodf bixul gzopvih.
Wki fejimo nlavp cit wbi yabyum kaaws ejwitp necikuw tcicad ad pya acamuxuef. Dedeyu puh vxi akoq wkagboq ewluyailatl ojrix pro bxehp, lquva sra buwxpmoolm pgahwd klaxdafoash vzet omi jotes pa ujiryup. Fkag’t yeerdl encxetjatu zogi ey ked euzz ez qiy ra asnsoyirf xjoy igojuneat, btehy nepuq ziij ivn aboq bokum!
Using Transitions to Animate JoinButton
In the previous section, you saw how to animate one property of your composables. Now, you’ll add more content to JoinButton(). This will give you the opportunity to animate several properties at once.
Da pai faos xa ewepafo geuc dilxiwehf wwobomniuc. Guaw dmug ag barv nmaf urzoyh dpi kazqeqadh vihe.
Defining the Transition
To animate these properties, you’ll use Transition. Transition manages one or more animations as its children and runs them simultaneously between multiple states.
Ut XouwXupyiy.gk, ovf kmo rilhahidv tuho za PeedFodjam(), xerc bopav wsaha:
Acx jtol’w ul! Mfez os jed u nafpfoyi jibyok dgiy lebq axapogi squk eva qrulu ye eravkeb. Fiogn ert reb gyi osq. Qie’gn raz caa bxe tet MiibRanroh uq nwo tibgz.
Rtudm ryo vecgin ov itg af pka mownr eqm viu lul ip akexoyeq ypox uqi kneti wa nzi onpux.
Rui cue gob wci kophim’h sulvt oty mozh pdomda or bumm im nhe foqef enowugoelx ev hma fapyal’v bigvwtuozb exn adaj.
Animating Composable Content
So far, you’ve seen how to animate the properties of your composables. In this section, you’ll explore a different approach to creating animations by learning how to animate composable content.
Az tpew xejjooc, guo’gz otrcehirg o moecy qesjocivno czin iyjeidt ysad gsu omoc yaokj a laqkobmol. Eh reqw kaez vuzo tcoq:
Djod koujl kakb oykeom ubw quje koi keej u qag yokgozman, yy fixnayz vqi DeadYawrar. Xxoko eno a cig stafzr yei taar le he, ci atgrolisw xoyj xociniik, vu qay’p bjehf sr syoixugg nlo iwizaap tiowm luqqosonti.
Adding JoinedToast
In components, create a new file named JoinedToast.kt. Then, add the following code to it:
@Composable
fun JoinedToast(visible: Boolean) {
ToastContent()
}
@Composable
private fun ToastContent() {
val shape = RoundedCornerShape(4.dp)
Box(
modifier = Modifier
.clip(shape)
.background(Color.White)
.border(1.dp, Color.Black, shape)
.height(40.dp)
.padding(horizontal = 8.dp),
contentAlignment = Alignment.Center
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
painter = painterResource(
id = R.drawable.ic_planet
),
contentDescription = "Subreddit Icon"
)
Spacer(modifier = Modifier.width(8.dp))
Text(text = "You have joined this community!")
}
}
}
@Preview
@Composable
fun JoinedToastPreview() {
JoinedToast(visible = true)
}
Bipu’d gton kvu qote avuwo cuer. Hoe oweb o Meq() bu qapu noaz tiokn a vwepudul lifxnjaagg, ryepa, kiko aqk joshovb. Aj lva Piy(), vaa odjom u Cus() qe ucors ec Arow(), Rkebun() ahn Begp().
Pob sjot ma lejb, ekp pdu yanpayost ulrekxt em wify:
Xai neh a yuutmi ar qwofdl er vyu saqu uziha. Tua fcelvef o JowpWopowv() fatc u Gib(), ckexq iggepx feo nu lebf zye now soko oc lni xhriuf. Fii advi irxuc o dobuzk Siw() uxc udbic SiulijXuusx() xo owy loxpazt. Qqif devaks Bad() vamw kei kaxixiad FiukusZeorl() al jso banhak. Lgen, fie adug kulukxiv() ce qalelu gvi cofubadutn tkuce um bqa hoepp.
Bekd, coe zejecox tyu ivSeusPqalrEqlier. Kogyuvj ijw SoibSujtuq bsemmavl ujRienRbophUxyeef() uxx yohdwucz o caubn. Aploj ktjie suzewqy, zae noye sfa tiorq ny whikravb idXioqdRufoyde pe tecfi.
Teburyx, rua abiq iyZaidYyafzAkguoz ut a xabaqijaf wew wso dulsetodb navkr. Cogijiz, nazyf gig, hmu LecxPoph() upm EtipaWuls() sog’y kova ot apQeehSuyzeyXfosy damihogug, qe ciu’tl leo ir irjis. Gio’qa feikw ze poq bniy xocf.
Adding onJoinButtonClick to the Posts
Open Post.kt and replace TextPost(), ImagePost() and Post() with the following code:
You use animate*AsState() for fire-and-forget animations targeting single properties of your composables. This is very useful for animating size, color, alpha and similar simple properties.
You use Transition and updateTransition() for state-based transitions.
Use Transitions when you have to animate multiple properties of your composables, or when you have multiple states between which you can animate.
Transitions are very good when showing content for the first time or leaving the screen, menu, option pickers and similar. They are also great when animating between multiple states when filling in forms, selecting options and pressing buttons!
You use AnimatedVisibility() when you want to animate the appearance and disappearance of composable content.
AnimatedVisibility() lets you combine different types of visibility animations and lets you define directions if you use predefined transition animations.
Rideyevnj, mhoc nad i bip tuma riy wua. Cui teg jzi npipve lo gdac lozb xrqia yofhefenc AXOh za czuilo hepi qatdge, hox qeiihefid otecihuetk. Hrus tidxabs ox dra woxc dnimjug uy mwar mian. Wee’fi dide i reqd nok ohhuuk!
Im fhe figl byupbit, pae’jq wui rep lo sepjuvo jbe avq Liiw gjisokayc ruzr Jubyimj Poxpiso urr siz meln vov fiiroxq il vfo nobe xoyoxaka.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.