jetc.dev Newsletter Issue #57
Published: 2021-03-23
This week, we spend a chunk of time thinking about testing, both for getting our code right now and to be able to adapt to the inevitable changes that are going to come about for how we do Compose UI development.
In addition, we explore animations and the Canvas()
, adapting our legacy Compose
code to the effect system, utility composables for design grids and zooming, and more!
Plus, we see what goes on inside Adam Powell’s head!
One Off the Stack, One Off the Slack
You’ve got questions. That’s understandable!
Testing Text Entry
Espresso’s Compose UI support is powerful, but sometimes it is not obvious how to
set up certain types of tests. Simulating text entry into a TextField()
is
one example, and we see the solution for conducting that test in this week’s
highlighted Stack Overflow question.
The Phases of Compose UI Rendering
Ever wonder how the Compose team remembers all of the various ways of solving
Compose UI problems? Well… you will still wonder how they remember all that stuff,
but at least you will get a better idea of the thought process, in this week’s
highlighted Kotlinlang #compose
Slack thread.
Composable Commentary
Posts, videos, and other new information related to Jetpack Compose!
Build an Android Chat app with Jetpack Compose
Márton Braun went beyond Google’s Jetchat sample app and wrote a full-fledged chat app, complete with server support through Stream. This post walks through every step of the process, from creating the initial project in Android Studio through the final results.
Dealing with Flaky Tests in Jetpack Compose
Igor Escodro identifies a scenario where your Compose UI testing might wind up with flaky tests — tests that may succeed or fail based on timing issues. Igor walks through how to deal with such tests, using Barista and a slightly different structure for the test cases.
Test Jetpack Compose UI Easily with the Role SemanticProperty
Yasin Kaçmaz walks us through using the role
property on the selectable()
modifier to be able to group widgets together, not only for UI and accessibility
purposes, but also for simplified testing.
Jetpack Compose — Curtain Effect
Paulo Pereira demonstrates a “curtain” animation, where a column of composables can fold out from an initial row, in a variation on the “accordion” animation. This GitHub repository contains the final result, in the form of a sample app.
A Quick Guide to the animate…AsState Animation API in Jetpack Compose
Pranav Jayaraj gives us an overview of the various animate-as-state top-level
functions in Compose UI, such as animateFloatAsState()
and animateColorAsState()
.
Pranav demonstrates both simple value animations and ones with a custom specification,
such as repeat rules or spring stiffness.
Exploring Jetpack Compose Canvas: the power of drawing
Julien Salvi takes a tour of the Canvas()
composable, showing how
to draw shapes, lines, and text on one, and comparing and contrasting it with the
Canvas
object from the classic View
system. Julien also ties the Canvas()
DSL into the animate-as-state functions from above, showing how they let you
recompose your Canvas()
and affect the elements that you draw.
Flexbox Layout Behavior in Jetpack Compose
Andy Dyer compares and contrasts “flexbox” from CSS and Web development with the
container composables and modifiers that we work with in Compose UI. While there
is no single Flexbox()
composable, you can get a lot of flexbox-style results
from the roster of standard composables.
How to Replace onCommit, onActive, and onDispose in Jetpack Compose
One challenge that we have with Compose and Compose UI is how much the API has shifted from the early developer previews to the now-current beta.
Tiger Oakes feels our pain.
In this post, Tiger reviews what onCommit
, onActive
, and onDispose
were in earlier versions of Compose, then shows us how to replace them
with SideEffect
, LaunchedEffect
, and DisposableEffect
.
Scrollable TopAppBar with Jetpack Compose
Max Hübscher wanted a TopAppBar()
that would slide away as the user scrolls
the content down, then slide back into position when the user scrolls the content
up. Alas, TopAppBar()
does not appear to offer that, so Max wrote one using a Surface()
,
rememberLazyListState()
, animateFloatAsState()
, and related composables.
Other Interesting Links
- Re-gaining orientation #2
- Android Jetpack Compose Navigation made Easy
- Video: How To Style And Theme Android Application With Jetpack Compose - Light & Dark Themes
- Building an Android Emoji Garden on Jetpacks! (Compose) with Realm
- Composing Web Content
- Jetpack Compose — An Introduction
Resource Roundup
100% pure code!
Gist: opatry/GridLayer.kt
Olivier Patry posted a simple composable for rendering a grid of squares. That may not seem like much, but if you place it at the bottom of your screen composable, it overlays that grid on what the rest of the composable renders, for helping you visualize how well you are matching requested designs in terms of size and position of the widgets.
GitHub: Tlaster/Zoomable
GitHub user Tlaster published a small library that contains a Zoomable()
composable that can wrap another composable and offer pinch-to-zoom on its
contents.
GitHub: fvalela1/CalendarJetpackCompose
Francesco Valela offers a CalendarJetpackCompose()
composable for rendering a calendar,
with the option of highlighting dates, optional month navigation, etc.
GitHub: dbaroncelli/D-KMP-sample
Daniele Baroncelli published a sample app for his D-KMP architecture, demonstrating how to use Kotlin/Multiplatform with mostly shared code, except for using platform-specific declarative UIs (Compose UI for Android, Swift UI for iOS).
GitHub: Badranh/sniff
Hasan Badran offers another image-loading library for Compose UI. This one uses Ktor for the network I/O and supports Compose for Desktop.
GitHub: Elbehiry/Delish
Mohamed Elbehiry published Delish, a gorgeous Compose UI app for browsing and searching recipes published by Spoonacular through their Web service API.
GitHub: manueldidonna/godot-trains
Manuel Di Donna released a nicely designed app for displaying Trenitalia train schedules. The name, though, suggests that there may be long waits for Italian trains… 😁
Gist: EugeneTheDev/DotsLoaders.kt
GitHub user EugeneTheDev created a suite of composables demonstrating a variety of loading animations, all using dots. Rolling dots, flashing dots, stretching dots…
…And One More Thing
The next year or two is going to be a period of experimentation, as we strive to find the best patterns for applying Compose UI, both for new projects and for revamping existing projects.
Just do not get too married to your solutions.
In Android app development, “change is the only constant”. The recommended app development patterns change extremely rapidly, even when the platform itself has slowed its rate of change from the wild early days. Public Android app development is barely 12 years old, yet we have gone through a variety of revolutions:
-
Use Java. Actually, use Kotlin.
-
Use activities. No, use fragments, but only for tablets. Wait, instead, use fragments for everything, with one activity. Actually, dump the fragments and use composables!
-
Use
AsyncTask
. No, use loaders. Hang on, switch to RxJava. Oh, can we interest you in coroutines? -
Just write code. No, use MVP. Sorry, that was a typo: use MVVM. Hey, MVI looks cute!
-
And so on.
It is almost assured that we will go through a few generations of approaches for how to apply Compose UI. Perhaps they will not be as fundamental as some of the other Android app development changes, but they may be more numerous:
-
Do we stick with top-level functions everywhere, or do something else (e.g., one
object
per screen)? -
How do we handle theme-like concerns, particularly if we are implementing our own design system and therefore may not be using
MaterialTheme
or Compose Material? -
How do we decide what gets locally
remember
-ed, what gets handled by a JetpackViewModel
, and what gets handled by something else (e.g., non-Jetpack viewmodel)? -
How do we handle navigation, now that we are navigating between functions? Is Navigation for Compose the “one true” navigation solution, or will we wind up switching to something else?
-
How do we organize our composables into modules, both for stacks that rely upon modules (e.g., Kotlin/Multiplatform) and for basic Android apps?
-
…and those are just a few that I thought of off the top of my (balding) head.
Tastes will change. The solutions that we use today will look dated tomorrow.
So, in many ways, the biggest thing that you can do is to try to be less opinionated about your own opinions. “Future you” may disagree with your opinions from today, and those opinions will drive a lot of your implementation decisions.
We have no way of predicting the exact nature of the changes that will happen. We can predict that the changes will happen. The more you can do to be able to adapt to those changes — such as writing good tests — the better off you will be when those changes come about.
And now, if you will excuse me, I need to go see what patterns changed while I was writing this newsletter issue… 😁
Or, you can subscribe to the Atom feed or follow Mark Murphy in the Fediverse.
Recent Issues:
- 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?!?
- 2024-11-19: Compose alphas! Compose Multiplatform patch! PaddingValues! Graphics layers! Swiping! Heatmaps! Navigation! And... why did we get a new production Compose BOM?!?