Hey all, I’m looking for a way to traverse the lay...
# compose
a
Hey all, I’m looking for a way to traverse the layout tree at runtime. Something like findById in test tools, does such a thing exist?
z
Generally it’s best to use
Modifier.testTag
for that sort of thing
But there’s no way to explicitly walk the subtree of a node.
a
It’s more complex unfortunately, I’m needing to create custom “test tags” and then reference them at runtime. We have custom compose components that we want to tag for analytics
How does the layout inspector do this?
Or accessibility for that matter? They have to have some way to traverse the subtree
z
Layout inspector uses APIs like`CompositionData`’s
asTree
and
mapTree
methods, you could try that but those are only intended for tooling so i’m not sure how reliable they’ll be for tests
Accessibility info is generated from semantics using internal APIs
a
Oh thats what I’m looking for I think, we have the tests worked out, its scanning the tree at runtime for our custom components that I’m stuck on
z
so at runtime the
CompositionData
stuff might not work at all? I think some of that data is only generated in debug mode, and even then only when a certain flag is set, and it has a huge performance cost
i think this is very much the wrong approach. You probably want to use something like ModifierLocals or the new TraversableNode API
although there might be other approaches – hard to say without knowing more about your system
a
It very well may be the wrong approach I’m newer to this. Im more accustomed to view binding where you reference the id lol
z
1. How do you generate tags? 2. How do you actually need to consume the tags? E.g. do you have some logic that runs a callback when a tagged view becomes visible, or something else?
a
Right now, tags will be strings in our composable functions within our library. Not sure which approach is best here but leaning towards a modifier extension function. Needing to pass Library project name, library version and component name all as strings. When that library is used in an application (and analytic calls are triggered) we need to check the screen for our custom components by capturing those tags. We are the first project to create a pure compose library and app at my company
Trying to capture usage and adoption metrics
z
Ok, so you have some external polling mechanism that asks “what tagged views are on screen right now” – correct?
a
Not yet, but that’s the idea.
It’s Adobe Analytics
z
So what I would probably do is build a modifier that registers for that signal and uses its LayoutCoordinates to lazily figure out if it’s visible or not and report itself.
Something like this
🌟 1
a
Oh ok, then apply that modifier to each component I want to track
z
exactly
And wrap your whole app in something like this to provide the `AnalyticsController`:
Copy code
@Composable fun App(analyticsController: AnalyticsController) {
  CompositionLocalProvider(LocalAnalyticsController provides analyticsController) {
    RestOfApp()
  }
}
a
Can I apply that to the component at the library level or would I need to do that in the application that consumes the lib?
z
Does your library already have some root composable wrapper it expects the app to use? If so, you could put it in there. Otherwise, I would either: 1. Expose
LocalAnalyticsController
and
AnalyticsController
from your library and ask the consuming app to provide an instance however it likes, or 2. Make
LocalAnalyticsController
private, expose
AnalyticsController
, and expose a
@Composable fun AnalyticsControllerProvider(controller: AnalyticsController)
function that your consuming app must use. (1) is simpler, and also allows your library consumers to consume the
LocalAnalyticsController
which may be good (for flexibility) or bad (if you want to control how it’s used).
a
Beautiful, I’ll give it a go! You mind if I DM you if I get too deep?
z
go ahead