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 @@ -59,6 +59,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = {
process: require('../../StyleSheet/processColor').default,
},
pointerEvents: true,
responderIgnoreScroll: true,
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,19 @@ export interface ScrollViewPropsAndroid {
* Causes the scrollbars not to turn transparent when they are not in use. The default value is false.
*/
persistentScrollbar?: boolean | undefined;

/**
* Emit touchcancel from native Android ScrollView, instead of letting Responder System
* terminate responder at scroll.
*
* When it's set to false, `onTouchCancel` on ScrollView children will not be invoked, but
* `onTouchEnd` will be invoked (if touch starts on it) - which aligns with iOS.
*
* The default value is true.
*
* @platform android
*/
responderIgnoreScroll?: boolean | undefined;
}

export interface ScrollViewProps
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,19 @@ export type ScrollViewPropsAndroid = $ReadOnly<{
* @platform android
*/
fadingEdgeLength?: ?number | {start: number, end: number},

/**
* Emit touchcancel from native Android ScrollView, instead of letting Responder System
* terminate responder at scroll.
*
* When it's set to false, `onTouchCancel` on ScrollView children will not be invoked, but
* `onTouchEnd` will be invoked (if touch starts on it) - which aligns with iOS.
*
* The default value is true.
*
* @platform android
*/
responderIgnoreScroll?: ?boolean,
}>;

