Skip to content

Commit 328d07a

Browse files
CalixTangmeta-codesync[bot]
authored andcommitted
Implement VirtualViewContainerStateExperimental (interval tree, updateModes optimization) (#54213)
Summary: Pull Request resolved: #54213 ## Changelog: [Internal] Modifies `VirtualViewContainerStateExperimental` to use an interval tree to store the container's VirtualViews. Interval tree's query allows us to lower the frequently-used updateModes() operation from `O(n)` to `O(m + log n)`, where `m` is the number of VirtualViews in the hysteresis range. General layout changes incur a penalty due to the requirement of maintaining a balanced BST. Performance Changes: * updateModes(): `O(n) -> O(m + log n)` (new algo) * updateMode(): `O(1) -> O(1)` * add VV: `O(1) -> O(log n)` * update VV: `O(1) -> O(log n)` * delete VV: `O(1) -> O(log n)` We expect scrolling to be much more frequent than a total layout change/updating many of the elements in the container at once. However, the initial load of a page will take `O(n log n)` time rather than `O(n)` time. We also include some bookkeeping sets for "old" hysteresis, prerender, and visible VVs. This will increase the memory footprint of `VirtualViewContainerState` by `O(m)`. More details are in https://docs.google.com/document/d/1Cmamx6fNfruoHLApX8tedqNVZsCEUyoBvQWpMvBsfcY/edit?tab=t.gqla6vu3231k. ### Note This diff only covers the Android version. iOS may follow after experimentation. Reviewed By: lunaleaps Differential Revision: D83783201 fbshipit-source-id: 93a7a93784d668e09d8ddacc7e30d289ccd8b7a2
1 parent 793f99d commit 328d07a

File tree

2 files changed

+518
-56
lines changed

2 files changed

+518
-56
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/VirtualViewContainer.kt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,45 @@ internal abstract class VirtualViewContainerState {
111111
updateModes()
112112
}
113113

114+
/**
115+
* Refreshes the coordinates for the Rects this class cares about (visibleRect, prerenderRect,
116+
* hysteresisRect)
117+
*/
118+
protected fun updateRects() {
119+
scrollView.getDrawingRect(visibleRect)
120+
121+
// This happens because ScrollView content isn't ready yet. The danger here is if ScrollView
122+
// intentionally goes but curently ScrollView and v1 Fling use this check to determine if
123+
// "content ready"
124+
if (visibleRect.isEmpty()) {
125+
debugLog("updateRects", { "scrollView visibleRect is empty" })
126+
// should set the other rects here in case scrollview is suddenly empty after the other rects
127+
// are non-empty
128+
prerenderRect.set(visibleRect)
129+
hysteresisRect.set(prerenderRect)
130+
return
131+
}
132+
133+
prerenderRect.set(visibleRect)
134+
prerenderRect.inset(
135+
(-prerenderRect.width() * prerenderRatio).toInt(),
136+
(-prerenderRect.height() * prerenderRatio).toInt(),
137+
)
138+
139+
hysteresisRect.set(prerenderRect)
140+
hysteresisRect.inset(
141+
(-visibleRect.width() * hysteresisRatio).toInt(),
142+
(-visibleRect.height() * hysteresisRatio).toInt(),
143+
)
144+
145+
debugLog(
146+
"updateRects",
147+
{
148+
"visibleRect ${visibleRect.toString()} prerenderRect ${prerenderRect.toString()} hysteresisRect ${hysteresisRect.toString()}"
149+
},
150+
)
151+
}
152+
114153
protected abstract fun updateModes(virtualView: VirtualView? = null)
115154
}
116155

0 commit comments

Comments
 (0)