jetc.dev Newsletter Issue #214

Published: 2024-05-14

The Navigation for Compose support for type safety triggered a lot of reactions, so we see what developers had to say! We also research performance, identify differences between states and flows, and play an accordion. Plus, we spend a bunch of time with Compose Multiplatform for iOS, especially Compose Cupertino, and I talk a bit about where and when I would use those technologies.

Ooooo… What Did We Get?

Reviewing the release notes for the latest Jetpack Compose update!

Compose Multiplatform is up to 1.6.10-rc01, with a noteworthy limitation on Android, and otherwise with a few bug fixes. But, we’re clearly getting close to a stable 1.6.10 release!

One Off the Stack, One Off the Slack

You’ve got questions. That’s understandable!

Why Is My derivedStateOf() Not Reacting to Changes?

derivedStateOf() reacts to changes in State, not ordinary variables. This is why mixing-and-matching the use of by and a destructuring = with State can get you in trouble: by means the variable is a delegate and remains connected to the underlying State, while a destructing = leaves you with just a plain value. See this in action in this week’s highlighted Stack Overflow question.

How Can I Remove Button Ripples?

Touch feedback for widgets like buttons is very important… except when it is not. See some options for undoing the default Material ripple effect, and why you might want that, in this week’s highlighted Kotlinlang #compose Slack thread.

The latest Navigation for Compose release (2.8.0-alpha08) got a fair bit of attention! Stefano Natali gives us an overview in Medium: Compose Navigation 2.8.0.

One of the focus areas in this release was type safe navigation, and for that, opinions vary:

Composable Commentary

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

Medium: Getting the native iOS look & feel in your Compose Multiplatform app

Jacob Ras explores the Compose Cupertino library, which offers themes and wrappers that give you composable wrappers around native UIKit components, in addition to an adaptive set of themes and widgets that offer Material Design on Android and a mix of native and emulated iOS widgets for Apple’s devices.

Mastering Jetpack Compose Performance: Part 2

Sagar Khurana “delves into the Compose Compiler Metrics Plugin, offering insights on immutable and mutable objects, and providing practical solutions to common performance issues”. See Part 1 of the series here!

Medium: Build Wear OS application using Jetpack Compose [Part 2— Get started with WearOS]

Aritra Das walks us through creating a Wear Compose project and using basic composables, such as Chip()/ToggleChip(), Stepper(), TitleCard(), and more!

Medium: My Favourite SwiftUI Component Missing from Compose

Speaking of Stepper(), Chris Mederos missed having that in ordinary Compose, so Chris put together some StepperButtons() that can be used in the trailing position of a TextField() or OutlinedTextField() to offer a similar UX. Chris created another version that ties into Compose Cupertino to even more closely match the iOS stepper look!

Medium: Reducing recomposition on Bubbles

Rogelio Robledo works on an app with a bubble chart with some expressive animations. In this post explores various steps the team took to boost performance by eliminating some recompositions, to be better able to handle lots of bubbles at once. Specifically, Rogelio looks at a few forms of deferring reads, using lambda forms of some modifiers.

Medium: MutableState or MutableStateFlow: A Perspective On What To Use In Jetpack Compose

You might think that the answer is simple: in a Compose app, for modules with at least the Compose runtime library, use MutableState over MutableStateFlow. Kerry Bisset explores this idea and concludes the opposite: all else being equal, prefer MutableStateFlow and other Flow implementations.

Resource Roundup

100% pure code!

GitHub: tusharhow / Connext

Tushar Mahmud released a library that puts a convenience wrapper around connectivity state, including a CheckConnectivityStatus() composable and a getNetworkType() extension function on Context.

GitHub: sergio11 / brownie_ui_library

Sergio Sánchez Sánchez brings us Brownie, a library for Compose for Android with an MVI implementation and related components, such as a loading state.

Gist: NakaoKisho / Accordion.kt

GitHub user NakaoKisho offers us a small implementation of an Accordion() composable, which expands and collapses to show a column of additional content.

Notable Releases

Horologist – Google’s adjunct library for Wear Compose – is up to 0.6.11, mostly to get on a newer Wear Compose alpha build.

Maps for Compose has a 5.0.0 and a 5.0.1. These introduce breaking API changes, notably where the content parameter to GoogleMap() is no longer nullable, but defaults to an empty lambda.

Jaewoong Eum’s colorpicker-compose is up to 1.0.8 with bug fixes and updated dependencies.

Alex Styl’s compose-menu is up to 1.3.0, with support for the Kotlin/JS flavor of Compose Multiplatform.

…And One More Thing

In the Fediverse, Juhani Lehtimäki wrote:

I’m fully sold on KMP but not on Compose UI. It has the same problems as Flutter and other cross platform UI, it doesn’t feel fully native on iOS, ever. You’re already in the uncanny valley and /or chasing the latest UI stuff on iOS as Apple doesn’t allow the teams to prep for new OS releases.

I understand his point. My counterpoint: not all apps are created equal.

Would I use Compose Multiplatform, even with Compose Cupertino, adaptive layer for a first-class mobile app for iOS? Probably not. There, native fidelity is going to be fairly important, and store ratings will be crucial. I would still strongly consider Kotlin Multiplatform, but with a fully-native iOS UI. That might still use Compose Cupertino for its UIKit wrappers, perhaps powered by Redwood.

There are just very few first-class apps. After all, there are only 100 apps in the Top 100. Even if we expand this to include major brands, there are still only so many of these apps.

By contrast… would I use Compose Multiplatform for an internal-use app for a company or other organization? Yes. Would I use it for a casual app, not targeting a large audience? Yes. Would I use it for a proof of concept? Yes. Would I use it for a public app, but where the app is ancillary and not the whole of the user experience? Yes. Would I use it for a first-generation app, with an eye towards migrating to a native iOS UI later if the first generation succeeds? Yes.

Those sorts of scenarios dwarf major-brand and other first-class apps. If you are doing mobile development, it is rather likely that you are building something for which absolute native fidelity is not much of an issue. That does not mean that you have to use Compose Multiplatform, Flutter, or other cross-platform UI toolkits for those sorts of apps, but that it is a viable option.