Skip to content

Commit

Permalink
Fix connection of animated nodes and scroll offset with useNativeDriver.
Browse files Browse the repository at this point in the history
Add example showing regression before this fix is applied.
  • Loading branch information
msand committed Mar 28, 2019
1 parent 2fc6888 commit 827fc61
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 1 deletion.
17 changes: 17 additions & 0 deletions Libraries/Animated/src/NativeAnimatedHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,24 @@ type EventMapping = {

let nativeEventEmitter;

let queueConnections = false;
let queue = [];

/**
* Simple wrappers around NativeAnimatedModule to provide flow and autocmplete support for
* the native module methods
*/
const API = {
enableQueue: function(): void {
queueConnections = true;
},
disableQueue: function(): void {
queueConnections = false;
while (queue.length) {
const args = queue.shift();
NativeAnimatedModule.connectAnimatedNodes(args[0], args[1]);
}
},
createAnimatedNode: function(tag: ?number, config: Object): void {
assertNativeAnimatedModule();
NativeAnimatedModule.createAnimatedNode(tag, config);
Expand All @@ -48,6 +61,10 @@ const API = {
},
connectAnimatedNodes: function(parentTag: ?number, childTag: ?number): void {
assertNativeAnimatedModule();
if (queueConnections) {
queue.push([parentTag, childTag]);
return;
}
NativeAnimatedModule.connectAnimatedNodes(parentTag, childTag);
},
disconnectAnimatedNodes: function(
Expand Down
3 changes: 2 additions & 1 deletion Libraries/Animated/src/animations/Animation.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@ class Animation {
onEnd && onEnd(result);
}
__startNativeAnimation(animatedValue: AnimatedValue): void {
NativeAnimatedHelper.API.enableQueue();
animatedValue.__makeNative();
animatedValue.__connectAnimatedNodes();
NativeAnimatedHelper.API.disableQueue();
this.__nativeId = NativeAnimatedHelper.generateNewAnimationId();
NativeAnimatedHelper.API.startAnimatingNode(
this.__nativeId,
Expand Down
4 changes: 4 additions & 0 deletions RNTester/js/RNTesterList.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ const ComponentExamples: Array<RNTesterExample> = [
key: 'ScrollViewSimpleExample',
module: require('./ScrollViewSimpleExample'),
},
{
key: 'ScrollViewAnimatedExample',
module: require('./ScrollViewAnimatedExample'),
},
{
key: 'SectionListExample',
module: require('./SectionListExample'),
Expand Down
5 changes: 5 additions & 0 deletions RNTester/js/RNTesterList.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ const ComponentExamples: Array<RNTesterExample> = [
module: require('./ScrollViewSimpleExample'),
supportsTVOS: true,
},
{
key: 'ScrollViewAnimatedExample',
module: require('./ScrollViewAnimatedExample'),
supportsTVOS: true,
},
{
key: 'SafeAreaViewExample',
module: require('./SafeAreaViewExample'),
Expand Down
115 changes: 115 additions & 0 deletions RNTester/js/ScrollViewAnimatedExample.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/

'use strict';

const React = require('react');
const ReactNative = require('react-native');
const {Component} = React;
const {
StyleSheet,
Text,
View,
Animated,
Easing,
TouchableOpacity,
Dimensions,
} = ReactNative;

class Button extends Component<{}> {
render() {
const {onPress, title} = this.props;
return (
<TouchableOpacity onPress={onPress}>
<View style={styles.button}>
<Text>{title}</Text>
</View>
</TouchableOpacity>
);
}
}

class ScrollViewAnimatedExample extends Component<{}> {
_scrollViewPos = new Animated.Value(0);

startAnimation = () => {
this._scrollViewPos.setValue(0);
Animated.timing(this._scrollViewPos, {
toValue: 100,
duration: 10000,
easing: Easing.linear,
useNativeDriver: true,
}).start();
};

render() {
const interpolated = this._scrollViewPos.interpolate({
inputRange: [0, 1],
outputRange: [0, 0.1],
});
const interpolated2 = this._scrollViewPos.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '1deg'],
});
return (
<View style={styles.container}>
<Animated.View
style={{
width: 100,
height: 100,
backgroundColor: 'black',
transform: [{translateX: interpolated}, {rotate: interpolated2}],
}}
/>
<Animated.ScrollView
horizontal
scrollEventThrottle={16}
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {x: this._scrollViewPos}}}],
{useNativeDriver: true},
)}>
<Button
onPress={this.startAnimation}
title="Scroll me horizontally"
/>
</Animated.ScrollView>
</View>
);
}
}

const {width, height} = Dimensions.get('window');

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
button: {
margin: 50,
width: width,
marginRight: width,
height: height / 2,
},
});

exports.title = '<ScrollViewAnimated>';
exports.description = 'Component that is animated when ScrollView is offset.';

exports.examples = [
{
title: 'Animated by scroll view',
render: function(): React.Element<typeof ScrollViewAnimatedExample> {
return <ScrollViewAnimatedExample />;
},
},
];

0 comments on commit 827fc61

Please sign in to comment.