Skip to content

Commit ab49cb0

Browse files
committed
Fix connection of animated nodes and scroll offset with useNativeDriver.
Add example showing regression before this fix is applied.
1 parent 2fc6888 commit ab49cb0

File tree

7 files changed

+131
-16
lines changed

7 files changed

+131
-16
lines changed

Libraries/Animated/src/NativeAnimatedHelper.js

+17
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,24 @@ type EventMapping = {
2929

3030
let nativeEventEmitter;
3131

32+
let queueConnections = false;
33+
let queue = [];
34+
3235
/**
3336
* Simple wrappers around NativeAnimatedModule to provide flow and autocmplete support for
3437
* the native module methods
3538
*/
3639
const API = {
40+
enableQueue: function(): void {
41+
queueConnections = true;
42+
},
43+
disableQueue: function(): void {
44+
queueConnections = false;
45+
while (queue.length) {
46+
const args = queue.shift();
47+
NativeAnimatedModule.connectAnimatedNodes(args[0], args[1]);
48+
}
49+
},
3750
createAnimatedNode: function(tag: ?number, config: Object): void {
3851
assertNativeAnimatedModule();
3952
NativeAnimatedModule.createAnimatedNode(tag, config);
@@ -48,6 +61,10 @@ const API = {
4861
},
4962
connectAnimatedNodes: function(parentTag: ?number, childTag: ?number): void {
5063
assertNativeAnimatedModule();
64+
if (queueConnections) {
65+
queue.push([parentTag, childTag]);
66+
return;
67+
}
5168
NativeAnimatedModule.connectAnimatedNodes(parentTag, childTag);
5269
},
5370
disconnectAnimatedNodes: function(

Libraries/Animated/src/animations/Animation.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@ class Animation {
5656
onEnd && onEnd(result);
5757
}
5858
__startNativeAnimation(animatedValue: AnimatedValue): void {
59+
NativeAnimatedHelper.API.enableQueue();
5960
animatedValue.__makeNative();
60-
animatedValue.__connectAnimatedNodes();
61+
NativeAnimatedHelper.API.disableQueue();
6162
this.__nativeId = NativeAnimatedHelper.generateNewAnimationId();
6263
NativeAnimatedHelper.API.startAnimatingNode(
6364
this.__nativeId,

Libraries/Animated/src/nodes/AnimatedNode.js

-6
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,12 @@ class AnimatedNode {
3535

3636
/* Methods and props used by native Animated impl */
3737
__isNative: boolean;
38-
__isConnected: boolean;
3938
__nativeTag: ?number;
4039
__makeNative() {
4140
if (!this.__isNative) {
4241
throw new Error('This node cannot be made a "native" animated node');
4342
}
4443
}
45-
__connectAnimatedNodes() {
46-
if (!this.__isNative) {
47-
throw new Error('This node cannot be connected natively');
48-
}
49-
}
5044
__getNativeTag(): ?number {
5145
NativeAnimatedHelper.assertNativeAnimatedModule();
5246
invariant(

Libraries/Animated/src/nodes/AnimatedWithChildren.js

-9
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,6 @@ class AnimatedWithChildren extends AnimatedNode {
2525
this.__isNative = true;
2626
for (const child of this._children) {
2727
child.__makeNative();
28-
}
29-
}
30-
}
31-
32-
__connectAnimatedNodes() {
33-
if (!this.__isConnected) {
34-
this.__isConnected = true;
35-
for (const child of this._children) {
36-
child.__connectAnimatedNodes();
3728
NativeAnimatedHelper.API.connectAnimatedNodes(
3829
this.__getNativeTag(),
3930
child.__getNativeTag(),

RNTester/js/RNTesterList.android.js

+4
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ const ComponentExamples: Array<RNTesterExample> = [
5959
key: 'ScrollViewSimpleExample',
6060
module: require('./ScrollViewSimpleExample'),
6161
},
62+
{
63+
key: 'ScrollViewAnimatedExample',
64+
module: require('./ScrollViewAnimatedExample'),
65+
},
6266
{
6367
key: 'SectionListExample',
6468
module: require('./SectionListExample'),

RNTester/js/RNTesterList.ios.js

+5
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ const ComponentExamples: Array<RNTesterExample> = [
9898
module: require('./ScrollViewSimpleExample'),
9999
supportsTVOS: true,
100100
},
101+
{
102+
key: 'ScrollViewAnimatedExample',
103+
module: require('./ScrollViewAnimatedExample'),
104+
supportsTVOS: true,
105+
},
101106
{
102107
key: 'SafeAreaViewExample',
103108
module: require('./SafeAreaViewExample'),
+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
* @flow
9+
*/
10+
11+
'use strict';
12+
13+
const React = require('react');
14+
const ReactNative = require('react-native');
15+
const {Component} = React;
16+
const {
17+
StyleSheet,
18+
Text,
19+
View,
20+
Animated,
21+
Easing,
22+
TouchableOpacity,
23+
Dimensions,
24+
} = ReactNative;
25+
26+
class ScrollViewAnimatedExample extends Component<{}> {
27+
_scrollViewPos = new Animated.Value(0);
28+
29+
startAnimation = () => {
30+
this._scrollViewPos.setValue(0);
31+
Animated.timing(this._scrollViewPos, {
32+
toValue: 100,
33+
duration: 10000,
34+
easing: Easing.linear,
35+
useNativeDriver: true,
36+
}).start();
37+
};
38+
39+
render() {
40+
const interpolated = this._scrollViewPos.interpolate({
41+
inputRange: [0, 1],
42+
outputRange: [0, 0.1],
43+
});
44+
const interpolated2 = this._scrollViewPos.interpolate({
45+
inputRange: [0, 1],
46+
outputRange: ['0deg', '1deg'],
47+
});
48+
return (
49+
<View style={styles.container}>
50+
<Animated.View
51+
style={{
52+
width: 100,
53+
height: 100,
54+
backgroundColor: 'black',
55+
transform: [{translateX: interpolated}, {rotate: interpolated2}],
56+
}}
57+
/>
58+
<Animated.ScrollView
59+
horizontal
60+
scrollEventThrottle={16}
61+
onScroll={Animated.event(
62+
[{nativeEvent: {contentOffset: {x: this._scrollViewPos}}}],
63+
{useNativeDriver: true},
64+
)}>
65+
<TouchableOpacity onPress={this.startAnimation}>
66+
<View style={styles.button}>
67+
<Text>Scroll me horizontally</Text>
68+
</View>
69+
</TouchableOpacity>
70+
</Animated.ScrollView>
71+
</View>
72+
);
73+
}
74+
}
75+
76+
const {width, height} = Dimensions.get('window');
77+
78+
const styles = StyleSheet.create({
79+
container: {
80+
flex: 1,
81+
justifyContent: 'center',
82+
alignItems: 'center',
83+
backgroundColor: '#F5FCFF',
84+
},
85+
button: {
86+
margin: 50,
87+
width: width,
88+
marginRight: width,
89+
height: height / 2,
90+
},
91+
});
92+
93+
exports.title = '<ScrollViewAnimated>';
94+
exports.description = 'Component that is animated when ScrollView is offset.';
95+
96+
exports.examples = [
97+
{
98+
title: 'Animated by scroll view',
99+
render: function(): React.Element<typeof ScrollViewAnimatedExample> {
100+
return <ScrollViewAnimatedExample />;
101+
},
102+
},
103+
];

0 commit comments

Comments
 (0)