jetc.dev Newsletter Issue #74
Published: 2021-07-20
rc02
shipped! And, since there are already signs of the first alpha for 1.1.0
,
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.
RC Reflections
Reviewing the release notes for the latest Jetpack Compose update!
Blissfully, rc02
has few changes, and most of those are just bug fixes. They did
semi-revert an rc01
change, so now dialogs will be sized based on the platform
by default â use usePlatformDefaultWidth = false
to change this back to
rc01
-style behavior.
One Off the Stack, One Off the Slack
Youâve got questions. Thatâs understandable!
Responding to Long Clicks
The 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.
@Preview and a ViewModel, Again
A few months ago, we looked at having a @Preview
composable accept a ViewModel
parameter.
That subject came up again, garnering a few new possible solutions, as we see
in this weekâs highlighted Kotlinlang #compose
Slack thread.
Composable Commentary
Posts, videos, and other new information related to Jetpack Compose!
Coil: Migrating From Accompanist
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.
New TwoPaneLayout Compose library preview
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.
How Jetpack Compose is Helping Put Accessibility First
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 accessibilityHeading
and onClickLabel
.
Compose architecture: MVVM or MVI with Flow?
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.
Medium: Jetpack Compose: Missing piece to the MVI puzzle?
Garima Jain also examines MVI, seeing how Compose support for @Stable
and @Immutable
can help deal with MVIâs preference for immutable view states while minimizing the cost
of recomposition as the view state changes.
Welcome you are visitor number 12345
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.
Video: Jetpack Compose Navigation for Beginners
Philipp Lackner is back to take a look at Navigation for Compose and the basic steps for adding it to a project and using it to navigate between screen composables.
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
Resource Roundup
100% pure code!
GitHub: JohannBlake / bitmap-from-composable
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 ComposeView
.
Johann also wrote a Medium post
with more information.
GitHub: thesauri / dpad-compose
Walter Berggren created a demonstration of how to pull off support for directional navigation in the current Compose UI code.
GitHub: boguszpawlowski / ComposeCalendar
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 Activity
extending Context
, and 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
SharedPreferences
value? 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.,
InputMethodManager
). -
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.
Referencing 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.
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?!?