jetc.dev Newsletter Issue #67

Published: 2021-06-01

This week, we dive deep into how some of the Compose magic occurs, with looks at the Kotlin compiler plugin and how recomposition works “under the hood”. We also look at some hiccups with collectAsState(), the current state of Lottie for Compose, and what the newly-added Kotlin/Native support for the Compose compiler plugin means. We also peek at an internationalization/localization library, a command-line tool for setting up Compose for Desktop projects, and what that app widget “conceptual code” shown in a Google I|O presentation might really mean.

One Off the Stack, One Off the Slack

You’ve got questions. That’s understandable!

Prefixes in a TextField()

Frequently, we want an input field that is not just user-entered text, but also contains other elements. For example, for entering a phone number, you might already know the appropriate country code from other details, and you want to allow the user to skip typing that part in. You can accomplish this and other similar effects using the visualTransformation parameter, as seen in this week’s highlighted Stack Overflow question.

Remember Your Flows

Compose often seems like magic, in part because its Kotlin compiler plugin is magic… for some things. However, there are limits to the magic, and after that, you need to remember arcane rules, no different than you would with any other framework. For example, you need to be very careful about Flow operators when combined with collectAsState(), if you want to avoid excessive (or perhaps infinite) recompositions, as we explore in this week’s highlighted Kotlinlang #compose Slack thread.

Composable Commentary

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

Podcast: Jetpack Compose Compilation

Android Developers Backstage is a long-running podcast, hosted by Google engineers. They have started a new series on Jetpack Compose, this time with Nick Butcher and Chet Haase talking with Adam Powell and Leland Richardson on the internals of the Kotlin compiler plugin and how it and the runtime drive recomposition.

A Historical Introduction to the Compose Reactive State Model

Zach Klippenstein has been busy! This post looks at past approaches for reactivity and compares them to what composables and recomposition offers us. Then, Zach continues with another post exploring how the Compose snapshot system works, giving us what amounts to transactional semantics on in-memory structures.

Custom Weekly Schedule Layout with Jetpack Compose - Part 1

Calendars with events are popular UI constructs, ones that often times are a pain to build. Daniel Rampelt created a weekly event schedule UI — the sort of thing that you might see in a personal planner, conference schedule, or room reservation app. This post, plus part 2, cover all the details, from event cells and custom Layout() composables for columns to row and column headers and grid lines.

Lottie Animations in Jetpack Compose Android

Lottie is a very popular animation system, and about six months ago it was made available for Compose as an alpha. In this post, Muhammad Danish brings us up to date with the current Lottie for Compose beta and how to use LottieAnimation() composables in your app.

The All-New State in Jetpack Compose

Siva Ganesh Kantamani is back, this time with an extensive review of state management in Compose, from remember() and state hoisting to LiveData and MutableState.

Compose – List / Detail: Basics

Mark Allison is starting to compose! In this post, Mark looks at the Jetpack SlidingPaneLayout for the classic View system and how to implement a similar setup in Compose UI, for offering side-by-side panes on wider screens and overlapping panes on narrower screens.

Tweets: Compose and Kotlin/Native

Andrei Shikov announced the availability of the Compose compiler for Kotlin/Native. While this does not mean that Compose for iOS is going to appear in the coming days, this is an important step towards offering Compose-style UI development for other UI systems, beyond Compose for Android, Compose for Desktop, Compose for Web, and Compose for Terminal (or however you want to categorize Jake Wharton’s Mosaic).

How to Disable Ripple Effect in Jetpack Compose

Compose Material applies the standard Material Design ripple animation. Some developers wanted that ripple for non-Material composables, which is why it is now available in a separate library. Mathan Raj wanted it gone, so in this brief post, Mathan demonstrates how to remove the standard ripple “indication” with nothing at all.

Video: Shimmer Animation (Jetpack Compose Beta)

Mitch Tabian returns with another screencast, this time showing how to implement a shimmer animation effect, designed to serve in the role of placeholder while you busily load content in the background.

Resource Roundup

100% pure code!

GitHub: adrielcafe / lyricist

Adriel Café is taking a shot at a Kotlin-centric string management system, for internationalization and localization purposes. It code-generates a CompositionLocal that you can use to get the translations of your strings for the current locale.

GitHub: iamjosephmj / flinger

Joseph James gives us a library that exposes an API for fling control in LazyColumn() and LazyRow(), allowing you to customize gravity, friction, and related properties.

GitHub: theapache64 / create-compose-desktop-app

GitHub user theapache64 created a NodeJS npm module that supplies a command-line Compose for Desktop project generator. You supply a display name and package name, and it code-generates a skeleton project for you.

…And One More Thing

Buried in the Google I|O presentation on app widgets, they showed off some “conceptual code” for creating app widgets using a composable API:

@Composable
fun ListWidget(items: List<Item>) {
  Column {
    Text("Shopping List")
    items.forEach { CheckListItem(it) }
  }
}

@Composable
fun CheckListItem(item: Item) {
  CheckBox(
    item.name,
    isChecked = item.isChecked,
    onStateChanged = { isChecked -> updateItem(item, isChecked) }
  )
}

This has led some developers to believe that we will be creating app widgets using Compose UI. I strongly doubt that this is the case. We will be able to create app widgets using Compose, but not Compose UI.

Compose UI requires a Canvas to draw on. In Compose for Android, that is Android’s Canvas. In Compose for Desktop, that is a canvas API supplied by Skia and Skiko.

However, other Compose targets, such as Compose for Web or Jake Wharton’s Mosaic, do not support Canvas. And, as a result, they do not support Compose UI. Compose for Web supports a facsimile of some of Compose UI, where they could pull off the same basic look using the DOM and CSS. And Mosaic has an even more limited API, given that it is targeting a terminal window rather than any sort of GUI.

Compose supports managing trees of data using composable functions. Compose UI supports managing trees of UI elements to be drawn on a Canvas using composable functions.

App widgets do not have a Canvas. Even though app widgets are part of Android, they are very different than the activities and fragments that we traditionally build. App widgets are really an IPC protocol between an app and a launcher, where the data passed between the process just so happens to describe a UI. That is why app widgets are created using RemoteViews, as that RemoteViews structure describes the UI and is what gets passed between the processes. RemoteViews does not give us a Canvas.

The most likely case is that writing app widgets with composables will look a bit like Compose UI, but the composables will map to things that you can represent in a RemoteViews. So, in the code snippet shown above, the Column() will map to a LinearLayout, the Text() will map to a TextView, and CheckBox() will map to a CheckBox (newly supported in RemoteViews in Android 12). But, you will not find TextField() in the app widgets API, as RemoteViews does not support EditText.

It would be truly wonderful if app widgets could somehow use the full suite of composables offered by Compose UI. Alas, that is unrealistic.