Skip to content

Commit 5d01c54

Browse files
zeyapfacebook-github-bot
authored andcommitted
Add responderIgnoreScroll prop on ScrollView
Summary: ## Changelog: [Android] [Changed] - Add responderIgnoreScroll prop on ScrollView When it's set to true (default), emit touchcancel from native Android ScrollView, instead of letting Responder System terminate responder at scroll. When false, `onTouchCancel` on ScrollView children will not be invoked, but `onTouchEnd` will be invoked (if touch starts on it) - which aligns with iOS. Allow opting in this new behavior at component level because (1) touchCancel is meaningful especially on android, and dev may be using onTouchCancel handler, if we enable this everywhere the handler is broken, (2) there's likely some issue in responder system when transferring js responder Differential Revision: D82761242
1 parent 4e595b7 commit 5d01c54

File tree

11 files changed

+82
-1
lines changed

11 files changed

+82
-1
lines changed

packages/react-native/Libraries/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = {
5959
process: require('../../StyleSheet/processColor').default,
6060
},
6161
pointerEvents: true,
62+
responderIgnoreScroll: true,
6263
},
6364
};
6465

packages/react-native/Libraries/Components/ScrollView/ScrollView.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,19 @@ export interface ScrollViewPropsAndroid {
586586
* Causes the scrollbars not to turn transparent when they are not in use. The default value is false.
587587
*/
588588
persistentScrollbar?: boolean | undefined;
589+
590+
/**
591+
* Emit touchcancel from native Android ScrollView, instead of letting Responder System
592+
* terminate responder at scroll.
593+
*
594+
* When it's set to false, `onTouchCancel` on ScrollView children will not be invoked, but
595+
* `onTouchEnd` will be invoked (if touch starts on it) - which aligns with iOS.
596+
*
597+
* The default value is true.
598+
*
599+
* @platform android
600+
*/
601+
responderIgnoreScroll?: boolean | undefined;
589602
}
590603

591604
export interface ScrollViewProps

packages/react-native/Libraries/Components/ScrollView/ScrollView.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,19 @@ export type ScrollViewPropsAndroid = $ReadOnly<{
388388
* @platform android
389389
*/
390390
fadingEdgeLength?: ?number | {start: number, end: number},
391+
392+
/**
393+
* Emit touchcancel from native Android ScrollView, instead of letting Responder System
394+
* terminate responder at scroll.
395+
*
396+
* When it's set to false, `onTouchCancel` on ScrollView children will not be invoked, but
397+
* `onTouchEnd` will be invoked (if touch starts on it) - which aligns with iOS.
398+
*
399+
* The default value is true.
400+
*
401+
* @platform android
402+
*/
403+
responderIgnoreScroll?: ?boolean,
391404
}>;
392405

