jetc.dev Newsletter Issue #63
Published: 2021-05-04
This week, we peek at InteractionSource
and how not to chain composables together.
We explore the impacts of Compose on dynamic feature modules and see how to offer
composable-specific modifiers. New libraries are available for settings, maps, and collapsing
app bars. And I warn you to make time for hallway testing as you migrate your app
to Compose UI.
One Off the Stack, One Off the Slack
You’ve got questions. That’s understandable!
What Is the StateListDrawable
Equivalent in Compose UI?
With things like button backgrounds, we used to use a StateListDrawable
to say “use these different images
based upon the state of the button”. This would allow us to have different images for the
pressed button state or the disabled button state from the normal button state. In Compose UI,
that tends to be handled differently, using State
that we observe. For states that depend on
user interaction, such as whether the composable is focused, there is InteractionSource
as a source
of State
, as we see in this week’s highlighted Stack Overflow question.
Avoid UI That Has Side Effects on Other UI
Using things like DisposableEffect
, it is possible to arrange for recomposition
of one composable to mutate state, which in turn triggers recomposition for some
other composable. This technically works, but it probably is not what you want, as we
see in this week’s highlighted Kotlinlang #compose
Slack thread.
Composable Commentary
Posts, videos, and other new information related to Jetpack Compose!
Sharing Compose Components Between Android and Desktop
Gérard Paligot works through a sample Kotlin/Multiplatform project that uses both
Compose and Compose for Desktop. In particular, he shows how to share composables
between the platforms, including having common composables reference per-platform
composables via expect
and actual
.
Dynamic Delivery with Jetpack Compose
Igor Escodro returns, this time looking at how Compose impacts dynamic feature module development. Technically, this is not supported yet, but Igor did not let that pesky detail stand in the way!
Podcast: Compose Academy
Joe Birch has launched a Compose-specific podcast as an adjunct to the Compose Academy Web site.
Creating a Custom Modifier Attribute on Jetpack Compose
While some modifiers are available everywhere, others are only available to child
composables of some specific composable. For example, weight()
is only available
for children of Row()
or Column()
. This bit of magic is handled via extension
functions and a custom type as the receiver of the lambda expression that creates
those child composables, as Francesc Vilarino Guell explores in this post.
Video: Android Night - Jetpack Compose
GDG Singapore hosted a 110-minute presentation by Kurt Renzo Acosta covering the basics of using Compose UI for your Android apps.
Custom Shape with Jetpack Compose
Julien Salvi continues a tour of Compose rendering, this time with a look at creating
custom Shape
implementations. We supply Shape
objects to modifiers like background()
and border()
, but there are only a few stock implementations of Shape
. Here, Julien shows
creating one from scratch, using Outline.Generic
and a relatively complex Path()
.
Jetpack Compose: An Easy Way to RecyclerView (Part I)
Waseef Akhtar walks through the basic steps of setting up a Compose UI application and
rendering a scrollable list using LazyColumn()
.
Jetpack Compose — Earthquake Effect
Most developers would prefer to avoid earthquakes. Paulo Pereira elected to create one… using some randomly-applied animations.
“Composing” the Flutter counter app with Jetpack Compose: Part 1
Annsh Singh writes a lot about Flutter, but is now playing around with Compose UI.
In this post, Annsh ported the “counter” app (Flutter’s “hello, world” equivalent)
to Compose UI, using rememberSaveable()
for retaining the counter state.
Other Interesting Links
Resource Roundup
100% pure code!
GitHub: alorma / Compose-Settings
Bernat Borrás Paronella is working on a library of composables that offer similar functionality
to stock Preference
elements in a PreferenceScreen
, following
the AOSP settings guidelines.
Right now, it covers simple links, plus switches and checkboxes, each in individual boxed
entries with titles and subtitles. (and TIL that AOSP has settings guidelines…)
GitHub: peterLaurence / MapCompose
Pierre Laurence offers up another library, this one for implemented tiled maps.
You provide sources of tiles (e.g., from files or Web services), and MapUI()
takes care of loading tiles as the user pans, flings, and zooms.
GitHub: onebone / compose-collapsing-toolbar
GitHub user onebone has a reusable composable for implementing a collapsing app bar, with configurable strategies for when the app bar reappears (or expands).
Other Interesting Links
…And One More Thing
As Compose and Compose UI roll along towards a stable release, teams will start to think about beginning to use these technologies in their apps. Some of those teams will focus first on “new construction”: new apps or new screens in existing apps. Other teams will prefer to start by rewriting existing UI.
There is a hidden cost to the rewriting approach: ad-hoc “hallway” testing.
Many teams have automated UI testing, using instrumented tests, Espresso, and the like. However, many teams also wind up skipping those, as they are expensive to write, expensive to maintain, and slow to run. Those teams focus automated tests on lower levels of the app and rely on manual testing for the UI.
There is nothing strictly wrong with either of those approaches. One size does not fit all.
However, what often gets ignored is ad-hoc testing, the sorts of things that team members do on a day-in, day-out basis by using the app. If you have been doing software development for any significant length of time, you will be familiar with ad-hoc testing:
-
You do something in the app
-
Something unexpected occurs, causing reactions ranging from 🤨 and 🤔 to 🙄 or 😮 (or 😭 or 😱)
-
At some point, you take steps to investigate the unexpected behavior and perhaps make fixes
Sometimes, you literally are the one doing this testing. Sometimes, it it teammates. Sometimes, it is managers or other teams within your organization. And, alas, sometimes, it is customers or other end users.
All of that feeds back into the app and makes the app better. And much of that gets thrown out when you do a wholesale rewrite.
In the case of redoing a screen using Compose UI, improvements from ad-hoc testing that fix things deeper in the app might remain, but improvements that affect your views might be lost when you replace those views with composables.
This is not to say that should never rewrite UIs. Nor is this concern unique to Compose. However, Compose is one of the bigger externally-induced reasons for rewriting UIs, and in particular rewriting the UIs of entire apps.
Make sure that as you do these rewrites that you budget sufficient time for ad-hoc testing and that you let ad-hoc testers know about screen changes. Make sure that you have good channels for ad-hoc testers to report any oddities that they see in the Compose-ified screens. Make sure that those ad-hoc testers know how to provide good reports about those oddities: steps to reproduce the problem, screenshots/screencasts, etc. And make sure that your development process has ways to take that feedback into account and make repairs.
The advantage of first applying Compose to “new construction” is that, by definition, everybody knows that it is new. The sorts of people used to reporting weird stuff will tend to be watching out for problems with new screens, where they might not realize that a rewritten screen was rewritten.
Regardless, make sure that your “eyes and ears” across your organization — including trusted beta testers — are able to help you as you work through bugs related to a Compose migration, whether those bugs come from your migration or from Compose itself.
Or, you can subscribe to the Atom feed or follow Mark Murphy in the Fediverse.
Recent Issues:
- 2024-12-10: A Compose Multiplatform alpha! Hot reload! Presentation! Sprites! Calendars!
- 2024-12-03: Rebecca Franks on clipping and masking! Stefano Natali on graphicsLayer()! FunkyMuse on type-safe nav results! And... if we have enough maps, do we need to store our maps in a Map?!?
- 2024-11-26: Math! Shared element transitions! Custom modifiers! Macrobenchmark! Adapting to platform-specific design systems! And... why does wrapContentSize() not wrap my content size?!?