Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ typedef NS_ENUM(NSInteger, RCTVirtualViewMode) {
RCTVirtualViewModeHidden = 2,
};

typedef NS_ENUM(NSInteger, RCTVirtualViewRenderState) {
RCTVirtualViewRenderStateUnknown = 0,
RCTVirtualViewRenderStateRendered = 1,
RCTVirtualViewRenderStateNone = 2,
};

/**
* Checks whether one CGRect overlaps with another CGRect.
*
Expand Down Expand Up @@ -67,25 +73,43 @@ @interface RCTVirtualViewComponentView () <UIScrollViewDelegate>
@implementation RCTVirtualViewComponentView {
RCTScrollViewComponentView *_lastParentScrollViewComponentView;
std::optional<enum RCTVirtualViewMode> _mode;
enum RCTVirtualViewRenderState _renderState;
std::optional<CGRect> _targetRect;
}

- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
_props = VirtualViewShadowNode::defaultSharedProps();
_renderState = RCTVirtualViewRenderStateUnknown;
}

return self;
}

- (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps
{
const auto &newViewProps = static_cast<const VirtualViewProps &>(*props);

if (!_mode.has_value()) {
const auto &newViewProps = static_cast<const VirtualViewProps &>(*props);
_mode = newViewProps.initialHidden ? RCTVirtualViewModeHidden : RCTVirtualViewModeVisible;
}

// If disabled, `_renderState` will always be `RCTVirtualViewRenderStateUnknown`.
if (ReactNativeFeatureFlags::enableVirtualViewRenderState()) {
switch (newViewProps.renderState) {
case 1:
_renderState = RCTVirtualViewRenderStateRendered;
break;
case 2:
_renderState = RCTVirtualViewRenderStateNone;
break;
default:
_renderState = RCTVirtualViewRenderStateUnknown;
break;
}
}

[super updateProps:props oldProps:oldProps];
}

Expand Down Expand Up @@ -219,7 +243,18 @@ - (void)dispatchOnModeChangeIfNeeded:(BOOL)checkForTargetRectChange

switch (newMode) {
case RCTVirtualViewModeVisible:
[self dispatchSyncModeChange:event];
if (_renderState == RCTVirtualViewRenderStateUnknown) {
// Feature flag is disabled, so use the former logic.
[self dispatchSyncModeChange:event];
} else {
// If the previous mode was prerender and the result of dispatching that event was committed, we do not need to
// dispatch an event for visible.
const auto wasPrerenderCommitted = oldMode.has_value() && oldMode == RCTVirtualViewModePrerender &&
_renderState == RCTVirtualViewRenderStateRendered;
if (!wasPrerenderCommitted) {
[self dispatchSyncModeChange:event];
}
}
break;
case RCTVirtualViewModePrerender:
if (!oldMode.has_value() || oldMode != RCTVirtualViewModeVisible) {
Expand Down
1 change: 1 addition & 0 deletions packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -5290,6 +5290,7 @@ public class com/facebook/react/viewmanagers/VirtualViewManagerDelegate : com/fa

public abstract interface class com/facebook/react/viewmanagers/VirtualViewManagerInterface : com/facebook/react/uimanager/ViewManagerWithGeneratedInterface {
public abstract fun setInitialHidden (Landroid/view/View;Z)V
public abstract fun setRenderState (Landroid/view/View;I)V
}

public final class com/facebook/react/views/drawer/ReactDrawerLayout : androidx/drawerlayout/widget/DrawerLayout {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<7d9248932099e75eb56ed8b7409b764e>>
* @generated SignedSource<<442cbf571b5654c5d322ca1b5542db7d>>
*/

/**
Expand Down Expand Up @@ -258,6 +258,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun enableVirtualViewDebugFeatures(): Boolean = accessor.enableVirtualViewDebugFeatures()

/**
* Enables reading render state when dispatching VirtualView events.
*/
@JvmStatic
public fun enableVirtualViewRenderState(): Boolean = accessor.enableVirtualViewRenderState()

/**
* Enables window focus detection for prioritizing VirtualView events.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<04fa992cf8fec2d89a49cc03bc3f7757>>
* @generated SignedSource<<166a7cc18f83861c6c4d7f96a55c5843>>
*/

