From 0a5bf335b082e2b7c852f42590444553c806cdc7 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Tue, 9 Jun 2026 03:32:46 -0700 Subject: [PATCH 1/2] Override shouldDelayChildPressedState in Android containers Summary: Changelog: [Android][Fixed] Prevent React Native containers from delaying native touches [`shouldDelayChildPressedState`](https://developer.android.com/reference/android/view/ViewGroup#shouldDelayChildPressedState%28%29) returns `true` for compatibility reasons and non-scrollable containers should override it and return `false` to prevent the press feedback from being delayed. Differential Revision: D108003374 --- packages/react-native/ReactAndroid/api/ReactAndroid.api | 2 ++ .../java/com/facebook/react/views/modal/ReactModalHostView.kt | 2 ++ .../com/facebook/react/views/safeareaview/ReactSafeAreaView.kt | 2 ++ .../com/facebook/react/views/text/PreparedLayoutTextView.kt | 2 ++ .../main/java/com/facebook/react/views/view/ReactViewGroup.kt | 2 ++ 5 files changed, 10 insertions(+) diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index fe791820641..8ea2cabcbc6 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -5403,6 +5403,7 @@ public final class com/facebook/react/views/modal/ReactModalHostView : android/v public final fun setStateWrapper (Lcom/facebook/react/uimanager/StateWrapper;)V public final fun setStatusBarTranslucent (Z)V public final fun setTransparent (Z)V + public fun shouldDelayChildPressedState ()Z public final fun showOrUpdate ()V } @@ -6445,6 +6446,7 @@ public class com/facebook/react/views/view/ReactViewGroup : android/view/ViewGro public fun setPointerEvents (Lcom/facebook/react/uimanager/PointerEvents;)V public fun setRemoveClippedSubviews (Z)V public final fun setTranslucentBackgroundDrawable (Landroid/graphics/drawable/Drawable;)V + public fun shouldDelayChildPressedState ()Z public fun updateClippingRect ()V public fun updateClippingRect (Ljava/util/Set;)V } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt index f36a1e3e138..629dffd5d73 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt @@ -134,6 +134,8 @@ public class ReactModalHostView(context: ThemedReactContext) : dialogRootViewGroup.dispatchProvideStructure(structure) } + override fun shouldDelayChildPressedState(): Boolean = false + protected override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { // Do nothing as we are laid out by UIManager } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/safeareaview/ReactSafeAreaView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/safeareaview/ReactSafeAreaView.kt index 86c25787dec..6a7792c8d5b 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/safeareaview/ReactSafeAreaView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/safeareaview/ReactSafeAreaView.kt @@ -39,6 +39,8 @@ internal class ReactSafeAreaView(val reactContext: ThemedReactContext) : ViewGro override fun onLayout(p0: Boolean, p1: Int, p2: Int, p3: Int, p4: Int): Unit = Unit + override fun shouldDelayChildPressedState(): Boolean = false + @Suppress("DEPRECATION") @UiThread private fun updateState(insets: Insets) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/PreparedLayoutTextView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/PreparedLayoutTextView.kt index 21609f7fd4f..67efb025b39 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/PreparedLayoutTextView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/PreparedLayoutTextView.kt @@ -402,6 +402,8 @@ internal class PreparedLayoutTextView(context: Context) : ViewGroup(context), Re } } + override fun shouldDelayChildPressedState(): Boolean = false + public override fun dispatchHoverEvent(event: MotionEvent): Boolean = super.dispatchHoverEvent(event) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt index 038778eeac5..24009633c75 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt @@ -650,6 +650,8 @@ public open class ReactViewGroup public constructor(context: Context?) : } } + override fun shouldDelayChildPressedState(): Boolean = false + override fun dispatchSetPressed(pressed: Boolean) { // Prevents the ViewGroup from dispatching the pressed state // to it's children. From 14198add936749a50cd45289ff27da9e364fc22d Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Tue, 9 Jun 2026 03:32:46 -0700 Subject: [PATCH 2/2] Allow to disable shouldDelayChildPressedState on scrollable Android containers Summary: Changelog: [Android][Added] Added an entry point that allows changing whether the scrollable React Native containers should delay pressed state in children views Scrollable Android containers should return `true` (the default implementation) from [`shouldDelayChildPressedState`](https://developer.android.com/reference/android/view/ViewGroup#shouldDelayChildPressedState%28%29) in order to delay pressed state feedback in children. This way the feedback isn't triggered at all during quick scrolls. React Native touch system doesn't rely on this so it's not affected by that behavior, but native components are which can produce a divergent experience. This diff adds a property to all scrollable components of React Native which allows external consumers to control this behavor on a per-view basis. The API is analoguous to [`delaysContentTouches`](https://developer.apple.com/documentation/uikit/uiscrollview/delayscontenttouches?language=objc) on iOS. Differential Revision: D108003375 --- .../ReactAndroid/api/ReactAndroid.api | 25 +++++++++++++--- .../uimanager/HasChildPressedStateDelay.kt | 29 +++++++++++++++++++ .../react/views/drawer/ReactDrawerLayout.kt | 9 +++++- .../views/scroll/ReactHorizontalScrollView.kt | 8 ++++- .../views/scroll/ReactNestedScrollView.kt | 10 +++++-- .../react/views/scroll/ReactScrollView.kt | 8 ++++- .../swiperefresh/ReactSwipeRefreshLayout.kt | 8 ++++- 7 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/HasChildPressedStateDelay.kt diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 8ea2cabcbc6..09dc9963050 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -3303,6 +3303,11 @@ public abstract class com/facebook/react/uimanager/GuardedFrameCallback : androi protected abstract fun doFrameGuarded (J)V } +public abstract interface class com/facebook/react/uimanager/HasChildPressedStateDelay { + public abstract fun getHasChildPressedStateDelay ()Ljava/lang/Boolean; + public abstract fun setHasChildPressedStateDelay (Ljava/lang/Boolean;)V +} + public abstract interface class com/facebook/react/uimanager/IViewGroupManager : com/facebook/react/uimanager/IViewManagerWithChildren { public abstract fun addView (Landroid/view/View;Landroid/view/View;I)V public abstract fun getChildAt (Landroid/view/View;I)Landroid/view/View; @@ -5146,10 +5151,13 @@ public abstract interface class com/facebook/react/viewmanagers/VirtualViewManag public abstract fun setRenderState (Landroid/view/View;I)V } -public final class com/facebook/react/views/drawer/ReactDrawerLayout : androidx/drawerlayout/widget/DrawerLayout { +public final class com/facebook/react/views/drawer/ReactDrawerLayout : androidx/drawerlayout/widget/DrawerLayout, com/facebook/react/uimanager/HasChildPressedStateDelay { public fun (Lcom/facebook/react/bridge/ReactContext;)V + public fun getHasChildPressedStateDelay ()Ljava/lang/Boolean; public fun onInterceptTouchEvent (Landroid/view/MotionEvent;)Z public fun onTouchEvent (Landroid/view/MotionEvent;)Z + public fun setHasChildPressedStateDelay (Ljava/lang/Boolean;)V + public fun shouldDelayChildPressedState ()Z } public final class com/facebook/react/views/drawer/ReactDrawerLayoutManager : com/facebook/react/uimanager/ViewGroupManager, com/facebook/react/viewmanagers/AndroidDrawerLayoutManagerInterface { @@ -5450,7 +5458,7 @@ public final class com/facebook/react/views/scroll/ReactHorizontalScrollContaine public final class com/facebook/react/views/scroll/ReactHorizontalScrollContainerViewManager$Companion { } -public class com/facebook/react/views/scroll/ReactHorizontalScrollView : android/widget/HorizontalScrollView, android/view/View$OnLayoutChangeListener, android/view/ViewGroup$OnHierarchyChangeListener, com/facebook/react/uimanager/ReactClippingViewGroup, com/facebook/react/uimanager/ReactOverflowViewWithInset, com/facebook/react/views/scroll/ReactAccessibleScrollView, com/facebook/react/views/scroll/ReactScrollViewHelper$HasFlingAnimator, com/facebook/react/views/scroll/ReactScrollViewHelper$HasScrollEventThrottle, com/facebook/react/views/scroll/ReactScrollViewHelper$HasScrollState, com/facebook/react/views/scroll/ReactScrollViewHelper$HasSmoothScroll, com/facebook/react/views/scroll/ReactScrollViewHelper$HasStateWrapper, com/facebook/react/views/scroll/VirtualViewContainer { +public class com/facebook/react/views/scroll/ReactHorizontalScrollView : android/widget/HorizontalScrollView, android/view/View$OnLayoutChangeListener, android/view/ViewGroup$OnHierarchyChangeListener, com/facebook/react/uimanager/HasChildPressedStateDelay, com/facebook/react/uimanager/ReactClippingViewGroup, com/facebook/react/uimanager/ReactOverflowViewWithInset, com/facebook/react/views/scroll/ReactAccessibleScrollView, com/facebook/react/views/scroll/ReactScrollViewHelper$HasFlingAnimator, com/facebook/react/views/scroll/ReactScrollViewHelper$HasScrollEventThrottle, com/facebook/react/views/scroll/ReactScrollViewHelper$HasScrollState, com/facebook/react/views/scroll/ReactScrollViewHelper$HasSmoothScroll, com/facebook/react/views/scroll/ReactScrollViewHelper$HasStateWrapper, com/facebook/react/views/scroll/VirtualViewContainer { public fun (Landroid/content/Context;)V public fun (Landroid/content/Context;Lcom/facebook/react/views/scroll/FpsListener;)V public synthetic fun (Landroid/content/Context;Lcom/facebook/react/views/scroll/FpsListener;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -5470,6 +5478,7 @@ public class com/facebook/react/views/scroll/ReactHorizontalScrollView : android public fun getFadingEdgeLengthStart ()I public fun getFlingAnimator ()Landroid/animation/ValueAnimator; public fun getFlingExtrapolatedDistance (I)I + public fun getHasChildPressedStateDelay ()Ljava/lang/Boolean; public fun getLastScrollDispatchTime ()J protected fun getLeftFadingEdgeStrength ()F public fun getOverflow ()Ljava/lang/String; @@ -5517,6 +5526,7 @@ public class com/facebook/react/views/scroll/ReactHorizontalScrollView : android public fun setEndFillColor (I)V public fun setFadingEdgeLengthEnd (I)V public fun setFadingEdgeLengthStart (I)V + public fun setHasChildPressedStateDelay (Ljava/lang/Boolean;)V public fun setLastScrollDispatchTime (J)V public fun setOverflow (Ljava/lang/String;)V public fun setOverflowInset (IIII)V @@ -5535,6 +5545,7 @@ public class com/facebook/react/views/scroll/ReactHorizontalScrollView : android public fun setSnapToEnd (Z)V public fun setSnapToStart (Z)V public fun setStateWrapper (Lcom/facebook/react/uimanager/StateWrapper;)V + public fun shouldDelayChildPressedState ()Z public fun startFlingAnimator (II)V public fun updateClippingRect ()V public fun updateClippingRect (Ljava/util/Set;)V @@ -5597,7 +5608,7 @@ public class com/facebook/react/views/scroll/ReactHorizontalScrollViewManager : public final class com/facebook/react/views/scroll/ReactHorizontalScrollViewManager$Companion { } -public class com/facebook/react/views/scroll/ReactScrollView : android/widget/ScrollView, android/view/View$OnLayoutChangeListener, android/view/ViewGroup$OnHierarchyChangeListener, com/facebook/react/uimanager/ReactClippingViewGroup, com/facebook/react/uimanager/ReactOverflowViewWithInset, com/facebook/react/views/scroll/ReactAccessibleScrollView, com/facebook/react/views/scroll/ReactScrollViewHelper$HasFlingAnimator, com/facebook/react/views/scroll/ReactScrollViewHelper$HasScrollEventThrottle, com/facebook/react/views/scroll/ReactScrollViewHelper$HasScrollState, com/facebook/react/views/scroll/ReactScrollViewHelper$HasSmoothScroll, com/facebook/react/views/scroll/ReactScrollViewHelper$HasStateWrapper, com/facebook/react/views/scroll/VirtualViewContainer { +public class com/facebook/react/views/scroll/ReactScrollView : android/widget/ScrollView, android/view/View$OnLayoutChangeListener, android/view/ViewGroup$OnHierarchyChangeListener, com/facebook/react/uimanager/HasChildPressedStateDelay, com/facebook/react/uimanager/ReactClippingViewGroup, com/facebook/react/uimanager/ReactOverflowViewWithInset, com/facebook/react/views/scroll/ReactAccessibleScrollView, com/facebook/react/views/scroll/ReactScrollViewHelper$HasFlingAnimator, com/facebook/react/views/scroll/ReactScrollViewHelper$HasScrollEventThrottle, com/facebook/react/views/scroll/ReactScrollViewHelper$HasScrollState, com/facebook/react/views/scroll/ReactScrollViewHelper$HasSmoothScroll, com/facebook/react/views/scroll/ReactScrollViewHelper$HasStateWrapper, com/facebook/react/views/scroll/VirtualViewContainer { public fun (Landroid/content/Context;)V public fun (Landroid/content/Context;Lcom/facebook/react/views/scroll/FpsListener;)V public synthetic fun (Landroid/content/Context;Lcom/facebook/react/views/scroll/FpsListener;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -5615,6 +5626,7 @@ public class com/facebook/react/views/scroll/ReactScrollView : android/widget/Sc public fun getFadingEdgeLengthStart ()I public fun getFlingAnimator ()Landroid/animation/ValueAnimator; public fun getFlingExtrapolatedDistance (I)I + public fun getHasChildPressedStateDelay ()Ljava/lang/Boolean; public fun getLastScrollDispatchTime ()J protected fun getOverScrollerFromParent ()Landroid/widget/OverScroller; public fun getOverflow ()Ljava/lang/String; @@ -5661,6 +5673,7 @@ public class com/facebook/react/views/scroll/ReactScrollView : android/widget/Sc public fun setEndFillColor (I)V public fun setFadingEdgeLengthEnd (I)V public fun setFadingEdgeLengthStart (I)V + public fun setHasChildPressedStateDelay (Ljava/lang/Boolean;)V public fun setLastScrollDispatchTime (J)V public fun setOverflow (Ljava/lang/String;)V public fun setOverflowInset (IIII)V @@ -5681,6 +5694,7 @@ public class com/facebook/react/views/scroll/ReactScrollView : android/widget/Sc public fun setSnapToEnd (Z)V public fun setSnapToStart (Z)V public fun setStateWrapper (Lcom/facebook/react/uimanager/StateWrapper;)V + public fun shouldDelayChildPressedState ()Z public fun startFlingAnimator (II)V public fun updateClippingRect ()V public fun updateClippingRect (Ljava/util/Set;)V @@ -5949,15 +5963,18 @@ public final class com/facebook/react/views/scroll/VirtualViewContainerState$Com public final fun create (Landroid/view/ViewGroup;)Lcom/facebook/react/views/scroll/VirtualViewContainerState; } -public class com/facebook/react/views/swiperefresh/ReactSwipeRefreshLayout : androidx/swiperefreshlayout/widget/SwipeRefreshLayout { +public class com/facebook/react/views/swiperefresh/ReactSwipeRefreshLayout : androidx/swiperefreshlayout/widget/SwipeRefreshLayout, com/facebook/react/uimanager/HasChildPressedStateDelay { public fun (Lcom/facebook/react/bridge/ReactContext;)V public fun canChildScrollUp ()Z + public fun getHasChildPressedStateDelay ()Ljava/lang/Boolean; public fun onInterceptTouchEvent (Landroid/view/MotionEvent;)Z public fun onLayout (ZIIII)V public fun onTouchEvent (Landroid/view/MotionEvent;)Z public fun requestDisallowInterceptTouchEvent (Z)V + public fun setHasChildPressedStateDelay (Ljava/lang/Boolean;)V public final fun setProgressViewOffset (F)V public fun setRefreshing (Z)V + public fun shouldDelayChildPressedState ()Z } public final class com/facebook/react/views/text/DefaultStyleValuesUtil { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/HasChildPressedStateDelay.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/HasChildPressedStateDelay.kt new file mode 100644 index 00000000000..be102ecaeba --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/HasChildPressedStateDelay.kt @@ -0,0 +1,29 @@ +/* + * 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.uimanager + +/** + * Implemented by scrollable container views that allow the delaying of their children's pressed + * state (see [android.view.ViewGroup.shouldDelayChildPressedState]) to be toggled externally, + * without changing the view's default behavior. + * + * This lets a module that holds a reference to such a container disable the delay (e.g. when it + * knows the gesture will not turn into a scroll, so children should show their pressed state + * immediately) and re-enable it afterwards. + */ +public interface HasChildPressedStateDelay { + /** + * Overrides whether this view delays its children's pressed state (see + * [android.view.ViewGroup.shouldDelayChildPressedState]). + * + * When `null` (the default), the view's framework default is used. Set to `true` or `false` to + * force the behavior, and back to `null` to restore the default. Lets a module holding a + * reference to the container toggle the delay without changing the default. + */ + public var hasChildPressedStateDelay: Boolean? +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayout.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayout.kt index 2c87d640550..7523bf1fe93 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayout.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/drawer/ReactDrawerLayout.kt @@ -20,6 +20,7 @@ import com.facebook.common.logging.FLog import com.facebook.react.R import com.facebook.react.bridge.ReactContext import com.facebook.react.common.ReactConstants +import com.facebook.react.uimanager.HasChildPressedStateDelay import com.facebook.react.uimanager.ReactAccessibilityDelegate.AccessibilityRole import com.facebook.react.uimanager.events.NativeGestureUtil.notifyNativeGestureEnded import com.facebook.react.uimanager.events.NativeGestureUtil.notifyNativeGestureStarted @@ -28,11 +29,14 @@ import com.facebook.react.uimanager.events.NativeGestureUtil.notifyNativeGesture * Wrapper view for [DrawerLayout]. It manages the properties that can be set on the drawer and * contains some ReactNative-specific functionality. */ -public class ReactDrawerLayout(reactContext: ReactContext) : DrawerLayout(reactContext) { +public class ReactDrawerLayout(reactContext: ReactContext) : + DrawerLayout(reactContext), HasChildPressedStateDelay { private var drawerPosition = Gravity.START private var drawerWidth = DEFAULT_DRAWER_WIDTH private var dragging = false + override var hasChildPressedStateDelay: Boolean? = null + init { ViewCompat.setAccessibilityDelegate( this, @@ -60,6 +64,9 @@ public class ReactDrawerLayout(reactContext: ReactContext) : DrawerLayout(reactC ) } + override fun shouldDelayChildPressedState(): Boolean = + hasChildPressedStateDelay ?: super.shouldDelayChildPressedState() + override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { try { if (super.onInterceptTouchEvent(ev)) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.kt index f2b308dd88f..1e455eb2ba5 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.kt @@ -36,6 +36,7 @@ import com.facebook.react.common.ReactConstants import com.facebook.react.common.build.ReactBuildConfig import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags import com.facebook.react.uimanager.BackgroundStyleApplicator +import com.facebook.react.uimanager.HasChildPressedStateDelay import com.facebook.react.uimanager.LengthPercentage import com.facebook.react.uimanager.LengthPercentageType import com.facebook.react.uimanager.MeasureSpecAssertions @@ -84,7 +85,8 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) : HasFlingAnimator, HasScrollEventThrottle, HasSmoothScroll, - VirtualViewContainer { + VirtualViewContainer, + HasChildPressedStateDelay { private companion object { private val DEBUG_MODE = false && ReactBuildConfig.DEBUG @@ -197,6 +199,7 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) : override var stateWrapper: StateWrapper? = null override var scrollEventThrottle: Int = 0 override var lastScrollDispatchTime: Long = 0L + override var hasChildPressedStateDelay: Boolean? = null override val virtualViewContainerState: VirtualViewContainerState get() = @@ -631,6 +634,9 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) : } } + override fun shouldDelayChildPressedState(): Boolean = + hasChildPressedStateDelay ?: super.shouldDelayChildPressedState() + override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { if (!scrollEnabled) return false diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollView.kt index c8adcdfd082..0a592234d2b 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactNestedScrollView.kt @@ -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<<2b0cbc5249ac34ae7f030a9c0fffd1f3>> + * @generated SignedSource<> */ /** @@ -38,6 +38,7 @@ import com.facebook.react.bridge.ReadableMap import com.facebook.react.common.ReactConstants import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags import com.facebook.react.uimanager.BackgroundStyleApplicator +import com.facebook.react.uimanager.HasChildPressedStateDelay import com.facebook.react.uimanager.LengthPercentage import com.facebook.react.uimanager.LengthPercentageType import com.facebook.react.uimanager.MeasureSpecAssertions @@ -93,7 +94,8 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) : HasFlingAnimator, HasScrollEventThrottle, HasSmoothScroll, - VirtualViewContainer { + VirtualViewContainer, + HasChildPressedStateDelay { private companion object { private var scrollerField: java.lang.reflect.Field? = null @@ -107,6 +109,7 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) : override var stateWrapper: StateWrapper? = null override var scrollEventThrottle: Int = 0 override var lastScrollDispatchTime: Long = 0L + override var hasChildPressedStateDelay: Boolean? = null public open var pointerEvents: PointerEvents = PointerEvents.AUTO @@ -552,6 +555,9 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) : } } + override fun shouldDelayChildPressedState(): Boolean = + hasChildPressedStateDelay ?: super.shouldDelayChildPressedState() + override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { if (!scrollEnabled) return false if (!PointerEvents.canChildrenBeTouchTarget(pointerEvents)) return true diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.kt index bd32aba8da9..691a57cbc33 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.kt @@ -30,6 +30,7 @@ import com.facebook.react.bridge.ReadableMap import com.facebook.react.common.ReactConstants import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags import com.facebook.react.uimanager.BackgroundStyleApplicator +import com.facebook.react.uimanager.HasChildPressedStateDelay import com.facebook.react.uimanager.LengthPercentage import com.facebook.react.uimanager.LengthPercentageType import com.facebook.react.uimanager.MeasureSpecAssertions @@ -85,7 +86,8 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) : HasFlingAnimator, HasScrollEventThrottle, HasSmoothScroll, - VirtualViewContainer { + VirtualViewContainer, + HasChildPressedStateDelay { private companion object { private var scrollerField: java.lang.reflect.Field? = null @@ -99,6 +101,7 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) : override var stateWrapper: StateWrapper? = null override var scrollEventThrottle: Int = 0 override var lastScrollDispatchTime: Long = 0L + override var hasChildPressedStateDelay: Boolean? = null public open var pointerEvents: PointerEvents = PointerEvents.AUTO @@ -544,6 +547,9 @@ constructor(context: Context, private val fpsListener: FpsListener? = null) : } } + override fun shouldDelayChildPressedState(): Boolean = + hasChildPressedStateDelay ?: super.shouldDelayChildPressedState() + override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { if (!scrollEnabled) return false if (!PointerEvents.canChildrenBeTouchTarget(pointerEvents)) return true diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/ReactSwipeRefreshLayout.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/ReactSwipeRefreshLayout.kt index 01431e9b685..d2c6fc8d6d9 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/ReactSwipeRefreshLayout.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/swiperefresh/ReactSwipeRefreshLayout.kt @@ -12,13 +12,14 @@ import android.view.ViewConfiguration import android.view.ViewGroup import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.facebook.react.bridge.ReactContext +import com.facebook.react.uimanager.HasChildPressedStateDelay import com.facebook.react.uimanager.PixelUtil import com.facebook.react.uimanager.events.NativeGestureUtil import kotlin.math.abs /** Basic extension of [SwipeRefreshLayout] with ReactNative-specific functionality. */ public open class ReactSwipeRefreshLayout(reactContext: ReactContext) : - SwipeRefreshLayout(reactContext) { + SwipeRefreshLayout(reactContext), HasChildPressedStateDelay { private var didLayout: Boolean = false private var refreshing: Boolean = false @@ -28,6 +29,8 @@ public open class ReactSwipeRefreshLayout(reactContext: ReactContext) : private var intercepted: Boolean = false private var nativeGestureStarted: Boolean = false + override var hasChildPressedStateDelay: Boolean? = null + public override fun setRefreshing(refreshing: Boolean) { this.refreshing = refreshing @@ -79,6 +82,9 @@ public open class ReactSwipeRefreshLayout(reactContext: ReactContext) : parent?.requestDisallowInterceptTouchEvent(disallowIntercept) } + override fun shouldDelayChildPressedState(): Boolean = + hasChildPressedStateDelay ?: super.shouldDelayChildPressedState() + public override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { if (shouldInterceptTouchEvent(ev) && super.onInterceptTouchEvent(ev)) { NativeGestureUtil.notifyNativeGestureStarted(this, ev)