393406
type StickyHeaderComponentType = component(

packages/react-native/Libraries/Components/ScrollView/ScrollViewNativeComponent.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig =
8888
},
8989
pointerEvents: true,
9090
isInvertedVirtualizedList: true,
91+
responderIgnoreScroll: true,
9192
},
9293
}
9394
: {

packages/react-native/Libraries/Components/ScrollView/ScrollViewNativeComponentType.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export type ScrollViewNativeProps = $ReadOnly<{
6363
pagingEnabled?: ?boolean,
6464
persistentScrollbar?: ?boolean,
6565
pinchGestureEnabled?: ?boolean,
66+
responderIgnoreScroll?: ?boolean,
6667
scrollEnabled?: ?boolean,
6768
scrollEventThrottle?: ?number,
6869
scrollIndicatorInsets?: ?EdgeInsetsProp,

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
133133
private @Nullable MaintainVisibleScrollPositionHelper mMaintainVisibleContentPositionHelper;
134134
private int mFadingEdgeLengthStart = 0;
135135
private int mFadingEdgeLengthEnd = 0;
136+
private boolean mResponderIgnoreScroll = true;
136137

137138
public ReactHorizontalScrollView(Context context) {
138139
this(context, null);
@@ -196,6 +197,7 @@ private void initView() {
196197
mMaintainVisibleContentPositionHelper = null;
197198
mFadingEdgeLengthStart = 0;
198199
mFadingEdgeLengthEnd = 0;
200+
mResponderIgnoreScroll = true;
199201
}
200202

201203
/* package */ void recycleView() {
@@ -1722,4 +1724,12 @@ public void setLastScrollDispatchTime(long lastScrollDispatchTime) {
17221724
public long getLastScrollDispatchTime() {
17231725
return mLastScrollDispatchTime;
17241726
}
1727+
1728+
public void setResponderIgnoreScroll(boolean responderIgnoreScroll) {
1729+
mResponderIgnoreScroll = responderIgnoreScroll;
1730+
}
1731+
1732+
public boolean getResponderIgnoreScroll() {
1733+
return mResponderIgnoreScroll;
1734+
}
17251735
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,14 @@ constructor(private val fpsListener: FpsListener? = null) :
413413
// Do Nothing: Align with static ViewConfigs
414414
}
415415

416+
@ReactProp(name = "responderIgnoreScroll")
417+
public fun setResponderIgnoreScroll(
418+
view: ReactHorizontalScrollView,
419+
responderIgnoreScroll: Boolean,
420+
) {
421+
view.responderIgnoreScroll = responderIgnoreScroll
422+
}
423+
416424
public companion object {
417425
public const val REACT_CLASS: String = "AndroidHorizontalScrollView"
418426
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ public class ReactScrollView extends ScrollView
131131
private @Nullable MaintainVisibleScrollPositionHelper mMaintainVisibleContentPositionHelper;
132132
private int mFadingEdgeLengthStart;
133133
private int mFadingEdgeLengthEnd;
134+
private boolean mResponderIgnoreScroll;
134135

135136
public ReactScrollView(Context context) {
136137
this(context, null);
@@ -193,6 +194,7 @@ private void initView() {
193194
mMaintainVisibleContentPositionHelper = null;
194195
mFadingEdgeLengthStart = 0;
195196
mFadingEdgeLengthEnd = 0;
197+
mResponderIgnoreScroll = true;
196198
}
197199

198200
/* package */ void recycleView() {
@@ -1527,4 +1529,12 @@ public void setLastScrollDispatchTime(long lastScrollDispatchTime) {
15271529
public long getLastScrollDispatchTime() {
15281530
return mLastScrollDispatchTime;
15291531
}
1532+
1533+
public void setResponderIgnoreScroll(boolean responderIgnoreScroll) {
1534+
mResponderIgnoreScroll = responderIgnoreScroll;
1535+
}
1536+
1537+
public boolean getResponderIgnoreScroll() {
1538+
return mResponderIgnoreScroll;
1539+
}
15301540
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,11 @@ constructor(private val fpsListener: FpsListener? = null) :
428428
}
429429
}
430430

431+
@ReactProp(name = "responderIgnoreScroll")
432+
public fun setResponderIgnoreScroll(view: ReactScrollView, responderIgnoreScroll: Boolean) {
433+
view.responderIgnoreScroll = responderIgnoreScroll
434+
}
435+
431436
public companion object {
432437
public const val REACT_CLASS: String = "RCTScrollView"
433438

packages/react-native/ReactCommon/react/renderer/components/scrollview/platform/android/react/renderer/components/scrollview/HostPlatformScrollViewProps.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@ HostPlatformScrollViewProps::HostPlatformScrollViewProps(
3838
rawProps,
3939
"nestedScrollEnabled",
4040
sourceProps.nestedScrollEnabled,
41+
true)),
42+
responderIgnoreScroll(
43+
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
44+
? sourceProps.responderIgnoreScroll
45+
: convertRawProp(
46+
context,
47+
rawProps,
48+
"responderIgnoreScroll",
49+
sourceProps.responderIgnoreScroll,
4150
true))
4251

4352
{}
@@ -57,6 +66,7 @@ void HostPlatformScrollViewProps::setProp(
5766
switch (hash) {
5867
RAW_SET_PROP_SWITCH_CASE_BASIC(sendMomentumEvents);
5968
RAW_SET_PROP_SWITCH_CASE_BASIC(nestedScrollEnabled);
69+
RAW_SET_PROP_SWITCH_CASE_BASIC(responderIgnoreScroll);
6070
}
6171
}
6272

@@ -76,7 +86,11 @@ SharedDebugStringConvertibleList HostPlatformScrollViewProps::getDebugProps()
7686
debugStringConvertibleItem(
7787
"nestedScrollEnabled",
7888
nestedScrollEnabled,
79-
defaultScrollViewProps.nestedScrollEnabled)};
89+
defaultScrollViewProps.nestedScrollEnabled),
90+
debugStringConvertibleItem(
91+
"responderIgnoreScroll",
92+
responderIgnoreScroll,
93+
defaultScrollViewProps.responderIgnoreScroll)};
8094
}
8195
#endif
8296

@@ -348,6 +362,10 @@ folly::dynamic HostPlatformScrollViewProps::getDiffProps(
348362
result["nestedScrollEnabled"] = nestedScrollEnabled;
349363
}
350364

365+
if (responderIgnoreScroll != oldProps->responderIgnoreScroll) {
366+
result["responderIgnoreScroll"] = responderIgnoreScroll;
367+
}
368+
351369
return result;
352370
}
353371

0 commit comments

Comments
 (0)