type StickyHeaderComponentType = component(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
},
pointerEvents: true,
isInvertedVirtualizedList: true,
responderIgnoreScroll: true,
},
}
: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export type ScrollViewNativeProps = $ReadOnly<{
pagingEnabled?: ?boolean,
persistentScrollbar?: ?boolean,
pinchGestureEnabled?: ?boolean,
responderIgnoreScroll?: ?boolean,
scrollEnabled?: ?boolean,
scrollEventThrottle?: ?number,
scrollIndicatorInsets?: ?EdgeInsetsProp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
private @Nullable MaintainVisibleScrollPositionHelper mMaintainVisibleContentPositionHelper;
private int mFadingEdgeLengthStart = 0;
private int mFadingEdgeLengthEnd = 0;
private boolean mResponderIgnoreScroll = true;

public ReactHorizontalScrollView(Context context) {
this(context, null);
Expand Down Expand Up @@ -196,6 +197,7 @@ private void initView() {
mMaintainVisibleContentPositionHelper = null;
mFadingEdgeLengthStart = 0;
mFadingEdgeLengthEnd = 0;
mResponderIgnoreScroll = true;
}

/* package */ void recycleView() {
Expand Down Expand Up @@ -710,7 +712,9 @@ && findDeepestScrollViewForMotionEvent(this, ev) != null) {
}

protected void handleInterceptedTouchEvent(MotionEvent ev) {
NativeGestureUtil.notifyNativeGestureStarted(this, ev);
if (mResponderIgnoreScroll) {
NativeGestureUtil.notifyNativeGestureStarted(this, ev);
}
ReactScrollViewHelper.emitScrollBeginDragEvent(this);
mDragging = true;
enableFpsListener();
Expand Down Expand Up @@ -778,7 +782,9 @@ public boolean onTouchEvent(MotionEvent ev) {
float velocityX = mVelocityHelper.getXVelocity();
float velocityY = mVelocityHelper.getYVelocity();
ReactScrollViewHelper.emitScrollEndDragEvent(this, velocityX, velocityY);
NativeGestureUtil.notifyNativeGestureEnded(this, ev);
if (mResponderIgnoreScroll) {
NativeGestureUtil.notifyNativeGestureEnded(this, ev);
}
mDragging = false;
// After the touch finishes, we may need to do some scrolling afterwards either as a result
// of a fling or because we need to page align the content
Expand Down Expand Up @@ -1722,4 +1728,12 @@ public void setLastScrollDispatchTime(long lastScrollDispatchTime) {
public long getLastScrollDispatchTime() {
return mLastScrollDispatchTime;
}

public void setResponderIgnoreScroll(boolean responderIgnoreScroll) {
mResponderIgnoreScroll = responderIgnoreScroll;
}

public boolean getResponderIgnoreScroll() {
return mResponderIgnoreScroll;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,14 @@ constructor(private val fpsListener: FpsListener? = null) :
// Do Nothing: Align with static ViewConfigs
}

@ReactProp(name = "responderIgnoreScroll")
public fun setResponderIgnoreScroll(
view: ReactHorizontalScrollView,
responderIgnoreScroll: Boolean,
) {
view.responderIgnoreScroll = responderIgnoreScroll
}

public companion object {
public const val REACT_CLASS: String = "AndroidHorizontalScrollView"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ public class ReactScrollView extends ScrollView
private @Nullable MaintainVisibleScrollPositionHelper mMaintainVisibleContentPositionHelper;
private int mFadingEdgeLengthStart;
private int mFadingEdgeLengthEnd;
private boolean mResponderIgnoreScroll;

public ReactScrollView(Context context) {
this(context, null);
Expand Down Expand Up @@ -193,6 +194,7 @@ private void initView() {
mMaintainVisibleContentPositionHelper = null;
mFadingEdgeLengthStart = 0;
mFadingEdgeLengthEnd = 0;
mResponderIgnoreScroll = true;
}

/* package */ void recycleView() {
Expand Down Expand Up @@ -593,7 +595,9 @@ public boolean onInterceptTouchEvent(MotionEvent ev) {
}

protected void handleInterceptedTouchEvent(MotionEvent ev) {
NativeGestureUtil.notifyNativeGestureStarted(this, ev);
if (mResponderIgnoreScroll) {
NativeGestureUtil.notifyNativeGestureStarted(this, ev);
}
ReactScrollViewHelper.emitScrollBeginDragEvent(this);
mDragging = true;
enableFpsListener();
Expand All @@ -619,7 +623,9 @@ public boolean onTouchEvent(MotionEvent ev) {
float velocityX = mVelocityHelper.getXVelocity();
float velocityY = mVelocityHelper.getYVelocity();
ReactScrollViewHelper.emitScrollEndDragEvent(this, velocityX, velocityY);
NativeGestureUtil.notifyNativeGestureEnded(this, ev);
if (mResponderIgnoreScroll) {
NativeGestureUtil.notifyNativeGestureEnded(this, ev);
}
mDragging = false;
// After the touch finishes, we may need to do some scrolling afterwards either as a result
// of a fling or because we need to page align the content
Expand Down Expand Up @@ -1527,4 +1533,12 @@ public void setLastScrollDispatchTime(long lastScrollDispatchTime) {
public long getLastScrollDispatchTime() {
return mLastScrollDispatchTime;
}

public void setResponderIgnoreScroll(boolean responderIgnoreScroll) {
mResponderIgnoreScroll = responderIgnoreScroll;
}

public boolean getResponderIgnoreScroll() {
return mResponderIgnoreScroll;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ public object ReactScrollViewHelper {
contentView.height,
scrollView.width,
scrollView.height,
if (scrollView is ReactScrollView)
(scrollView as ReactScrollView).responderIgnoreScroll
else if (scrollView is ReactHorizontalScrollView)
(scrollView as ReactHorizontalScrollView).responderIgnoreScroll
else true,
)
)
if (scrollEventType == ScrollEventType.SCROLL) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,11 @@ constructor(private val fpsListener: FpsListener? = null) :
}
}

@ReactProp(name = "responderIgnoreScroll")
public fun setResponderIgnoreScroll(view: ReactScrollView, responderIgnoreScroll: Boolean) {
view.responderIgnoreScroll = responderIgnoreScroll
}

public companion object {
public const val REACT_CLASS: String = "RCTScrollView"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class ScrollEvent private constructor() : Event<ScrollEvent>() {
private var scrollViewHeight = 0
private var scrollEventType: ScrollEventType? = null
private var timestamp: Long = 0
private var responderIgnoreScroll: Boolean = true

override fun onDispose() {
try {
Expand All @@ -53,6 +54,7 @@ public class ScrollEvent private constructor() : Event<ScrollEvent>() {
contentHeight: Int,
scrollViewWidth: Int,
scrollViewHeight: Int,
responderIgnoreScroll: Boolean,
) {
val timestampMs = SystemClock.uptimeMillis()
super.init(surfaceId, viewTag, timestampMs)
Expand All @@ -67,6 +69,7 @@ public class ScrollEvent private constructor() : Event<ScrollEvent>() {
this.scrollViewWidth = scrollViewWidth
this.scrollViewHeight = scrollViewHeight
this.timestamp = timestampMs
this.responderIgnoreScroll = responderIgnoreScroll
}

override fun getEventName(): String =
Expand Down Expand Up @@ -110,7 +113,7 @@ public class ScrollEvent private constructor() : Event<ScrollEvent>() {
event.putMap("velocity", velocity)
event.putInt("target", viewTag)
event.putDouble("timestamp", timestamp.toDouble())
event.putBoolean("responderIgnoreScroll", true)
event.putBoolean("responderIgnoreScroll", responderIgnoreScroll)
return event
}

Expand All @@ -131,6 +134,7 @@ public class ScrollEvent private constructor() : Event<ScrollEvent>() {
contentHeight: Int,
scrollViewWidth: Int,
scrollViewHeight: Int,
responderIgnoreScroll: Boolean,
): ScrollEvent =
(EVENTS_POOL.acquire() ?: ScrollEvent()).apply {
init(
Expand All @@ -145,13 +149,14 @@ public class ScrollEvent private constructor() : Event<ScrollEvent>() {
contentHeight,
scrollViewWidth,
scrollViewHeight,
responderIgnoreScroll,
)
}

@Deprecated(
"Use the obtain version that explicitly takes surfaceId as an argument",
ReplaceWith(
"obtain(surfaceId, viewTag, scrollEventType, scrollX, scrollY, xVelocity, yVelocity, contentWidth, contentHeight, scrollViewWidth, scrollViewHeight)"
"obtain(surfaceId, viewTag, scrollEventType, scrollX, scrollY, xVelocity, yVelocity, contentWidth, contentHeight, scrollViewWidth, scrollViewHeight, responderIgnoreScroll)"
),
)
@JvmStatic
Expand All @@ -166,6 +171,7 @@ public class ScrollEvent private constructor() : Event<ScrollEvent>() {
contentHeight: Int,
scrollViewWidth: Int,
scrollViewHeight: Int,
responderIgnoreScroll: Boolean,
): ScrollEvent =
obtain(
ViewUtil.NO_SURFACE_ID,
Expand All @@ -179,6 +185,7 @@ public class ScrollEvent private constructor() : Event<ScrollEvent>() {
contentHeight,
scrollViewWidth,
scrollViewHeight,
responderIgnoreScroll,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ internal class ReactTextScrollWatcher(private val editText: ReactEditText) : Scr
0, // can't get content height
editText.width,
editText.height,
true, // responderIgnoreScroll
)

eventDispatcher?.dispatchEvent(event)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ HostPlatformScrollViewProps::HostPlatformScrollViewProps(
rawProps,
"nestedScrollEnabled",
sourceProps.nestedScrollEnabled,
true)),
responderIgnoreScroll(
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
? sourceProps.responderIgnoreScroll
: convertRawProp(
context,
rawProps,
"responderIgnoreScroll",
sourceProps.responderIgnoreScroll,
true))

{}
Expand All @@ -57,6 +66,7 @@ void HostPlatformScrollViewProps::setProp(
switch (hash) {
RAW_SET_PROP_SWITCH_CASE_BASIC(sendMomentumEvents);
RAW_SET_PROP_SWITCH_CASE_BASIC(nestedScrollEnabled);
RAW_SET_PROP_SWITCH_CASE_BASIC(responderIgnoreScroll);
}
}

Expand All @@ -76,7 +86,11 @@ SharedDebugStringConvertibleList HostPlatformScrollViewProps::getDebugProps()
debugStringConvertibleItem(
"nestedScrollEnabled",
nestedScrollEnabled,
defaultScrollViewProps.nestedScrollEnabled)};
defaultScrollViewProps.nestedScrollEnabled),
debugStringConvertibleItem(
"responderIgnoreScroll",
responderIgnoreScroll,
defaultScrollViewProps.responderIgnoreScroll)};
}
#endif

Expand Down Expand Up @@ -348,6 +362,10 @@ folly::dynamic HostPlatformScrollViewProps::getDiffProps(
result["nestedScrollEnabled"] = nestedScrollEnabled;
}

if (responderIgnoreScroll != oldProps->responderIgnoreScroll) {
result["responderIgnoreScroll"] = responderIgnoreScroll;
}

return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class HostPlatformScrollViewProps final : public BaseScrollViewProps {

bool sendMomentumEvents{};
bool nestedScrollEnabled{};
bool responderIgnoreScroll{};

#pragma mark - DebugStringConvertible

Expand Down
Loading
Loading