I’m curious about whether there is an API that all...
# compose
v
I’m curious about whether there is an API that allows me to get a callback about a composable being rendered on the screen or potentially modify a composable function right before its rendered. Sounds crazy I know but an API like
LayoutInflater.Factory2
gave some of this functionality in classic Android. Just curious if something like this already exists or is planned for in Compose.
a
The only real analog I can think of would be the composer interface itself. I'm curious what you would want to do along these lines
v
I was toying with the idea of adding overlays to composables for debugging reasons.
The simplest approach would be to create a default Modifier for your codebase that every Composable can use. The modifier would the provide this functionality through the logic that makes sense but I wonder if this can be done without every Composable having to “opt-in”
On a related note, I’m curious about what
InspectorInfo
does and if that could somehow be leveraged?
z
I would think you’d also need to get pretty granular events about individual recompose scopes – otherwise you’re analyzing the entire slot table/composable tree on every frame, which is quite slow (e.g. try clicking the checkbox in this sample app)
Hm, another idea: Can you wrap the
UiApplier
type that is used by the android composition? That used to be possible, not sure if it’s been locked down in recent versions. If you can wrap the applier though, you could get nice granular and immediate notifications any time LayoutNodes are added/removed. That type is internal now, so you might need reflection to read their bounds, and i’m not sure if there’s a way to directly listen to them for remeasure/relayout events, but if there is that might work. Of course you’d need a custom entry point as well then, couldn’t just use
setContent
anymore.
a
I think it's safe to say that this isn't a supported feature for the time being, but I'm keen to collect some use cases as it's kind of intriguing. We moved Composer to be an interface for other reasons of general API decoupling between the compiler plugin and runtime but it does raise this interesting avenue.
In general we've taken a fairly hard stance that thou shalt not manipulate the results of composable functions you call in any manner outside of their public API (which includes any CompositionLocals they consume)
This is demonstrated by the emit model, the preference for hoisted state objects as API, etc. Folks messing with Android date picker internals via findViewById and then being distressed by implementation detail changes that break those manipulations has stood as a cautionary tale throughout compose's development
v
@Zach Klippenstein (he/him) [MOD] Haven’t looked into hooks that UiApplier gives me but sounds like an interesting angle for sure!
@Adam Powell Thanks for shedding more light. I wonder how something like the overdraw debugging tool would be created in Compose? I know overdraw might not be that big of a concern in Compose due to the optimizations that are a first class citizen but a tool like that would be the use case that would require something like this.
the preference for hoisted state objects as API
On a related note, I’m curious about how state hoisting relates to not allowing manipulation of composable functions?
a
only in that it's a conscious pattern for exposing explicit API for callers to interact with
re. creating something like the overdraw debugging tool: probably by making it a part of compose-ui itself, from the state of things at the moment. Not a terribly satisfying answer, I know. 🙂
but for that in particular, drawing happens long after composition has come and gone. You would need to hook some very different parts of compose-ui than composition to do that.
v
well I’m sure everything will be possible with time 😄 Doing this in compose-ui makes sense if I had some way to get this information. I have a couple crazy ideas to do it with what I have today but I don’t know if these would actually work. 1. Use the slot table to get the bounds of each composable in the hierarchy. Then create a separate Compose tree using these bounds with the information you want in the overlays of the Composable. Finally, wrap this overlay compose tree into a
ComposeView
and inject this view directly at the top of the window/hierarchy. 2. The second idea is to somehow wrap every single Composable inside a
ComposeView
when a certain debug menu is enabled. Since every single composable is noew effectively a classic Android view as I wrap them inside ComposeView, I can just rely on
LayoutInflater.Factory2
to get the callbacks I need.
There are costs associated with both these options but since the purpose is debugging, maybe its acceptable to some level.
a
which overdraw debugging tool are you referring to anyway? the one in developer options already Just Works 🙂
(both 1 and 2 above are kind of terrifying)
v
hahaha agreed! And surprised to see the overdraw was just working but glad to see that! What I was hoping to do was something similar to overdraw where I add a colored overlay on top of the composable but also show the name of the composable in that overlay. This would help with something like component discovery.
a
yeah the layout inspector does the latter pretty well
z
Just to ruin Adam’s day ( 😛 ), I prototyped my idea and it kinda works – although I did this during a meeting so i didn’t bother getting removals, moves, or size changes working, and those are the really interesting bits.
🎖️ 1
🤔 1
v
that’s really cool!
and that’s a fair point. I just checked out the layout inspector with Compose support documentation and it seems like this should be good enough for now!