jetc.dev Newsletter Issue #55
Published: 2021-03-09
This week, as we gear up for a possible beta02
release, we look at scrolling
lists: how to disable the scrolling and how to have stateful rows.
We also hear from Google’s Leland Richardson, spend time with architecture,
spend even more time with clocks, and peek at a reusable pull-to-refresh
composable. Plus, I beg you to start thinking about what else you can fix
in your UI as you migrate to Compose… such as thinking about other form factors.
One Off the Stack, One Off the Slack
You’ve got questions. That’s understandable!
How to Disable and Enable Scrolling?
LazyColumn()
and LazyRow()
offer built-in scrolling. However, you might
have the desire to temporarily disable scrolling, then re-enable it later.
This is not offered by those composables, but Google’s Ryan Mentley shows us how
we can implement it ourselves, in this week’s highlighted Stack Overflow question.
Stateful Rows in a LazyColumn()
The good news: having rows with state (e.g., a checkbox) is a lot simpler with
Compose UI than it is with RecyclerView
. The bad news: you still need to think
through the state management, as we see in this week’s highlighted
Kotlinlang #compose
Slack thread.
Composable Commentary
Posts, videos, and other new information related to Jetpack Compose!
Video: Jetpack Compose Beta AMA
Google’s Leland Richardson hosted an hour-long livestream where he took questions about Compose and Compose UI from the audience and offered up his best answers!
How To Understand Composables & Recomposition
Ryan Kay walks us through the act of recomposition, including when it occurs and what all gets recomposed. If you prefer a video format, Ryan has a short YouTube video on the same subject. He also wrote a post this week on modeling UI events with sealed classes in Compose.
Architecture in Jetpack Compose — MVP, MVVM, & MVI
Ian Alexander looks at how the MV* architecture patterns that we all know and
hate love translate into the world of Compose and Compose UI.
Getting ready for Declarative UIs — Part 2 — Implementing Unidirectional Data Flow
Raul Hernandez Lopez gives us another peek at architecture in Compose and similar sorts of reactive/declarative UIs. This time, Raul explores the meaning and implementation of a “unidirectional data flow”, which is a popular structure that Compose supports well.
Compose O’Clock
This week is all about Compose keeping track of time, courtesy of the countdown timer called for in the second week of the Android Developer Challenge. However, there are other types of clocks. Márton Braun and Aurimas Liutikas each demonstrated creating an animated clock using Compose UI, using vertical strips of numbers for each digit in the time, sliding up and down as the time changes.
Compose (UI) beyond the UI (Part III): No AAC-ViewModel and a sample app
Jordi Saumell continues a walkthrough of Compose UI, looking at how we can
avoid the Jetpack ViewModel
entirely. This time, Jordi walks through… yet another
clock app, showing how the time gets updated without needing a ViewModel
to emit
changes to that time.
Video: Step It Up: Compose for Desktop
Nishant Srivastava delivered a short presentation on Compose for Desktop at FOSDEM 2021, looking at how it works and showing how to get started with desktop app development.
Mavericks, Meet Jetpack Compose
Mavericks (or MvRx) is an RxJava-powered MVI app framework
published by AirBnb. Gabriel Peal announced mavericks-compose
, which provides
Compose integration for Mavericks.
Wrap Compose IDEA/Android Studio Plugin
Rasul Aghakishiyev has published a small IDE plugin that wraps a selected composable
in one of a number of common composables, such as Box()
or Row()
.
Fix: Jetpack Compose observeAsState Type Error has no method
Paul Blundell reminds us that you need to add import androidx.compose.runtime.getValue
and
import androidx.compose.runtime.setValue
to avoid delegate problems when using
observeAsState()
to recompose based on changes in the value of a LiveData
.
Resource Roundup
100% pure code!
GitHub: poculeka / PullToRefresh
Adrian Pucułek put together a small library containing a pull-to-refresh composable.
You can wrap a LazyColumn()
in a PullToRefresh()
, where you supply an onRefresh
parameter to get control when the gesture is triggered so you can update your data
model and recompose your UI.
GitHub: jeziellago / compose-markdown
Jeziel Lago brings us a library that offers a MarkdownText()
composable that handles
rendering Markdown-formatted text.
GitHub: STAR-ZERO / ComposeFlowLayout
A “flow layout” continues to be popular: show as many children as possible on
the current row, then start a new row and continue. We saw one implementation
of this back in Issue #32. Kenji Abe
offers up another library with a FlowLayout()
composable, where you provide the
spacing of items, plus the items itself, and FlowLayout()
flows them across
however many rows are required.
Gist: vitorprado / RatingBar.kt
Vitor Prado brings us a small RatingBar()
composable, where we provide the rating
as a Float
in the 0-5 range and it renders a row of stars for that rating, including
a partial final star.
…And One More Thing
Now that Compose and Compose UI are in their first beta, teams may start to think about beginning to use these technologies in their apps. If your team is among them, you should consider taking this opportunity to also clean up other shaky practices in your current UI implementation.
For example, you might want to stop thinking of screen sizes.
Some Android developers are fixated on finding screen dimensions, then trying
to use them. For example, in Compose UI, you can find the screen height using
LocalConfiguration.current.screenHeightDp
.
However, this is not really a good idea… because your app may not be using the full screen.
Most Android devices nowadays support split-screen mode. Many users will not be using that mode, but some will. In split-screen mode, your app’s window is not going to take up the full screen, but rather only part of it.
Chrome OS devices, and specialty “desktop-style environments” like Samsung DeX, use Android’s free-form multiwindow support. In this case, your app’s window also is not going to take up the full screen, but rather only part of it. Many users will not be using this sort of device or environment, but some will.
With “foldables”, the screen size can change, and users may be more prone to use split-screen mode. We might soon get “rollable” phones. Who knows what other form factors will follow those? After all, who would have predicted the LG Wing?
(personally, I half expect the next segment to be “crumple-ables”)
You might look at all of those and conclude that none of them are very popular. That may well be true. However, combined, the number of users using one of those environments might be interesting.
More importantly, manufacturers keep trying, presumably with some encouragement and support from Google. Eventually, something is going to become a hit, either on its own merits or because Apple decides that it is cool.
In other words, the era of “one screen = one app” most likely is coming to a close.
So, rather than think in terms of “how big is the screen?”, think instead in terms
of “how much space do I have?”. We saw this a few weeks ago in
the “How Big Are We?” post in the “One Off the Slack” series.
You can use things like BoxWithConstraints
or onSizeChanged()
to be able to adapt
your UI to match the available space, and let the system worry how much space
that is.
Adopting Compose UI will require a significant overhaul of your UI code, as you adopt Compose UI progressively through your app. While you are making those changes, think through what other assumptions your code is making, and see if you can avoid making those assumptions, to better future-proof your UI. After all, you never know when someday your app needs to run on a phone that the user can just crumple up and shove in their pocket.
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?!?