/**
Expand Down Expand Up @@ -58,6 +58,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
private var enableViewRecyclingForTextCache: Boolean? = null
private var enableViewRecyclingForViewCache: Boolean? = null
private var enableVirtualViewDebugFeaturesCache: Boolean? = null
private var enableVirtualViewRenderStateCache: Boolean? = null
private var enableVirtualViewWindowFocusDetectionCache: Boolean? = null
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
private var fuseboxEnabledReleaseCache: Boolean? = null
Expand Down Expand Up @@ -416,6 +417,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
return cached
}

override fun enableVirtualViewRenderState(): Boolean {
var cached = enableVirtualViewRenderStateCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.enableVirtualViewRenderState()
enableVirtualViewRenderStateCache = cached
}
return cached
}

override fun enableVirtualViewWindowFocusDetection(): Boolean {
var cached = enableVirtualViewWindowFocusDetectionCache
if (cached == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<89ffcb75b9b94600174ba8a704314a69>>
* @generated SignedSource<<27e8fa8139901c1decaba5bfcbced221>>
*/

/**
Expand Down Expand Up @@ -104,6 +104,8 @@ public object ReactNativeFeatureFlagsCxxInterop {

@DoNotStrip @JvmStatic public external fun enableVirtualViewDebugFeatures(): Boolean

@DoNotStrip @JvmStatic public external fun enableVirtualViewRenderState(): Boolean

@DoNotStrip @JvmStatic public external fun enableVirtualViewWindowFocusDetection(): Boolean

@DoNotStrip @JvmStatic public external fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<a6d35f8073773430d24779cd69f194f1>>
* @generated SignedSource<<5efae3bf30e8acf69f0682372c39f7b2>>
*/

/**
Expand Down Expand Up @@ -99,6 +99,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi

override fun enableVirtualViewDebugFeatures(): Boolean = false

override fun enableVirtualViewRenderState(): Boolean = false

override fun enableVirtualViewWindowFocusDetection(): Boolean = false

override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<466ed58fa72b8d114887bb0a4931aa18>>
* @generated SignedSource<<498e9a51a9a0d0c0c4eb69c84bb33dd1>>
*/

/**
Expand Down Expand Up @@ -62,6 +62,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
private var enableViewRecyclingForTextCache: Boolean? = null
private var enableViewRecyclingForViewCache: Boolean? = null
private var enableVirtualViewDebugFeaturesCache: Boolean? = null
private var enableVirtualViewRenderStateCache: Boolean? = null
private var enableVirtualViewWindowFocusDetectionCache: Boolean? = null
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
private var fuseboxEnabledReleaseCache: Boolean? = null
Expand Down Expand Up @@ -458,6 +459,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
return cached
}

override fun enableVirtualViewRenderState(): Boolean {
var cached = enableVirtualViewRenderStateCache
if (cached == null) {
cached = currentProvider.enableVirtualViewRenderState()
accessedFeatureFlags.add("enableVirtualViewRenderState")
enableVirtualViewRenderStateCache = cached
}
return cached
}

override fun enableVirtualViewWindowFocusDetection(): Boolean {
var cached = enableVirtualViewWindowFocusDetectionCache
if (cached == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<caf71a49d116ff499ef11c5657323cdd>>
* @generated SignedSource<<fce6841e89beec5be32b76fc0941ef95>>
*/

