Skip to content

Commit 22e7794

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 22e7794

File tree

7 files changed

+54
-1
lines changed

7 files changed

+54
-1
lines changed

Libraries/Components/ScrollView/ScrollView.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,7 @@ class ScrollView extends React.Component<Props, State> {
17581758
: this.props.removeClippedSubviews
17591759
}
17601760
key={this.state.contentKey} // TODO(macOS GH#774)
1761+
inverted={this.props.inverted} // TODO(macOS GH#774)
17611762
collapsable={false}
17621763
>
17631764
{children}

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: 12 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)
@@ -106,6 +107,11 @@ + (BOOL)isCompatibleWithResponsiveScrolling
106107
return YES;
107108
}
108109

110+
- (BOOL)isFlipped
111+
{
112+
return !self.inverted;
113+
}
114+
109115
- (void)scrollWheel:(NSEvent *)theEvent
110116
{
111117
if (!self.scrollEnabled) {
@@ -549,6 +555,12 @@ - (void)setAccessibilityLabel:(NSString *)accessibilityLabel
549555
{
550556
[_scrollView setAccessibilityLabel:accessibilityLabel];
551557
}
558+
559+
- (void)setInverted:(BOOL)inverted
560+
{
561+
_inverted = inverted;
562+
_scrollView.inverted = inverted;
563+
}
552564
#endif // ]TODO(macOS GH#774)
553565

554566
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)