jetc.dev Newsletter Issue #74
rc02 shipped! And, since there are already signs of the first alpha for
it is extremely likely that next week will bring the stable Compose release! 🙌
This week, we look at how
@Preview can work with a
ViewModel parameter… again.
We also get caught up on Coil’s first-class support for Compose, examine MVI in a
Compose context, and talk about accessibility. We also see how to capture a composable
in a “screenshot” bitmap and how to work with arrow keys, D-pads, and the like.
And I point out that
LocalContext helps you identify where you are doing things
in a composable that might belong somewhere else in your architecture.
Reviewing the release notes for the latest Jetpack Compose update!
rc02 has few changes, and most of those are just bug fixes. They did
rc01 change, so now dialogs will be sized based on the platform
by default — use
usePlatformDefaultWidth = false to change this back to
One Off the Stack, One Off the Slack
You’ve got questions. That’s understandable!
clickable() modifier is for responding to simple clicks. If you need to respond
to long clicks as well, use the
combinedClickable() modifier, as we see in this week’s
highlighted Stack Overflow question.
A few months ago, we looked at having a
@Preview composable accept a
That subject came up again, garnering a few new possible solutions, as we see
in this week’s highlighted Kotlinlang
#compose Slack thread.
Posts, videos, and other new information related to Jetpack Compose!
Coil (an image-loading library) now has first-class support for Compose UI, supplanting the external implementation from Chris Banes’ Accompanist library. As you switch from Accompanist to a pure-Coil solution, though, there are several things that you will need to rename — this portion of the Coil documentation outlines what you will need to do.
Microsoft has been hard at work to make Compose work well with the Microsoft Surface Duo,
their Android-powered dual-screen device. Joy Liu returns with a blog post outlining
their new library with a
TwoPaneLayout() composable that reacts to hinge placement
and orientation to help you present distinct content on each half of a foldable. Joy
also recorded a Twitch livestream reviewing the use of this composable.
Chris Yono examines the options we have in Compose UI for providing accessibility
information to Talkback and similar accessibility services. Chris explores
the Compose edition of
contentDescription, along with newer options like
Catalin Ghita graces the newsletter again, this time touching “the third rail” of Android app development: architecture patterns. Here, Catalin looks at whether there are aspects of MVI that might be more amenable to Compose UI-based apps than a strict MVVM implementation would be.
Garima Jain also examines MVI, seeing how Compose support for
can help deal with MVI’s preference for immutable view states while minimizing the cost
of recomposition as the view state changes.
Maia Grotepass continues her exploration of retro UIs with a look at the venerable page counter. In the 1990’s, a page counter would show how many visitors have visited a particular Web page, back when the Web had few users and few sites to visit. Maia’s counter uses an animated effect akin to an odometer to show the counter climb.
Medium: Create an Auto-Scroll ViewPager with transformation and ken burns effect in Android Jetpack Compose
Mr Umbrella returns, this time with a pager-style UI (using Accompanist) that automatically switches between pages. It also performs a scal animation on the images shown in the pager, to provide a Ken Burns effect for those images.
Other Interesting Links
- Medium: Learning to Speak Compose
- Jetpack Compose: Layouts
- Video: Text Fields - Jetpack Compose
- My First Attempt at creating a game with Jetpack Compose
- Medium: What I learnt building a tweet screen using Jetpack Compose
- Implement TabLayout with ViewPager in Android Jetpack Compose
- Medium: Integrate Google Maps in Jetpack Compose List
- Medium: State Management in Jetpack Compose
- Medium: Playing with TextField in Compose
- Things you need to know before switching to Jetpack Compose
100% pure code!
A popular question is: how do we generate a “screenshot” of a composable, converting
what it renders on-screen into a bitmap? Johann Blake took a shot at it, using a
ComposeView to wrap the composable, then capturing a bitmap of that
Johann also wrote a Medium post
with more information.
Bogusz Pawłowski created a library for rendering interactive calendars, with customizable date/date range selection, along with customizable composables for rendering individual pieces (e.g., days, weeks).
Other Interesting Links
…And One More Thing
The general pattern for Compose is that composable functions are pure top-level functions, not member functions of some activity, fragment, or other construct. This feels weird and will need some time for us to adapt. However, it has the advantage of helping to identify where we are doing things that may not be the best.
A big downside of
Context being a ‘god object’,
is that it was very easy to do things in an
Activity that might not belong there.
So, when you go reaching for
LocalContext.current, ask yourself whether that
logic really belongs in your current composable, versus belonging somewhere else:
Want to navigate to some legacy activity when a button gets clicked! Great! But your composable that calls
Button()might not be the right spot to do that work. It may be better to have your composable take an on-button-click lambda expression that you can invoke instead, and let the actual navigation be handled in some higher-order composable.
Want to read a
SharedPreferencesvalue? Cool! But, that is data, and so really that should be coming from your viewmodel or a similar abstraction for getting data from your data sources. After all, you will want to supply test data when you test your composable.
Need the value of some resource? Wonderful! But there are built-in functions for a lot of that, such as
stringResource(), that you may wish to use instead.
Need to talk to some system service? Um, OK. But, that too probably ought to be isolated in your viewmodel, except for the occasional system service that is purely UI-centric (e.g.,
And so on
Roughly speaking, if the work you want to do with a
Context is not tied very closely
to a UI concern, probably there is a better place for you to do that work, such as a
calling function or viewmodel.
LocalContext.current may not rise all the way to “code smell”, but it is the
sort of thing that you should still look at closely. It may represent a “so-so”
legacy pattern that is less appropriate in a Compose world.
- 2023-11-21: Compose/Material3/Wear Compose updates! remember()! Adaptive layouts! Compose Multiplatform in 2024! @email@example.com on BasicTextField2()! Compose Multiplatform charts! And... is TV Compose in trouble?!?
- 2023-11-14: Compose Compiler! BasicTextField2()! @firstname.lastname@example.org and animations! Optimization! @email@example.com, JetBrains, and Fleet! JetBrains and plotting! And... we collapse?!?
- 2023-11-07: Compose Multiplatform! Chips in fields! Diffing! Custom fonts in Glance app widgets! Heatmaps! PIN input! And @firstname.lastname@example.org is in a bit of a haze?!?