HomeAndroidConstructing Reddit Recap with Jetpack Compose on Android | by Android Builders...

Constructing Reddit Recap with Jetpack Compose on Android | by Android Builders | Android Builders | Apr, 2023


This can be a visitor publish from Reddit Engineer, Aaron Oertel, on how they’ve leveraged Compose of their Android App.

After we first introduced Reddit Recap to our customers in late 2021, it was an enormous success and we knew that it will come again in 2022. And whereas there was just one 12 months in between, the way in which we construct cell apps at Reddit basically modified which made us rebuild the Recap expertise from the bottom up with a extra vibrant consumer expertise, wealthy animations and superior sharing capabilities.

One of many largest adjustments was the introduction of Jetpack Compose and our composition-based presentation structure. To completely leverage our reactive UI structure we determined to rewrite the entire UI from the bottom up in Compose. We deemed it to be price it since Compose would enable us to specific our UI with easy, reusable parts.

On this publish, we’ll cowl how we leveraged Jetpack Compose to construct a shiny new Reddit Recap expertise for our customers by creating reusable UI parts, leveraging declarative animations and making the entire expertise buttery clean. Hopefully you may be as bananas over Compose as we’re after listening to about our expertise.

Design mockups of different Recap card layouts

For these of you who didn’t get an opportunity to make use of Reddit Recap earlier than, it’s a assortment of various playing cards that whimsically describe how a consumer used Reddit within the final 12 months. From a UI perspective, most of those playing cards are comparable and include a top-section graphic or infographic, a title, a subtitle, and customary parts just like the shut and share buttons.

With this construction in thoughts, Compose made it actually handy for us to create a template for the bottom for every card. This template would then deal with widespread operations the playing cards have in widespread equivalent to positioning every element, dealing with insets for various system sizes, managing fundamental animations and extra. To offer an instance, our generic card that shows an illustration, title and textual content may very well be declared like so:

We might then create a Composable operate for every card kind that leverages the template by passing in composables for the completely different types of playing cards utilizing content material slots.

For the 2022 Recap expertise, we needed to raise the expertise and make it extra pleasant by making it extra interactive by means of animations. Compose made constructing animations and transformations intuitive by permitting us to declare what the animation ought to appear to be as an alternative of dealing with the internals.

Animated GIF showing Reddit Recap’s animations

We leveraged enter and exit animations that every one playing cards might share in addition to some customized animations for the consumer’s distinctive Means Card (the shiny silver card within the above GIF). After we first mentioned including these animations, there have been some issues about complexity. Prior to now, we needed to work by means of some challenges when working with animations within the Android View System by way of managing animations, cancellations and think about state.

Luckily, Compose abstracts this away, since animations are expressed declaratively, not like with Views. The framework is accountable for cancellation, resumption, and guaranteeing right states. This was particularly essential for Recap, the place the animation state is tied to the scroll state and manually managing animations could be cumbersome.

We began constructing the enter and exit animations into our format template by wrapping every animated element in an AnimatedVisibility composable. This composable takes a boolean worth that’s used to set off the animations. We added visibility monitoring to our top-level, vertical content material pager (that pages by means of all Recap playing cards), which passes the seen flag to every Recap card composable. Every card can then cross the seen flag into the format scaffold or use it immediately so as to add customized animations. AnimatedVisibility helps a lot of the options we’d like, equivalent to transition kind, easing, delays, durations. Nonetheless, one difficulty we bumped into was the clipping of animated content material, particularly content material that’s scaled with an overshooting animation spec the place the animated content material scales outdoors of the guardian’s bounds. To handle this difficulty, we wrapped some animated composables in Packing containers with further padding to stop clipping.

To make including these animations simpler so as to add, we created a set of composables that we wrapped round our animated layouts like this:

A particular a part of Reddit Recap is that every consumer will get a singular Means Card that summarizes how they spent their 12 months on Reddit. After we first launched Recap, we seen how customers liked sharing these playing cards on social media, so for this 12 months we needed to construct one thing actually particular.

Animated GIF showing holographic effect of Ability Card

The problem with constructing the Means Card was that we needed to match a variety of custom-made content material that’s completely different for each consumer and language into a comparatively small area. To realize this, we have been initially trying into utilizing ConstraintLayout however determined to not go that route as a result of it makes the code tougher to learn and doesn’t provide efficiency advantages over utilizing nested composables. As an alternative, we used a Field which allowed us to align the kids and achieved relative positioning utilizing a padding modifier that accepts proportion values. This labored fairly effectively. Nonetheless, textual content dimension turned a problem, particularly after we began testing these playing cards in several languages. To mitigate textual content scaling points and be sure that the expertise was constant throughout completely different display screen sizes and densities, we determined to make use of a hard and fast textual content scale and use dynamic scaling of textual content (to scale textual content down because it will get longer).

