A good lesson from having dialog content which gra...
# compose-wear
y
A good lesson from having dialog content which grabs the Rotary focus. Use HierarchicalFocusCoordinator to respond to the focus events. With Navigation, this is handled for you. But not within a single screen composable with a dialog.
plus green 1
👏 1
Copy code
var shouldShowWarningOverlay by remember { mutableStateOf(false) }

    Box {
        HierarchicalFocusCoordinator(requiresFocus = {
            !shouldShowWarningOverlay
        }) {
            val state1 = rememberScalingLazyListState()
            ScalingLazyColumn(
                modifier = Modifier
                    .fillMaxSize()
                    .rotaryWithScroll(state1),
                state = state1
            ) {
...
            }
        }

        HierarchicalFocusCoordinator(requiresFocus = { shouldShowWarningOverlay }) {
            AnimatedVisibility(visible = shouldShowWarningOverlay) {
                val state2 = rememberScalingLazyListState()
                ScalingLazyColumn(
                    modifier = Modifier
                        .fillMaxSize()
                        .rotaryWithScroll(state2),
                    state = state2
                ) {
...
                }
            }
        }
    }
Without this, rotary stops working once you dismiss the dialog
l
Any chance this can be handled automatically?
j
What exactly does HierarchicalFocusCoordinator do? The documentation doesn’t make it’s functionality obvious. I’ve made elements focusable without it.
I guess better yet. How should I use
HierarchicalFocusCoordinator(…)
. For example. I have a custom timer picker composable, made up a hour, minute, and second composable, that all can receive focus in order to received rotary scroll events. I would imagine the 3 child composable should be wrapped in a `HierarchicalFocusCoordinator`(…). But I ran into trouble with the
requiresFocus
lambda. In order to determine which composable should be focused it seems like I’d need to implement a focus tracking system and defeating the purpose of the focus coordinator. Am I overthinking the component and it would work ideally for a custom time picker (Made up of 3 identical composable)?
y
Horologist has 2 time pickers. If you can't use them, the you can see how they work. They do include this
The focus system in compose isn't managed. It's just a bunch of FocusRequesters attached to things and last wins.
But multiple can be on screen or composed but off screen. Say a Pager.
Hierarchical focus control is a nested tree of composable things. The active one must have true all the way to the top.
So in a Pager, each screen has a HFC, but the one where current page == page num has true. So the right components grab focus.
Similar for navigation
It's easy to build in for navigation and pagers. Probably should be for real dialogs.
j
So each page of the pager should be wrapped in a HierarchicalFocusCoordinator but not necessarily each focusable composable in the screen?
y
Not sure about a dialog composable that just covers the parent.
Correct
🙏 1
j
On a related note to your original post, do you know why rotary event cause UI jank? I’ve built bare-bones test app and I was getting non-smooth rotary scrolls; In Logcat i see the following printed out
2023-11-13 165324.756 26118-26118 Choreographer com.android.vending I Skipped 59 frames! The application may be doing too much work on its main thread.
2023-11-13 165324.756 4312-4312 Choreographer com.example.oskitwear I Skipped 59 frames! The application may be doing too much work on its main thread.
2023-11-13 165324.756 485-572 system_server system_process W Long monitor contention with owner InputDispatcher (578) at void com.android.server.power.PowerManagerService.scheduleUserInactivityPreTimeout(long, long)(PowerManagerService.java:2957) waiters=0 in void com.android.server.power.PowerManagerService.releaseWakeLockInternal(android.os.IBinder, int) for 886ms
2023-11-13 165324.760 485-504 Looper system_process W Slow dispatch took 871ms android.fg h=android.os.Handler c=com.android.server.Watchdog$HandlerChecker@668b6a6 m=0
2023-11-13 165324.802 4312-4356 EGL_emulation com.example.oskitwear D app_time_stats: avg=1113.25ms min=1113.25ms max=1113.25ms count=1
y
No. But a great example for macro benchmark. Set up a scrolling test and check the trace. Especially with composition runtime tracing.
If you haven't set up baseline profiles then probably that.