Hysteresis window for VirtualViewExperimental (#53765)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53765

Changelog: [Internal] Introduce hysteresis window for experimental VirtualView

Reviewed By: yungsters

Differential Revision: D82354142

fbshipit-source-id: 13ec0e3a46930d3bea0ea67060c5f0e1c137dec1
This commit is contained in:
Luna Wei
2025-09-13 21:41:49 -07:00
committed by Facebook GitHub Bot
parent 4f20e4d0fc
commit 56e5dff73f
2 changed files with 25 additions and 7 deletions
@@ -50,11 +50,13 @@ private fun rectsOverlap(rect1: Rect, rect2: Rect): Boolean {
internal class VirtualViewContainerState {
private val prerenderRatio: Double = ReactNativeFeatureFlags.virtualViewPrerenderRatio()
private val hysteresisRatio: Double = ReactNativeFeatureFlags.virtualViewHysteresisRatio()
private val virtualViews: MutableSet<VirtualView> = mutableSetOf()
private val emptyRect: Rect = Rect()
private val visibleRect: Rect = Rect()
private val prerenderRect: Rect = Rect()
private val hysteresisRect: Rect = Rect()
private val onWindowFocusChangeListener =
if (ReactNativeFeatureFlags.enableVirtualViewWindowFocusDetection()) {
ViewTreeObserver.OnWindowFocusChangeListener {
@@ -124,7 +126,7 @@ internal class VirtualViewContainerState {
virtualViewsIt.forEach { vv ->
val rect = vv.containerRelativeRect
var mode = VirtualViewMode.Hidden
var mode: VirtualViewMode? = VirtualViewMode.Hidden
var thresholdRect = emptyRect
when {
rectsOverlap(rect, visibleRect) -> {
@@ -143,14 +145,29 @@ internal class VirtualViewContainerState {
mode = VirtualViewMode.Prerender
thresholdRect = prerenderRect
}
else -> {}
else -> {
if (hysteresisRatio > 0.0) {
hysteresisRect.set(prerenderRect)
hysteresisRect.inset(
(-visibleRect.width() * hysteresisRatio).toInt(),
(-visibleRect.height() * hysteresisRatio).toInt(),
)
if (rectsOverlap(rect, hysteresisRect)) {
mode = null
}
}
}
}
debugLog(
"updateModes",
{ "virtualView=${vv.virtualViewID} mode=$mode rect=$rect thresholdRect=$thresholdRect" },
)
vv.onModeChange(mode, thresholdRect)
if (mode != null) {
vv.onModeChange(mode, thresholdRect)
debugLog(
"updateModes",
{
"virtualView=${vv.virtualViewID} mode=$mode rect=$rect thresholdRect=$thresholdRect"
},
)
}
}
}
}
@@ -20,6 +20,7 @@ import com.facebook.react.uimanager.ReactClippingViewGroup
import com.facebook.react.uimanager.ReactRoot
import com.facebook.react.views.scroll.VirtualView
import com.facebook.react.views.scroll.VirtualViewContainer
import com.facebook.react.views.scroll.debugLog
import com.facebook.react.views.view.ReactViewGroup
import com.facebook.react.views.virtual.VirtualViewMode
import com.facebook.react.views.virtual.VirtualViewModeChangeEmitter