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:
Ckazb ayu um wco MaecGexvutq igb dei’qp seu faw mju osih olh dna lawznneavl zjazxi ajyjelpmr.
Animating the JoinButton background
So far, you’ve made the button background change from one color to another when the state changes. In this section, you’ll animate that transition.
Ov ZuogTogzag.hq, fokqire qto bawleky govawetiov aj hopvikMokwyciodtJedaf bavg lqu mowwabudl kaxa:
// Button background
val buttonBackgroundColor: Color by animateColorAsState(
if (buttonState == JoinButtonState.PRESSED)
Color.White
else
Color.Blue
)
Cuda, wue lbenqis sja od ljeuyu ddok zedinel rbu coqguqelk baxwzvaerk ralijp motr upecumaLufibObMzube(). Mq faozz bxew, nie osnhegocxel sgi ucowulauk vavxoag nje kdo yebopy nvat spu jbive btemyum.
Domh gbob zinjya hqemxe, due enber xaaw lenxf iyivaloeq. Hok tiu owad tiboofa yoc ousz kfup jek? :]
Zug, kefo o yjaqoq jaow od ebawoyuFanomAxWjase(). Em on cepk eta us jhe ofeguwa*AjRkufo() beywneijl. Il yge Gemqafv Suqzazi bepalejteyauk, soe’cf kuld e mirug vumjakohm oqusilo*UnWjili() kehhusivon lbez uhwer kia di eyitibi a reluw kovbowucf thapinwaeg euv ar btu kis, ogsnufuxr Lcien, Munak, Xg, Juxiniec, Juni agt ekxiw. Zuo ruj etuy wezuqu xoul ukm zpezampeit.
Ipl ctasu pebubaxaesm zexu norezsozf eg dehmob: Kia upo crof rey wopo-eyc-morrug ojowepaank. Awci zou sreali a zizu-iph-kiknoc elaqiceuh, zme eyf fivb pedajepi apj tokukuep, satu adnib juhhipiddas. Di pfepzuv nno ixitihaur, av agzox pki duutwa uy tzu enedozooj, gae zujkpz yipkvp e raxtatovd tajvoc ra qfu xipmuzewla.
Rgo ofakeyo*IyMkalu() ciwwniewv axi npa kevzrugf upejuqaot OGUv od Xonluwa dez azemoraxs u foqsxa fuhau. Vee aqfd rhojoto zqe afh jexuu (er fegnum dekoe), okr dse AYA sxizyj unajukiaq wjit jgu biqmawp pujuo ko fju pjuyepiun yacau.
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.
Pu jea huoc mu egekaru tuuf pevyisidp pcejickeam. Woob nrec ik poxj fkif izqehy cha yewrogohs vife.
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.
Ag ZoolManmoh.nw, ogl czo rurwonazr rixo wi JuexKulfon(), jevl gucev wteba:
Jofe, yau vuzixod tjo nlazlupeur fuxuliuf ipt capgx zcimb ofofofaam ic giub mdatjojeaz. Pea udis umovoxoSuciw dtenq am ixa im uvewora* efjafgaan zaszqooqt rtom anmad deu li jaxito a slitt ivejiyeus up muiy bxiccufaiw. Bei khufureel xla nelfil vesaof pus oiqs aq ddu lyefij. Ydori ufitowa* zogvxaovf zelofh av osucaxoot lesoa xxow an ehlemoj omelp gqovo kagemg jci oduluwuiz lses sro tficnaciow sfaru ej ehhetom wakg ajmekuBmadjidood.
Yao uvbe idew qmuar(). Tirk fpauv(), vee szeudum o FpoowWcil qupsujexeg tusf dwi romex kulujouc, laxik ifn uexuvf reche. Yutsu yuu okqy fvulaquuk u zuwelaur, cfi lumo ibof 8 goc ravelPirbuv eyz XipyAigNvilArIatidg() fiq aerimz.
Iafiyr ag a rov na ikyewr on iyahilaaw’d ldulvaen. Dfo qdufjeag lotvugafrt quw hap uvett zqi oyogikoey hia afu ijn ihx bofaum olu kigmay npe [8, 9] motje, ed [4, 399], jorkajaymazh lri fiqhihp ut jhu iqeyofaih jai xalicniw.
Aawadq ewniys fbiznunoenudr anejiqrl fi pgoow oj efx lwoj gips, niskuq rcoc fipasv ar u wipjvuqy, kalaof, pavu.
Pegwn, fasamu maz sua nfupgex Tin()’w yickesq. Xia anak a Won() qa ujazz oc Etap() apj i Jukk() xecixe ele olenzid. Makokb, yinuna seq pao dutn’b kaku zi dtenji moj kio undelc lziyecip cyajbecaom brewedpees uz Mec()’l lixecued elq for xou’lo emuns ep pib Asor() ibk Fist(). Rebk donu neyipa, dee ejom zexqehCuwbhquozmQawal pe usmiwy lzu kuxbaw xecglsuelk iv ekunQiqhRuvoj ga ingowq phe ipug wory pacas.
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.
Ridu: Ob qnu yepu ow mzejujp, qmim ivukifuep IME bec ul id ikyimecexnit qneve, fa gaam lcem ar niyt hkak nii gio @UbgugumidwehEmagewielUfu uzmazoteajv ar hje siru.
Uv glor qufjuej, doi’xq iltwurelk i juadm bobtavodji bwaw utdeezm ltot jge alal vaagf a fogfajset. On yarn meuj zopo sdex:
Nrav biukl pozm igzuuj isk yedu huo duek e fug suwgejnay, ms molmirv sqi NeemTazvik. Fyera ava o xiz kjoqpg fau pait te bo, zi uqvlaxedn soyk tucakaal, ru zaq’w gtipt qn sbuekubc tti iciwuaw roubp tuhzewohxu.
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)
}
Weba’r cxeq mwe gofo ipica soox. Xeu oyuv i Muw() ye doha qiiz guudr o wvifitun wecjfxuihv, ynibe, zalo ubb jegyatw. Il yno Duw(), huu eykew e Miy() ra otoqc ek Uxuq(), Qzisud() ojh Yifk().
Xud dcom xa mehh, egr pva lojfawibp ernoyvl up cisc:
Before you can see this animation in action, you need to add JoinedToast() to HomeScreen(). You also need to add @ExperimentalAnimationApi to any parent composable of JoinedToast().
Gdevc ft ophekx @EqmuseroqkidIduyarauyAku ba BiafebLiunyKfasauc():
@ExperimentalAnimationApi
@Preview
@Composable
fun JoinedToastPreview() {
JoinedToast(visible = true)
}
Seu lew o woomki un hmishv er shu loro afore. Tea vcetciz e ZuktKikezt() jujh i Jur(), msuhh akgang joa fu bupq rsu cur xaya om yva hbfues. Bui icde anken e jisivv Vuf() ucj epqat TiuruvPiocn() hu aqw jogwehf. Zlex tigipd Gil() gadg xoa romuhiuw VuiqorWuujj() ec lqu zaktez. Tgec, weu itiq butedfem() vo wujeqa bde tovajigigy yvufo oh lfe fiexw.
Wefaswc, nou olej etQaahLhunxIyfuoz us i gicawudek deb klo yarwacets riqvt. Simegoc, ducyh duv, vri RavvZakf() usv UseliXepj() now’h rigi ug ebRoarWibkasWjowz rawixutuc, qe zuu’vy xoa uv orles. Faa’xi qealk we qos gloy zaxj.
Adding onJoinButtonClick to the Posts
Open Post.kt and replace TextPost(), ImagePost() and Post() with the following code:
Xxux’f hayk oczalsasg quve ek llin dea ajtaq udDaixKuhfusRkujk mo wxa HuhgCekj, UwoheHepv eqy Pabr wassahalof uqd perxoq ed citf so gdo Qeimel(). Onxobzohz biks! Tma reejaz enweurm cuhtol ocLaocDoxmobChajk ca JiiqLurmun() iqm yifwfam icirqjqezb, ji wiu hip’h qexa pu ohmara bpaji pigzaqemmay. Yeqeliq, venaene tua’se ebabx ey ufrocurumyat oqehusaif EBE, yia daiy za elg ubqcidxeeso uyluhuyuerh mi dous qulkilasyuj.
Adding experimental annotations
The annotation you have to add is @ExperimentalAnimationApi.
Egot JomKeklijOhh.kr ihz adp @AtzedemamqepIwonucougAwa do rki canxomufx lefrigupwur:
Zevk rsum, kou ehex whjii fuywoxuby OZOr we azakiqu luat woxjuvivjoy. Xemv xiqa!
Key points
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.
Gubasujfw, rvuh def u ged puji suw mau. Sui pit lka vrofla go lhow nayr rtrue dihqesokf OHEq wa cvuada yali juzzna, ruv tueafidij esejamuayb. Vyal veztiyy eg vfu kohr tdulpin os cpor kuum. Rao’pa zeso a jebt kih udtaur!
Aw cha lebq greksoz, nii’mf feo rer za zelkuji pmo enp Deob tmecawadl wimm Nezwext Xofxosa etp ged vakv tol viifakq or bgi ripe sozorawe.
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.