/**
Expand Down Expand Up @@ -99,6 +99,8 @@ public interface ReactNativeFeatureFlagsProvider {

@DoNotStrip public fun enableVirtualViewDebugFeatures(): Boolean

@DoNotStrip public fun enableVirtualViewRenderState(): Boolean

@DoNotStrip public fun enableVirtualViewWindowFocusDetection(): Boolean

@DoNotStrip public fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ internal class ReactVirtualView(context: Context) :
View.OnLayoutChangeListener {

internal var mode: VirtualViewMode? = null
internal var renderState: VirtualViewRenderState = VirtualViewRenderState.Unknown
internal var modeChangeEmitter: ModeChangeEmitter? = null
internal var prerenderRatio: Double = ReactNativeFeatureFlags.virtualViewPrerenderRatio()
internal val debugLogEnabled: Boolean = ReactNativeFeatureFlags.enableVirtualViewDebugFeatures()
Expand Down Expand Up @@ -267,7 +268,18 @@ internal class ReactVirtualView(context: Context) :
"VirtualView::mode change $oldMode -> $newMode, nativeID=$nativeId")
when (newMode) {
VirtualViewMode.Visible -> {
emitSyncModeChange(VirtualViewMode.Visible)
if (renderState == VirtualViewRenderState.Unknown) {
// Feature flag is disabled, so use the former logic.
emitSyncModeChange(VirtualViewMode.Visible)
} else {
// If the previous mode was prerender and the result of dispatching that event was
// committed, we do not need to dispatch an event for visible.
val wasPrerenderCommitted =
oldMode == VirtualViewMode.Prerender && renderState == VirtualViewRenderState.Rendered
if (!wasPrerenderCommitted) {
emitSyncModeChange(VirtualViewMode.Visible)
}
}
}
VirtualViewMode.Prerender -> {
if (oldMode != VirtualViewMode.Visible) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package com.facebook.react.views.virtualview

import android.graphics.Rect
import androidx.annotation.VisibleForTesting
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
import com.facebook.react.module.annotations.ReactModule
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.UIManagerHelper
Expand Down Expand Up @@ -39,6 +40,19 @@ internal class ReactVirtualViewManager :
}
}

@ReactProp(name = "renderState")
override fun setRenderState(view: ReactVirtualView, value: Int) {
// If disabled, `renderState` will always be `VirtualViewRenderState.Unknown`.
if (ReactNativeFeatureFlags.enableVirtualViewRenderState()) {
view.renderState =
when (value) {
1 -> VirtualViewRenderState.Rendered
2 -> VirtualViewRenderState.None
else -> VirtualViewRenderState.Unknown
}
}
}

override fun setNativeId(view: ReactVirtualView, nativeId: String?) {
super.setNativeId(view, nativeId)
view.debugLog("setNativeId") { "${view.id}" }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.react.views.virtualview

/**
* Represents the the render state of children in the most recent commit.
*
* This enables `ReactVirtualView` to know whether a previously emitted `VirtualViewModeChangeEvent`
* has been committed, in order to only emit subsequent events that would change it.
*/
internal enum class VirtualViewRenderState(val value: Int) {
Unknown(0),
Rendered(1),
None(2),
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<8f4c2b4cd9f25778e0809c1261aa4728>>
* @generated SignedSource<<04d1e45bd61df19a284947523172bf4a>>
*/

/**
Expand Down Expand Up @@ -267,6 +267,12 @@ class ReactNativeFeatureFlagsJavaProvider
return method(javaProvider_);
}

bool enableVirtualViewRenderState() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableVirtualViewRenderState");
return method(javaProvider_);
}

bool enableVirtualViewWindowFocusDetection() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableVirtualViewWindowFocusDetection");
Expand Down Expand Up @@ -551,6 +557,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableVirtualViewDebugFeatures(
return ReactNativeFeatureFlags::enableVirtualViewDebugFeatures();
}

bool JReactNativeFeatureFlagsCxxInterop::enableVirtualViewRenderState(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::enableVirtualViewRenderState();
}

bool JReactNativeFeatureFlagsCxxInterop::enableVirtualViewWindowFocusDetection(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::enableVirtualViewWindowFocusDetection();
Expand Down Expand Up @@ -771,6 +782,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"enableVirtualViewDebugFeatures",
JReactNativeFeatureFlagsCxxInterop::enableVirtualViewDebugFeatures),
makeNativeMethod(
"enableVirtualViewRenderState",
JReactNativeFeatureFlagsCxxInterop::enableVirtualViewRenderState),
makeNativeMethod(
"enableVirtualViewWindowFocusDetection",
JReactNativeFeatureFlagsCxxInterop::enableVirtualViewWindowFocusDetection),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<b9c0a8157499e2007c6afafe2f59d0ce>>
* @generated SignedSource<<bdf1914ba3b7ac5e86d028c69f5073be>>
*/

/**
Expand Down Expand Up @@ -144,6 +144,9 @@ class JReactNativeFeatureFlagsCxxInterop
static bool enableVirtualViewDebugFeatures(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);

static bool enableVirtualViewRenderState(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);

static bool enableVirtualViewWindowFocusDetection(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<74d7512ad4e33dd4ba58cdf1da104173>>
* @generated SignedSource<<ad9c01a715c11edb67626cd3e801144d>>
*/

/**
Expand Down Expand Up @@ -178,6 +178,10 @@ bool ReactNativeFeatureFlags::enableVirtualViewDebugFeatures() {
return getAccessor().enableVirtualViewDebugFeatures();
}

bool ReactNativeFeatureFlags::enableVirtualViewRenderState() {
return getAccessor().enableVirtualViewRenderState();
}

bool ReactNativeFeatureFlags::enableVirtualViewWindowFocusDetection() {
return getAccessor().enableVirtualViewWindowFocusDetection();
}
Expand Down
Loading
Loading