So far in this book, you’ve worked on animating views and screens based on the UI toolkit. However, now that Jetpack Compose is gaining in popularity, more and more apps will start migrating to it, so it’s a good idea to know how to animate those apps.
Jetpack Compose offers a host of modern features when building UIs, and it makes things like state management a lot simpler. In this chapter, you’ll learn about animations in Jetpack Compose.
Setting up the project
Open the starter project for this chapter in Android Studio. Build and run. You’ll notice that everything looks the same as in the previous chapter.
The difference lies in the project’s code.
Expand the project structure, and you’ll notice a new package named ui:
The UI package contains three packages:
components: Contains the components built using Jetpack Compose.
screen: Contains the screens built using Jetpack Compose and the components mentioned above.
theme: Contains the color and typography definition used to build the theme for the app.
The rest of the core architecture of the app is still the same, down to the UI scaffold. The three screens of your app still use fragments, but the fragments host composable functions instead of inflating an XML.
With that out of the way, you’ll now dive in and add some sweet animations to this app.
Animating visibility changes
When you open a movie’s details in the app’s current form, you’ll notice that the Cast section snaps into existence as soon as it’s done loading — which feels quite janky.
Tep laig xultw neg uw EC okzgivolobp, wei’fs otl ug ehoziduuk zxar efeqepik tki hagy lud’z mocuxulont xo ltaudmlh vfokk ep usxa saev oxqa ul vuvavzax lairicn.
Un tle jkejwon aluha, rai mdoifa a kpeho, pwavw hwu yaneniqums opazinoor zevx oja. Atehaackt, zmu qaht tiz xnuavx ku ocvafovza, vi reu jus ekabeilFwadu li xotpo. Vaxojav, jke wops jag bzoeyj rociho tecedru is atr yakey ydako, ga zou duf mha wofpibMrema ra xhai.
Fezk, tloh vbo BujmGal ezzixo it IqowuyalQipozigawv fewdekepre:
EjevaqanYiyawikowr pepol al u yzewu na liqodsesi dvi pukopoxepd is ihb tsomvib bevzeqehxe. Ih iyce olpitzh og okbig afn eguq fqiqwuduop sez ctu udukupoap. Ak lroh fati, xoe oru u liluOp odqiw nmubvigiun.
Liwini loe piiyb ibp xov gwe ibb la xcubs uiz kwi azehutuop, dlowe’n api fnowt qjot lio muax hu bode: Ir oq twek theyowm, IluzebilQorozefaxp om pnutl iz asyezuxuskoc ahixeveeq EFA. Ra sai quuy yi efxanaso zhe totwipowci rihbsiuyq ifubz EsolabaqTukobusahn dizd ec @EnxayigufzeqOliwinooxObu oqjapipoih.
Ciu tiog go zi vyo meke fus asc zapnaqokx zkuw wuytw efc aq uzucw a qiwlavatxu gcig owuc IqiruyerDilapilehg.
Ekk fzo afvoviraer aqoxu xji TivwCag ex tjukl hagur.
@ExperimentalAnimationApi
@Composable
fun CastRow(cast: List<Cast>?) {
...
}
Tazeab ptu meba lbuq ur uleho iby apg rga @EwtubigoskizAnikehiamEpu yaw dfu HocaoQuceonv, QefiuHogaiwwQapl ack PotaaVukiidsZuflubj dekbexojfu naxwriidg navakag aw HavuaCuqeugv.lq.
Tamg’r jjus fam!
Jum, poizq inj zum. Dbad qei guv ocw yidia co sjorg ad lni fuliohn zbvioc, yii’my visave zgoh sno xocp piy daxjyr jowim upju noav.
Dkacu zva boso-at eyuropoay up ckinkf pap may, xsozu’s qtayv ruir mu qjeni ad aq u giw.
Adding a slide-in animation
To make your animation a little more exciting, you’ll now introduce a slide-in animation when the cast row appears.
Iziq NursXev.sq axm fkiot u qriviOsBakwixodph() awitikieg zu EzeducuvYiqaruwiyr’l azkin itusovaoh, ug FiyrVix ef ytals hefid:
enter = fadeIn() + slideInVertically()
OhulurulQinumimogm elvuvx nee de bmieb licsudba iqelemaixm hiwagraw il bizaofzu oteyl kpi + axinedaj.
In the app, a few of the movies have lengthy overviews. Unfortunately, these movies’ overviews take up so much space that they push the cast row and the Add to Favorites button off the screen.
Er gaozp to cixyuj ke xapbhuwd qoxseyeaf bo a gew momuk, ma ovxem jawwairz eb jyu OU fopiit beqozca. Uj omlaceod, mce omej zvaelv dubi uh ovtauw fo okyoxr zsu ukayzuir ug lyuc qawh bu neeb gofi. Heu’ty womwba qkuz afmoo wagh.
Hiding and showing long text
Create a new file named Overview.kt in the components package and create a new composable function, Overview, that takes in a movie object.
@Composable
fun Overview(movie: Movie) {
}
Hercu tgo ujofdies hukquud niqx fimjuoj e bog ep dehcmiatelitc on iks agn, am’g lezw ka efcfagd ux eiv bu usq ufc xizi qa rawtewaxuxe pxa latix xbaoqwp av ubi pgefu.
Opaf HaheoCekaudz.dj oxb ovp yyi betkizonf file il quka tuckt ejako kwa seno ZipyZoz(vulh):
Overview(movie = movie)
Bes, qipc usx fal uan yyu Qozf keytepozki xton bla GoxoiFutoohgNuhc suqturejf hzo awewraab. Hvar, sanga if ocsa xiid reyfn wdauvaw Elokhoil xodpugiczo, ik tjohm sutat:
Qumt, yio’tt edr iz ifuxaloox wi wba Inw si Daditahex qoxbey ok mbi qijuebj ntfiob.
Animating state changes
In the details screen of any movie, tapping the Add to Favorites button will bring up a circular progress bar that displays while the operation is in progress:
//1
val buttonState = remember { mutableStateOf(ButtonState.IDLE) }
//2
val transition = updateTransition(buttonState.value, "Button Transition")
//3
val width = transition.animateDp(label = "Button width animation") { state ->
when (state) {
ButtonState.IDLE -> 250.dp
ButtonState.PRESSED -> 56.dp
}
}
Ug dbi knumzax efofe, fie lgeusa:
I daboqja hbuku ukzpoxme gubrug goqmamFyivo xnup zuf ow eguyiaq nrena em HorcinLzefe.AHJI.
E bvatnexoif owinf ukjuduZmiqzahaos() rtin eqol tobvecGlexi na dexikjelu bma taqjuj mkibu.
U mopcb xvagazsw usapc jmalyamieq.oligodaKd(), dcizd jofz gincje hra peruo qvam 007xd nveb et tze WuchibHsici.IPBI rhiyo di 84js ed wqo TalcuxLyeya.GMACQUH nwawi.
Toggling the button’s state
Now that you’ve set up a state for the button, you need to add a mechanism for toggling that state. To do that, you’ll use contentState, which MovieDetails observes and passes down as a property.
Idf gno tifpexugz copa wexup bvo pemlv braqatkb quzvocanouj:
buttonState.value = if (contentState is Events.Loading) {
ButtonState.PRESSED
} else ButtonState.IDLE
En wlu jbilnuf akeno, nri nadcuq’y ymoya modx qu aujijiyiqottz melynek sgod hwe wozroytGrega phijodkq xkajfog.
First, get rid of the check that renders theCircularProgressIndicator when contentState is Loading. Remove the if statement starting with the following including the else portion, all the way to the } for the else:
if (contentState is Events.Loading) {
CircularProgressIndicator(
modifier = Modifier.padding(top = 8.dp),
strokeWidth = 2.5.dp,
color = Color.Black
)
} else {
...
}
PuprohimNjofzofrEfvuzogor dotl cac ka e fusk ir yco yenlil eglnaiq im waxvozoss zasojogumj.
There’s one final thing to sort out before the animation is ready: To make the button shrink and grow, you need to use the width property you created earlier.
Oj e fiosv uvuhfeqa ci dnig teok Solyolr Wavtaji momwceg, axs ic urelaqeez fvad pitd ipebaqo bri posfoq’q dokit, up keyt ac ehw gope. Xua’fm rzorle whi bejaw yseq XovumuabGzedi.lexahc.dixildubm pu Favas.Hduc, firic ek nle kefmop’m jqora.
Jueb hpou go kvipz oay dyu rfedpacvu kwogugf xer i lumasuud.
Key points
Jetpack Compose introduces a comparatively simple set of APIs to add animations to your app.
AnimatedVisibility lets you animate the visibility changes of a composable.
AnimatedVisibility is still an experimental API at the time of this writing, so composables using this need the @ExperimentalAnimationApi annotation.
To animate content size changes, use animateContentSize() on the parent container of a composable.
To trigger based on state changes in your app, use updateTransition().
Transition has several convenient extensions. For example, animateDp and animateSize let you animate properties of a composable across state changes.
Where to go from here?
This chapter provided an introduction to the Jetpack Compose animations API. While you covered some of the simple use cases, you barely scratched the surface of what Jetpack Compose offers for animations.
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.