As soon as the format was full, we began trying into how we will flip this static card right into a enjoyable, interactive expertise. Our movement designer shared this Pokemon Card Holo Impact animation as an inspiration for what we needed to attain. Regardless of our issues about format complexity, we discovered Compose made it easy to construct this animation as a single format modifier that we might simply apply to the basis composable of our Means Card format. Particularly, we created a brand new stateful Modifier utilizing the composed operate (Word: This may very well be modified to make use of Modifier.Node which presents higher efficiency) wherein we noticed the system’s rotation state (utilizing the SensorManager API) and utilized the rotation to the format utilizing the graphicsLayer modifier with the system’s (dampened) pitch and roll to mutate rotationX and rotationY. By utilizing a DisposableEffect we will handle the SensorManager subscription with out having to explicitly clear up the subscription within the UI.

This appears roughly like so:

Making use of the graphicsLayer modifier to our means card’s root composable gave us the neat impact that follows the rotation of the system whereas additionally dealing with the cleanup of the Sensor assets as soon as the Composition ends. To essentially make this characteristic pop, we added a holographic impact.

We discovered that we will construct this impact by animating a gradient that’s laid on high of the cardboard format and utilizing coloration mixing utilizing the BlendMode.ColorDodge when drawing the gradient. Colour mixing is the method of how parts are painted on a canvas, which, by default, makes use of BlendMode.SrcOver which simply attracts on high of the prevailing content material. For the holo impact we’re utilizing BlendMode.ColorDodge, which divides the vacation spot by the inverse of the supply. Surprisingly, that is fairly easy in Compose:

For the gradient, we created a category named AngledLinearGradient that extends ShaderBrush and determines the beginning and finish coordinates of the linear gradient utilizing the angle and drag offset. To attract the gradient over the content material, we will use the drawWithContent modifier to set the colour mix mode to create the holo impact.

Now we now have the facility to use the holo impact to any composable factor just by including the Modifier.applyHoloAndRotationEffect(). For the needs of science, we needed to check this on our app’s root format and belief me, it’s ridiculously lovely.

As soon as we added the animations, nonetheless, we bumped into some efficiency points. The rationale was easy: most animations set off frequent recompositions, that means that any top-level animations (equivalent to animating the background coloration) might probably set off recompositions of unrelated UI parts. Subsequently, it is very important make our composables skippable (that means that composition will be skipped if all parameters are equal to their earlier worth). We additionally made positive any parameters we handed into our composables, equivalent to UiModels, have been immutable or steady, which is a requirement for making composables skippable.

To diagnose whether or not our composables and fashions meet these standards, we leveraged Compose Compiler Metrics. These gave us stability details about the composable parameters and allowed us to replace our UiModels and composables to be sure that they may very well be skipped. We bumped into a number of snags. At first, we weren’t utilizing immutable collections, which meant that our listing parameters have been mutable and therefore composables utilizing these params couldn’t be skipped. This was a straightforward repair. One other surprising difficulty we bumped into was that whereas our composables have been skippable, we discovered that when lambdas have been recreated, they weren’t thought of equal to earlier cases, so we wrapped the occasion handler in a keep in mind name, like this:

As soon as we made all of our composables skippable and up to date our UiModels, we instantly seen large efficiency good points that resulted in a very clean scroll expertise. One other best-practice we adopted was deferring state reads to when they’re actually wanted which in some instances eliminates the necessity to recompose. Consequently, animations ran easily and we had higher confidence that recomposition would solely occur when it actually ought to.

Our superior new expertise was one price sharing with associates and we seen this even throughout playtesting that individuals have been excited to indicate off their Means Playing cards and stats. This made nailing the share performance essential. To make sharing a clean, seamless expertise with constant pictures, we invested closely into making this nice. Our targets: Enable any card to be shared to different social platforms or to be downloaded, whereas additionally ensuring that the playing cards look constant throughout platforms and system varieties. Moreover, we needed to have completely different side ratios for shared content material for apps like Twitter or Instagram Tales and to customise the cardboard’s background based mostly on the cardboard kind.

Animated GIF that demonstrates sharing flow of Recap cards

Whereas this sounds daunting, Compose additionally made this straightforward for us as a result of we have been in a position to leverage the identical composables we used for the first UI to render our shareable content material. To be sure that playing cards look constant, we used mounted sizing, side ratios, display screen densities and font scales, all of which may very well be achieved utilizing CompositionLocals and Modifiers. Sadly, we couldn’t discover a solution to take a snapshot of composables, so we used an AndroidView that hosts the composable to take the snapshot.

Our utility for capturing a card appeared one thing like this:

We’re in a position to simply override font scales, format densities and use a hard and fast dimension by wrapping our content material in a set of composables. One caveat is that we needed to apply the density override twice since we go from composable to Views and again to composables. Below the hood, RedditComposeView is used to render the content material, anticipate pictures to be rendered from the cache and snap a screenshot utilizing view.drawToBitmap(). We built-in this rendering logic into our sharing move, which calls into the renderer to create the cardboard preview that we then share to different apps. That rounds out the consumer journey by means of Recap, all powered by seamlessly utilizing Compose.

We have been thrilled to provide our customers a pleasant expertise with wealthy animations and the flexibility to share their 12 months on Reddit with their associates. In comparison with the 12 months earlier than, Compose allowed us to do much more issues with fewer strains of code, extra reusable UI parts, and sooner iteration. Animations have been intuitive so as to add and the potential of making customized stateful modifiers, like we did for the holographic impact, illustrates simply how highly effective Compose is.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments