jetc.dev Newsletter Issue #211
Published: 2024-04-23
We got all kinds of new stuff: an updated Compose BOM and Compose Compiler, new alphas for Compose and Wear Compose, a new Glance beta, the first steps of Compose Material3 and Jetpack Lifecycle Runtime going multiplatform, and a new Compose Multiplatform beta!
We also migrate away from ClickableText()
and nest some lazy containers.
We look at a pair of replacement scaffolds. And I chat a bit about Skip, an iOS-first
multiplatform option.
Ooooo… What Did We Get?
Reviewing the release notes for the latest Jetpack Compose update!
The Compose BOM is up to 2024.04.01
.
That maps to the 1.6.6
patch releases
of the core Compose artifacts and 1.2.1
of Compose Material3. Those patches
have minor bug fixes.
Compose Compiler is out with 1.5.12
,
containing a couple of bug fixes.
Compose is up to 1.7.0-alpha07
, with a variety of interesting changes, including:
-
Support for initializing one composition local from another
-
Support for item appearance/disappearance animations in lazy grids and staggered grids
-
LinkAnnotation
in anAnnotatedString
is now the official replacement forClickableText()
, which is deprecated -
AnnotatedString
now offers afromHtml()
function to parse HTML -
Support for pressed state on links
Compose Material3 is up to 1.3.0-alpha05
. SearchBar()
and DockedSearchBar()
now have overloads that take a TextField()
slot parameter, so you can style it
separately.
Also, we got three new Compose artifacts, as Compose Material3 starts to go multiplatform:
androidx.compose.material3:material3-common
androidx.compose.material3:material3-common-android
androidx.compose.material3:material3-common-desktop
Wear Compose 1.4.0-alpha07
is available, offering a new rotary()
Modifier,
along with SelectableChip()
and SplitSelectableChip()
composables.
Glance now has a 1.1.0-beta02
release, adding in the source JARs that were
missing from 1.1.0-beta01
.
We got three new Compose-adjacent artifacts:
androidx.lifecycle:lifecycle-runtime-compose-android
androidx.lifecycle:lifecycle-runtime-compose-desktop
androidx.navigation:navigation-fragment-compose
…and updates to four more:
androidx.activity:activity-compose:1.9.0
androidx.fragment:fragment-compose:1.7.0-rc02
androidx.fragment:fragment-compose:1.8.0-alpha02
androidx.navigation:navigation-compose:2.8.0-alpha07
Also,
JetBrains released Compose Multiplatform 1.6.10-beta01
.
This offers experimental multiplatform versions of Navigation for Compose and
the Jetpack ViewModel
. It also adds support for multi-module projects that
leverage Compose Multiplatform resources.
One Off the Stack, One Off the Slack
You’ve got questions. That’s understandable!
What Is The Difference Between derivedStateOf()
and remember()
With a Key?
remember()
with a key triggers recomposition when the key changes. derivedStateOf()
triggers recomposition when the associated lambda expression evaluation result changes.
Those are not the same, but the visible impact can be subtle, as we see in this
week’s highlighted Stack Overflow question.
How Do We Use Coroutines in Lifecycle Effects?
In other words, can you use coroutines inside LifecycleStartEffect()
and kin?
The answer is yes, but it’s not the recommended approach, as we see in this week’s
highlighted Kotlinlang #compose
Slack thread.
Composable Commentary
Posts, videos, and other new information related to Jetpack Compose!
I Removed JetPack Compose from My App
Spoiler alert: Donn Felker did not remove Jetpack Compose from his app. He did,
however, write a post explaining that there are times when using View
-based
widgets makes sense. In this case, Donn relied on third-party libraries that
had “out of the box” support for the Toolbar
widget, and that resulted in less
overall code than using the AppBar()
composable.
Migrating from the ClickableText composable to LinkAnnotation
Joe Birch pours one out for the now-deprecated ClickableText()
(we hardly knew ye!) and explores what
it takes to use LinkAnnotation
and buildAnnotatedString()
as a replacement.
Medium: Creating a Time Picker Based on the ELSA Speak App Using Jetpack Compose
Andrii Veremiienko walks us through creating a rotary time picker, using a Layout()
for the UI and blending in fling and drag support via a custom drag()
modifier.
anchoredDraggable For Speed And Fun
Xiaoming liked the playback speed slider from the now-defunct Google Podcast app
and set out to recreate it, using the anchoredDraggable()
modifier.
Medium: Nested LazyColumn in Jetpack Compose
Narayan Panthi examines lazy containers (LazyColumn()
, LazyRow()
, LazyGrid()
),
first in isolation, then nested. Narayan specifically examines two patterns:
LazyRow()
composables nested inside a LazyColumn()
and a LazyColumn()
nested inside another LazyColumn()
.
Medium: Some Best-Practices for State Management in Jetpack Compose
Kayvan Kaseb reviews the use cases for remember()
, the role of state hoisting,
the value of immutable state holders, and more.
Other Interesting Links
- Create an Android App With Kotlin and Jetpack Compose
- Medium: 2048 with Compose: Part 1
- Medium: Compose navigation transition animation for adventurous dev only
- Medium: Compose State vs StateFlow: State Management in Jetpack Compose
- Medium: Creating a simple calendar widget using Jetpack Compose & Glance
- Medium: Different color Status Bar in different screens| Edge to Edge | Android
- Medium: Disable Landscape orientation in Jetpack Compose per screen
- Medium: How to Celebrate Personal Milestones with an Android Widget Using Jetpack Compose Glance API
- Medium: Mastering Screen Orientation Detection in Jetpack Compose
- Medium: State Management Simplified: A Beginner’s Guide to Jetpack Compose
- Using XML Views in Compose
Resource Roundup
100% pure code!
GitHub: stoyan-vuchev / responsive-scaffold
Stoyan Vuchev created a ResponsiveScaffold()
composable, designed for supporting
various window sizes and postures (landscape/portrait). It includes NavigationRail()
support and conditional hiding of the FAB on larger screens.
GitHub: EudyContreras / Snap-Scaffold
Eudy Contreras is also working with scaffolds, in this case making it easier to implement snap behavior in scrollable content: sticky headers, collapsible headers, and so on.
GitHub: takahirom / Rin
Takahiro Menju brings the rememberRetained()
concept from
Circuit to Compose Multiplatform’s own
navigation and viewmodel support.
GitHub: theolm / rinku
Theodoro Loureiro mota brings us a library to simplify deeplink support to Kotlin Multiplatform and Compose Multiplatform, for iOS and Android.
GitHub: w2sv / Composed
Janek Zangenberg has a library with a wide range of Compose utility functions,
from dimension, color, and map conversions to permission state to custom Saver
implementations.
Notable Releases
Maps for Compose is up to
a 4.3.4
release.
This adds a stability configuration file, to mark the Maps SDK types used by Maps
for Compose as stable. This should improve performance, courtesy of strong skipping
mode.
…And One More Thing
I have been seeing a few mentions of Skip recently. Roughly speaking, this is the inverse of the original Kotlin Multiplatform and Compose Multiplatform. Instead of writing in Kotlin and the code being cross-compiled into code for iOS, you write in Swift, and Skip transpiles into Kotlin. And, rather than writing in Compose and using that across both platforms, Skip converts SwiftUI into Compose.
I can see the allure. Lots of apps — rightly or wrongly — are iOS-first. Skip lets you have a maximum-fidelity implementation on iOS, and gives you an Android equivalent. And, simply getting this to work at all is very impressive.
That said, my biggest concern is with dependencies. The only dependencies that work with Skip
right now are where “the dependent module has a Skip/skip.yml
file”. At this
point, probably few Swift libraries are Skip-enabled. This results in a “Catch-22”
situation: few libraries will invest in being Skip-enabled unless Skip becomes
popular, and Skip may have problems becoming popular because few libraries are
Skip-enabled. My guess is that the issue is that Skip is source transpiler —
is is unclear how this will work with dependencies for which source code
is unavailable.
This is analogous to the state of Kotlin Multiplatform and Compose Multiplatform… except that JetBrains has a substantial head start. It is unclear if Skip will gain an ecosystem of comparable size.
Skip also seems like a much smaller firm than JetBrains. As a result, effectively they are forced to charge for their tooling, at a $999/year rate ($499 for the first year). While they have an open source free option, it is limited to GPL/AGPL/LGPL projects. The Kotlin Multiplatform and Compose Multiplatform environments are “free as in beer” more broadly.
I certainly wish Skip luck. Competition, in business and in ideas, is a good thing.
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?!?