Skip to content

Commit 9a6231a

Browse files
appdenchristophpurrer
authored andcommitted
Support inverted ScrollView on macOS
Allow to render a scrollView's content in inverted order which is especially helpful in messaging applications. We can't rely on -1 scale hacks on macOS because of inverse issues with trackpad/scrollwheel, dragging scrollbars, tracking hovers, etc. Hence we added 'native' support for inverted views
1 parent 84c0863 commit 9a6231a

File tree

8 files changed

+53
-2
lines changed

8 files changed

+53
-2
lines changed

Libraries/Components/ScrollView/ScrollView.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,10 @@ export type Props = $ReadOnly<{|
499499
* ScrollView. This is usually used with inverted ScrollViews.
500500
*/
501501
invertStickyHeaders?: ?boolean,
502+
/**
503+
* Reverses the direction of scroll. Uses native inversion on macOS and scale transforms of -1 elsewhere
504+
*/
505+
inverted?: ?boolean,
502506
/**
503507
* Determines whether the keyboard gets dismissed in response to a drag.
504508
*
@@ -1758,6 +1762,7 @@ class ScrollView extends React.Component<Props, State> {
17581762
: this.props.removeClippedSubviews
17591763
}
17601764
key={this.state.contentKey} // TODO(macOS GH#774)
1765+
inverted={this.props.inverted} // TODO(macOS GH#774)
17611766
collapsable={false}
17621767
>
17631768
{children}

Libraries/Lists/FlatList.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ type OptionalProps<ItemT> = {|
112112
*/
113113
initialScrollIndex?: ?number,
114114
/**
115-
* Reverses the direction of scroll. Uses scale transforms of -1.
115+
* Reverses the direction of scroll. Uses native inversion on macOS and scale transforms of -1 elsewhere
116116
*/
117117
inverted?: ?boolean,
118118
/**

Libraries/Lists/VirtualizedList.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -960,7 +960,8 @@ class VirtualizedList extends React.PureComponent<Props, State> {
960960
} = this.props;
961961
const {data, horizontal} = this.props;
962962
const isVirtualizationDisabled = this._isVirtualizationDisabled();
963-
const inversionStyle = this.props.inverted
963+
// macOS natively supports inverted lists, thus not needing an inversion style
964+
const inversionStyle = this.props.inverted && Platform.OS !== 'macos' // TODO(macOS GH#774)
964965
? horizontalOrDefault(this.props.horizontal)
965966
? styles.horizontallyInverted
966967
: styles.verticallyInverted

React/Views/ScrollView/RCTScrollContentView.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,8 @@
1111

1212
@interface RCTScrollContentView : RCTView
1313

14+
#if TARGET_OS_OSX // [TODO(macOS GH#774)
15+
@property (nonatomic, assign, getter=isInverted) BOOL inverted;
16+
#endif // ]TODO(macOS GH#774)
17+
1418
@end

React/Views/ScrollView/RCTScrollContentView.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
#import "RCTScrollView.h"
1919

2020
@implementation RCTScrollContentView
21+
#if TARGET_OS_OSX // TODO(macOS GH#774)
22+
- (BOOL)isFlipped
23+
{
24+
return !self.inverted;
25+
}
26+
#endif // ]TODO(macOS GH#774)
2127

2228
- (void)reactSetFrame:(CGRect)frame
2329
{

React/Views/ScrollView/RCTScrollContentViewManager.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ @implementation RCTScrollContentViewManager
1414

1515
RCT_EXPORT_MODULE()
1616

17+
RCT_EXPORT_OSX_VIEW_PROPERTY(inverted, BOOL) // TODO(macOS GH#774)
18+
1719
- (RCTScrollContentView *)view
1820
{
1921
return [RCTScrollContentView new];

React/Views/ScrollView/RCTScrollView.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ @interface RCTCustomScrollView :
4343
@property (nonatomic, assign) BOOL pinchGestureEnabled;
4444
#else // [TODO(macOS GH#774)
4545
+ (BOOL)isCompatibleWithResponsiveScrolling;
46+
@property (nonatomic, assign, getter=isInverted) BOOL inverted;
4647
@property (nonatomic, assign, getter=isScrollEnabled) BOOL scrollEnabled;
4748
@property (nonatomic, strong) NSPanGestureRecognizer *panGestureRecognizer;
4849
#endif // ]TODO(macOS GH#774)
@@ -549,6 +550,11 @@ - (void)setAccessibilityLabel:(NSString *)accessibilityLabel
549550
{
550551
[_scrollView setAccessibilityLabel:accessibilityLabel];
551552
}
553+
554+
- (void)setInverted:(BOOL)inverted
555+
{
556+
_inverted = inverted;
557+
}
552558
#endif // ]TODO(macOS GH#774)
553559

554560
RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)

packages/rn-tester/js/examples/ScrollView/ScrollViewExample.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,19 @@ const examples = ([
270270
},
271271
]: Array<RNTesterModuleExample>);
272272

273+
// TODO [(macOS GH#774)
274+
if (Platform.OS === 'macos') {
275+
examples.push({
276+
title: '<ScrollView> (inverted = true)\n',
277+
description:
278+
"You can display <ScrollView>'s child components in inverted order",
279+
render: function (): React.Node {
280+
return <InvertedContentExample />;
281+
},
282+
});
283+
}
284+
// ]TODO(macOS GH#774)
285+
273286
if (Platform.OS === 'ios') {
274287
examples.push({
275288
title: '<ScrollView> smooth bi-directional content loading\n',
@@ -548,6 +561,20 @@ const HorizontalScrollView = (props: {direction: 'ltr' | 'rtl'}) => {
548561
);
549562
};
550563

564+
const InvertedContentExample = () => {
565+
return (
566+
<View>
567+
<ScrollView
568+
style={[styles.scrollView, {height: 200}]}
569+
contentOffset={{x: 100, y: 0}}
570+
inverted={true}
571+
nestedScrollEnabled>
572+
{ITEMS.map(createItemRow)}
573+
</ScrollView>
574+
</View>
575+
);
576+
};
577+
551578
const EndFillColorFadingEdgeLen = () => {
552579
const [endFillColor, setEndFillColor] = useState('');
553580
const [fadingEdgeLen, setFadingEdgeLen] = useState(0);

0 commit comments

Comments
 (0)