jetc.dev Newsletter Issue #105

Published: 2022-02-22

This week, we look at rotating composables, both permanently and as part of a swinging animation. We also see Google’s Chris Sinco build a shrine, implement the “action mode” UI pattern, and explore various animation API options. We look at composables that handle the animation for us, such as flipping cards or animated heart outlines. And I continue grumbling about Compose performance, this time pointing out a homebrew way of improving our results without a full minification pass.

Note: This newsletter will take a one-week break after this issue and will return on March 8th!

One Off the Stack, One Off the Slack

You’ve got questions. That’s understandable!

How Do I Rotate a Composable?

Compose Material offers a Slider() composable, but it is horizontal. If you want a vertical slider, you could rotate the Slider(), though since it responds to user input, that gets a bit tricky. Learn how to pull this off in this week’s highlighted Stack Overflow question!

How Do We Use ComposeView in an AutoCompleteTextView?

A key part of migrating to Compose UI is ComposeView, to be able to wrap a composable in a View. This works in most cases, but there are edgy edge cases where using ComposeView is challenging… such as in the drop-down portion of an AutoCompleteTextView. Learn some ways of trying to pull this off in this week’s highlighted Kotlinlang #compose Slack thread!

Composable Commentary

Posts, videos, and other new information related to Jetpack Compose!

Video: Building Shrine in Compose

In a series of three videos, starting with the one linked to above, Google’s Chris Sinco works through building the Shrine “Material Study” project using Compose Material. Part two and part three are also available.

Medium: How To Collect Flows Lifecycle-Aware In Jetpack Compose

Yanneck Reiß points out the lifecycle limitations of collectAsState() for Flow and examines using flowWithLifecycle() to improve upon that. Yanneck then wraps up the desired pattern in a rememberFlow() extension function.

Medium: Building contextual mode of top app bar in Jetpack Compose

When the action bar pattern was introduced, “action modes” were included. These might be activated on a long click of a list item, where the action bar theme and actions would change to represent operations on the long-clicked-upon item. Tushar Kathuria explores implementing the same UI pattern in Compose Material, showing how a simple State can be used to drive whether your TopAppBar() is in regular or contextual mode.

Medium: Android’s IME Actions: Don’t ignore them.

That button in the lower right corner of your soft keyboard is the “action button”. Not only can we choose which style to use for that button, but we can get control when it is clicked, to navigate, switch focus, or otherwise help our user through our UI. In this post, Kasem SM explores how we do this, leveraging keyboardOptions and keyboardActions on TextField().

Medium: The 3 Jetpack Compose Animation Transition Low-Level APIs

Elye continues exploring Compose UI’s animation APIs, this time comparing and contrasting animate...AsState(), Animatable, and Transition, for achieving various animation effects in your app.

Medium: Conditional Navigation in Jetpack Compose

Francesc Vilarino Guell is back, this time looking at conditional navigation, where your navigation destination varies by circumstance. The classic scenario for this is when the user needs to log in before they can access the main portion of your app, and so when the app starts you need to conditionally show the login screen instead of the main screen. Francesc looks at using Navigation for Compose for this, using LaunchedEffect().

Medium: The Art of Swing Effect With Jetpack Compose

Stephen Vinouze gets into the swing of things, examining how to use Compose animation APIs to have a composable rotate around a particular point. This involves customizing the transformOrigin of the graphicsLayer() modifier, so your animation effects use a different origin than the center of the composable.

Resource Roundup

100% pure code!

GitHub: wajahatkarim3 / Flippable

Wajahat Karim offers us a Flippable() composable, for animating a flip transition between the front and back of something, such as a card. Flippable() provides slots for the front and back composables, plus a FlipController for triggering the flip.

GitHub: jkuatdsc / form-builder

GitHub user jkuatdsc published a library for helping you manage a form in Compose UI. Here, a “form” is a collection of text fields, where the library offers a FormState() container for individual field states, with centralized validation of the field contents.

Gist: c5inco / HeartRate.kt

Google’s Chris Sinco brings us a heart icon that animates colors along its path, inspired by this tweet.

…And One More Thing

I mentioned last week how Compose UI’s performance issues can collide with Wear OS’s performance issues, at least on poor-CPU watches. Obviously, there are poor-CPU phones as well, particularly older ones, and some developers run into problems more generally.

This leads to Slack threads like this one, where Zoltan Demant got better performance by creating a staging build type:

buildTypes {
    debug {
        minifyEnabled false
        shrinkResources false
        signingConfig signingConfigs.debug
    }

    release {
        minifyEnabled true
        shrinkResources true
        signingConfig signingConfigs.release
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }

    staging {
        initWith release
        minifyEnabled false
        shrinkResources false
    }
}

By and large, this staging build type is equivalent to debug, just with debuggable set to false. As Google’s Adam Powell noted:

ART changes its JIT behavior based on whether the app is debuggable

So, there is some “method to the madness”, and it is plausible that this indeed will help. I hope to try it out in the coming days.

One the one hand, it is great that we are finding these things. On the other hand, it is unfortunate that we in the community are having to come up with these semi-random approaches to address the problems on our own.