jetc.dev Newsletter Issue #96
Published: 2021-12-21
We got slightly more than one RC release this past week — we’ll see what that means!
Beyond that, we look at child composables and how we pass colors down. We look at the alpha version of Jetpack Glance for creating app widgets. We explore custom password and multi-toggle button composables, plus swiping cards off of stacks and blocking Compose Material ripples. And I’m concerned about some advice from Chris Banes, which means I’m probably wrong, though perhaps I’m usefully wrong.
RC Reflections
Reviewing the release notes for the latest Jetpack Compose update!
1.1.0-rc02
is out for androidx.compose.compiler:compiler:1.1.0-rc02
, with official support for Kotlin 1.6.10!
They also started publishing a table showing what Kotlin versions are supported
by which Compose compiler versions.
Note, though, that the rest of the Compose artifacts are still at 1.1.0-rc01
.
Mostly, those appear to be bug fixes. One that has a possible functional aspect:
scrollToItem()
and animateScrollToItem()
on LazyListState
now support
negative scroll offsets.
One Off the Stack, One Off the Slack
You’ve got questions. That’s understandable!
How Does the Surface() Content Color Affect Children?
A Surface()
takes a contentColor
parameter, which affects the color of
things like the text of a Text()
that is a child of the Surface()
. See
how this is accomplished in this week’s highlighted Stack Overflow thread.
How Do We Examine the Content of Child Composables?
DRY (“Don’t Repeat Yourself”) is a fine programming maxim, but sometimes defining
the single source of truth can be tricky. This is especially true in Compose UI,
where often Composable A cannot interrogate Composable B to get a value. Learn ways
of working around this in this week’s highlighted Kotlinlang #compose
Slack thread!
Composable Commentary
Posts, videos, and other new information related to Jetpack Compose!
Announcing Jetpack Glance Alpha for app widgets
Google has released the first alpha of Jetpack Glance, its new composable API for defining
app widgets and, in the future, Wear OS tiles and perhaps other “glanceable” targets.
One note: while the minSdkVersion
is set to 21, Glance really only supports back to API Level 23.
Medium: Building a ComposeWidget using Jetpack Glance
Matthew Meehan wasted no time in putting the Jetpack Glance alpha to use, creating an
app widget to keep track of how many glasses of water you drink. Matthew explores the boundaries
of Jetpack Glance (hint: you still need a layout resource, for the widget preview), examines ActionCallback
for responding to click events, and more. Also: stay hydrated! 😁 🚰
Jetpack Compose: Run Preview with Hilt
Chetan Gupta wanted to use @Preview
with a composable that uses hiltViewModel()
.
In the end, that is not really practical, so Chetan walks through a workaround, involving
a run configuration to launch a custom preview activity. Or, avoid using Hilt directly in leaf
composables (the sorts of things that you want to preview).
Medium: Koin for Compose proposal (Jetpack and Multiplatform)
Back in issue 83, I linked to cokoin, a Koin wrapper for use with Compose (both the Compose Multiplatform and Google’s Jetpack edition). Here, Bruno Wieczorek explains the origins of cokoin, why it is a separate library, and how it works.
Medium: How to create a composable password with Jetpack Compose
Juan Guillermo Gómez Torres explores a PasswordTextField()
composable,
including its use of VisualTransformation
, its options for password strength
calculations (for creating new passwords), and more!
Exploring theming in Jetpack Compose
Chizoba Ogbonna reviews MaterialTheme()
and its component parts (colors, typography, shapes, etc.)
and how you can tailor them to match your target designs. Chizoba also looks at
theme adapters for Material Component for Android and AppCompat, if you need
to share theme definitions between composables and classic View
-based UIs.
Jetpack Compose - Configuring a Simple Multi Toggle Button
The Dev Bits and Bytes team looks at creating a MultiToggleButton()
composable
for displaying a row of mutually-exclusive toggle buttons.
Other Interesting Links
- How to use highlight.js in your Jetpack Compose Web project
- Medium: Jetpack Compose 3- Theming
- Medium: Places Autocomplete Widget from Compose without fragment (using intent)
- Medium: Fundamentals of Jetpack Compose
Resource Roundup
100% pure code!
GitHub: lhoyong / swiper
GitHub user lhoyong created a Swiper()
composable, rendering a stack of items and
allowing users to swipe off the top item to expose the one underneath.
Gist: mxalbert1996 / Scrollbar.kt
Albert Chang posted a snippet of code that implements a series of modifiers for
drawing scrollbars for LazyColumn()
, LazyRow()
, and other scrollable containers.
Gist: hisetu / NoRipple.kt
GitHub user hisetu does not like ripples, apparently, and created noRippleClickable()
and selectableNoRipple()
modifiers to inhibit the default ripple effect from Compose Material.
Other Interesting Links
…And One More Thing
About two months ago, Chris Banes wrote “Always provide a Modifier parameter”. This was well-received by the community, and I agree with its arguments in some situations. IMHO, though, its recommendations require more nuance for the overall ecosystem.
Other Compose UI experts extol the benefits of creating composables that implement a design system, whether that design system is wrapped around Compose Material or is created as a peer of Compose Material (based on pre-Material composables). IMHO, that is the better goal. There should be little question in the development team of how to assemble a Compose-based UI for your app: it should be based on a set of composables that in turn are based on what the designers ask for. Or, if the project lacks designers, there should still be a set of common UI elements that get applied consistently throughout the app.
Chris’ post does not prohibit the creation of composables for a design system. However, Chris’ objective appears to be maximum flexibility, and that can conflict with creating composables for a design system. Composables for a design system need to reliably implement the design system, more so than being flexible.
Chris’ final code snippet contains comments like:
// We can add any behavior we wish here!
and:
/**
* This now has a modifier parameter, allowing callers
* to customize the layout, behavior and more!
*/
When implementing composables for a design system, those can be bugs, not features,
if they allow the composables to be used in ways that do not adhere to the designs.
And, since Modifier
is very flexible, exposing a Modifier
parameter all but guarantees
that the composables can be used in ways that do not adhere to the designs.
So, now we get down to team mechanics: is it better to have an API that is inflexible
but is reliable, or is it better to have an API that is flexible but unreliable? Stronger
teams can accomplish more in less time with the flexible-but-unreliable API, as they can
rely upon external processes to enforce the design where the composables do not. For
example, those teams have a large enough design team, or have a design-savvy QA team, such that they
can do design reviews to ensure adherence to the designs. Not
everyone has that sort of staffing, though. Or, they have teams with a lot of junior
developers, ones for whom adhering to a design system is a new concept. For those,
having an inflexible-but-reliable API may be the better course of action, even if it
means creating a couple of renditions of a composable (perhaps wrapping around a
flexible private
implementation) to handle varying scenarios.
In time, perhaps with tooling improvements we will be able to create composables
that are both flexible and reliable. For example, we could work out a way to validate
a Modifier
input to ensure that it does not mess with things that it should not.
Right now, I do not think we are in position to perform that sort of validation.
Does this mean that you should never expose a Modifier
input to your composables?
Of course not. It does mean that you should think through the short-term and long-term
role of the composables that you create, and consider whether supporting Modifier
input
is the right answer. It may be that the right answer is not “always” or “never” offer
Modifier
input, but rather “sometimes”, such as “only for private
composables”.
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?!?