Skip to content

Commit 90186cd

Browse files
hannojgfacebook-github-bot
authored andcommitted
Add workaround for android API 33 ANR when inverting ScrollView (#37913)
Summary: As explained in this issue: - #35350 starting from android API 33 there are severe performance issues when using `scaleY: -1` on a view, and its child view, which is what we are doing when inverting the `ScrollView` component (e.g. in `FlatList`). This PR adds a workaround. The workaround is to also scale on the X-Axis which causes a different transform matrix to be created, that doesn't cause the ANR (see the issue for details). However, when doing that the vertical scroll bar will be on the wrong side, thus we switch the position in the native code once we detect that the list is inverted. The goal of this PR is that react-native users can just use `<FlatList inverted={true} />` without running into any ANRs or the need to apply manual hot fixes 😄 ## Changelog: <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: [ANDROID] [FIXED] - ANR when having an inverted `FlatList` on android API 33+ For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> [ANDROID] [FIXED] - ANR when having an inverted `FlatList` on android API 33+ Pull Request resolved: #37913 Test Plan: - The change is minimal, and only affects android. - Run the RNTesterApp for android and confirm that in the flatlist example the inverted list is still working as expected. Reviewed By: rozele Differential Revision: D46871197 Pulled By: NickGerleman fbshipit-source-id: 872a2ce5313f16998f0e4d2804d61e4d8dca7bfd
1 parent 74e6c95 commit 90186cd

File tree

4 files changed

+42
-3
lines changed

4 files changed

+42
-3
lines changed

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,4 +379,22 @@ public void setPointerEvents(ReactScrollView view, @Nullable String pointerEvent
379379
public void setScrollEventThrottle(ReactScrollView view, int scrollEventThrottle) {
380380
view.setScrollEventThrottle(scrollEventThrottle);
381381
}
382+
383+
@ReactProp(name = "inverted")
384+
public void setInverted(ReactScrollView view, boolean inverted) {
385+
// Usually when inverting the scroll view we are using scaleY: -1 on the list
386+
// and on the parent container. HOWEVER, starting from android API 33 there is
387+
// a bug that can cause an ANR due to that. Thus we are using different transform
388+
// commands to circumvent the ANR. This however causes the vertical scrollbar to
389+
// be on the wrong side. Thus we are moving it to the other side, when the list
390+
// is inverted.
391+
// See also:
392+
// - https://github.com/facebook/react-native/issues/35350
393+
// - https://issuetracker.google.com/issues/287304310
394+
if (inverted) {
395+
view.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_LEFT);
396+
} else {
397+
view.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_DEFAULT);
398+
}
399+
}
382400
}

packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,15 @@ ScrollViewProps::ScrollViewProps(
319319
rawProps,
320320
"scrollToOverflowEnabled",
321321
sourceProps.scrollToOverflowEnabled,
322-
{})) {}
322+
{})),
323+
inverted(
324+
CoreFeatures::enablePropIteratorSetter ? sourceProps.inverted
325+
: convertRawProp(
326+
context,
327+
rawProps,
328+
"inverted",
329+
sourceProps.inverted,
330+
{})) {}
323331

324332
void ScrollViewProps::setProp(
325333
const PropsParserContext &context,
@@ -368,6 +376,7 @@ void ScrollViewProps::setProp(
368376
RAW_SET_PROP_SWITCH_CASE_BASIC(snapToEnd);
369377
RAW_SET_PROP_SWITCH_CASE_BASIC(contentInsetAdjustmentBehavior);
370378
RAW_SET_PROP_SWITCH_CASE_BASIC(scrollToOverflowEnabled);
379+
RAW_SET_PROP_SWITCH_CASE_BASIC(inverted);
371380
}
372381
}
373382

@@ -492,7 +501,9 @@ SharedDebugStringConvertibleList ScrollViewProps::getDebugProps() const {
492501
debugStringConvertibleItem(
493502
"snapToStart", snapToStart, defaultScrollViewProps.snapToStart),
494503
debugStringConvertibleItem(
495-
"snapToEnd", snapToEnd, defaultScrollViewProps.snapToEnd)};
504+
"snapToEnd", snapToEnd, defaultScrollViewProps.snapToEnd),
505+
debugStringConvertibleItem(
506+
"inverted", inverted, defaultScrollViewProps.inverted)};
496507
}
497508
#endif
498509

packages/react-native/ReactCommon/react/renderer/components/scrollview/ScrollViewProps.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class ScrollViewProps final : public ViewProps {
6868
ContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior{
6969
ContentInsetAdjustmentBehavior::Never};
7070
bool scrollToOverflowEnabled{false};
71+
bool inverted{false};
7172

7273
#pragma mark - DebugStringConvertible
7374

packages/virtualized-lists/Lists/VirtualizedList.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type {
1414
LayoutEvent,
1515
ScrollEvent,
1616
} from 'react-native/Libraries/Types/CoreEventTypes';
17+
import Platform from 'react-native/Libraries/Utilities/Platform';
1718
import type {ViewToken} from './ViewabilityHelper';
1819
import type {
1920
Item,
@@ -1969,7 +1970,15 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
19691970

19701971
const styles = StyleSheet.create({
19711972
verticallyInverted: {
1972-
transform: [{scaleY: -1}],
1973+
transform:
1974+
// Android 13 Bug Workaround:
1975+
// On Android, we need to invert both axes to mitigate a native bug
1976+
// that could lead to ANRs.
1977+
// Simply using scaleY: -1 leads to the application of scaleY and
1978+
// rotationX natively, resulting in the ANR.
1979+
// For more information, refer to the following Android tracking issue:
1980+
// https://issuetracker.google.com/issues/287304310
1981+
Platform.OS === 'android' ? [{scale: -1}] : [{scaleY: -1}],
19731982
},
19741983
horizontallyInverted: {
19751984
transform: [{scaleX: -1}],

0 commit comments

Comments
 (0)