compose/remote/Documentation/parts/rc_scroll.md
RemoteCompose provides a physics-based, hierarchical scrolling system that supports orthogonal nesting (e.g., horizontal rows inside vertical columns) and dynamic state synchronization.
To handle deep nesting and scrolling reliably, the interaction engine uses three distinct coordinate spaces:
| Space | Reference | Usage |
|---|---|---|
| Root-Relative | Document origin (0,0) | Used for top-level hit testing (contains(x, y)). |
Viewport-Relative (lx, ly) | Component top-left on screen | Used by Modifiers (ripples, scroll logic). |
Content-Relative (cx, cy) | Component's scrollable origin | Passed to children so they can ignore parent scroll. |
Scrolling is not hardcoded into layouts. Instead, LayoutComponent uses a ScrollDelegate interface. If a component has a ScrollModifierOperation in its modifier list, it registers itself as the delegate for horizontal or vertical axes.
LayoutComponent applies a translation transformation (getScrollX(), getScrollY()) before painting its children.CoreDocument)Touch events enter via CoreDocument.touchDown/Drag/Up. The document tracks "applied touch operations"—components currently being interacted with—to bypass hit-testing during a drag.
Component)Events propagate down the tree in reverse drawing order (top-most component first).
Interaction handlers return a boolean.
ScrollModifier) are still notified even if a child consumed the event. This allows a nested list to scroll even if the user started the drag on a button.TouchExpression)The ScrollModifierOperation typically hosts a TouchExpression. This engine handles:
VelocityEasing curve to continue the scroll.RemoteCompose handles nested scrolls by utilizing the "Orthogonal Capture" rule:
Layout managers like ColumnLayout and RowLayout are "scroll-aware":
internalLayoutMeasure, they check mComponentModifiers.hasVerticalScroll().setVerticalScrollDimension() to inform the modifier of the total scrollable range, which the TouchExpression uses for boundary clamping.