Skip to content

Commit

Permalink
Fix using multiple animations
Browse files Browse the repository at this point in the history
  • Loading branch information
terrysahaidak committed Feb 18, 2019
1 parent 2f713b6 commit 36120ad
Show file tree
Hide file tree
Showing 16 changed files with 227 additions and 162 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Expand Up @@ -38,6 +38,7 @@
"class-methods-use-this": "off",
"arrow-parens": "off",
"import/no-unresolved": ["error", { "ignore": ["^react$", "^react-native$", "^react-native-reanimated$"] }],
"import/extensions": ["error", "never", {"ignorePackages": true, "js": "never"} ]
"import/extensions": ["error", "never", {"ignorePackages": true, "js": "never"} ],
"react/no-multi-comp": 0
}
}
6 changes: 5 additions & 1 deletion Example/App.js
@@ -1,4 +1,5 @@
import React from 'react';
import { StatusBar } from 'react-native';
import AppNavigator from './navigation/AppNavigator';
import { NavigationService } from './services';
// import screens from './navigation/screens';
Expand All @@ -12,7 +13,10 @@ class App extends React.PureComponent {

render() {
return (
<AppNavigator ref={(ref) => NavigationService.init(ref)} />
<React.Fragment>
<StatusBar ranslucent />
<AppNavigator ref={(ref) => NavigationService.init(ref)} />
</React.Fragment>
);
}
}
Expand Down
3 changes: 3 additions & 0 deletions Example/app.json
Expand Up @@ -24,6 +24,9 @@
],
"ios": {
"supportsTablet": true
},
"androidStatusBar": {
"barStyle": "dark-content"
}
}
}
5 changes: 5 additions & 0 deletions Example/navigation/AppNavigator.js
Expand Up @@ -2,6 +2,7 @@ import {
createStackNavigator,
createAppContainer,
} from 'react-navigation';
import { StatusBar, Platform } from 'react-native';
import screens from './screens';
import Examples from '../screens/Examples/Examples';
import TransitionBase from '../screens/TransitionBase/TransitionBase';
Expand All @@ -18,6 +19,10 @@ const AppNavigator = createStackNavigator(
{
defaultNavigationOptions: ({ navigation }) => ({
title: navigation.getParam('title'),
headerStyle: {
marginTop:
Platform.OS === 'ios' ? null : -StatusBar.currentHeight,
},
}),
},
);
Expand Down
25 changes: 23 additions & 2 deletions Example/screens/Keyframes/Keyframes.js
Expand Up @@ -62,7 +62,7 @@ const config = createAnimationConfig({

const s = StyleSheet.create({
container: {
flex: 1,
height: 300,
backgroundColor: colors.white,
paddingTop: 50,
},
Expand Down Expand Up @@ -90,7 +90,7 @@ const s = StyleSheet.create({
},
});

export default class App extends React.PureComponent {
class Example extends React.PureComponent {
state = {
value: false,
};
Expand Down Expand Up @@ -134,3 +134,24 @@ export default class App extends React.PureComponent {
);
}
}

export default class App extends React.PureComponent {
state = {
showSecond: false,
};

componentDidMount() {
// testing each animation has its own state
setTimeout(() => this.setState({ showSecond: true }), 1000);
}

render() {
return (
<React.Fragment>
<Example />

{this.state.showSecond && <Example />}
</React.Fragment>
);
}
}
32 changes: 21 additions & 11 deletions Example/screens/TransitionBase/TransitionBase.js
@@ -1,5 +1,5 @@
import React from 'react';
import { StyleSheet, View, Dimensions } from 'react-native';
import { StyleSheet, View, Dimensions, FlatList } from 'react-native';
import {
Reanimatable,
createAnimationConfig,
Expand Down Expand Up @@ -29,27 +29,23 @@ const config = createAnimationConfig({
});

const s = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.white,
paddingTop: 50,
scroll: {
paddingVertical: 20,
},
animationContainer: {
marginBottom: 100,
height: 250,
justifyContent: 'center',
},
animatableView: {
height: 100,
backgroundColor: colors.red,
},
row: {
flexDirection: 'row',
position: 'absolute',
bottom: 50,
alignSelf: 'center',
},
});

export default class App extends React.PureComponent {
class Example extends React.PureComponent {
state = {
value: true,
};
Expand All @@ -67,7 +63,7 @@ export default class App extends React.PureComponent {

render() {
return (
<View style={s.container}>
<View>
<Reanimatable
ref={this.reanimatableRef}
config={config}
Expand Down Expand Up @@ -101,3 +97,17 @@ export default class App extends React.PureComponent {
);
}
}

export default function App() {
// performance test
const range = Array.from(new Array(10));

return (
<FlatList
data={range}
contentContainerStyle={s.scroll}
renderItem={() => <Example />}
keyExtractor={(_, i) => i.toString()}
/>
);
}
3 changes: 2 additions & 1 deletion lib/components/DelegateAnimation.js
Expand Up @@ -5,7 +5,7 @@ class DelegateAnimation extends React.PureComponent {
constructor(props) {
super(props);

const { values } = props._internal;
const { values } = props.generate();

this.state = {
values,
Expand All @@ -19,6 +19,7 @@ class DelegateAnimation extends React.PureComponent {

DelegateAnimation.propTypes = {
children: T.func,
generate: T.func,
};

export default DelegateAnimation;
26 changes: 14 additions & 12 deletions lib/components/KeyframesAnimation.js
@@ -1,24 +1,28 @@
import React from 'react';
import { InteractionManager } from 'react-native';
import T from 'prop-types';
import A from 'react-native-reanimated';

class KeyframesAnimation extends React.PureComponent {
constructor(props) {
super(props);

const { values, animation, operations } = props._internal;
const { values, operations } = props.generate();
this._operations = operations;

this.state = {
values,
animation,
};
}

componentWillUnmount() {
if (this.props.resetOnUnmount) {
setTimeout(() => this.reset(), 16);
}
componentDidMount() {
InteractionManager.runAfterInteractions(() => {
const animation = this._operations.createAnimation();

this.setState({
animation,
});
});
}

reset() {
Expand All @@ -28,7 +32,9 @@ class KeyframesAnimation extends React.PureComponent {
render() {
return (
<React.Fragment>
<A.Code exec={this.state.animation} />
{this.state.animation && (
<A.Code exec={this.state.animation} />
)}
{this.props.children(this.state.values)}
</React.Fragment>
);
Expand All @@ -37,11 +43,7 @@ class KeyframesAnimation extends React.PureComponent {

KeyframesAnimation.propTypes = {
children: T.func,
resetOnUnmount: T.bool,
};

KeyframesAnimation.defaultProps = {
resetOnUnmount: true,
generate: T.func,
};

export default KeyframesAnimation;
4 changes: 2 additions & 2 deletions lib/components/Reanimatable.js
Expand Up @@ -10,7 +10,7 @@ import {
import { ANIMATION_TYPE } from '../core/constants';

const validateConfig = (config) => {
if (typeof config._internal !== 'object') {
if (typeof config.generate !== 'function') {
throw new Error(
'Invalid config provided for the Reanimatable component. Did you forget to use "createAnimationConfig"?',
);
Expand Down Expand Up @@ -63,7 +63,7 @@ const Reanimatable = React.forwardRef(({
break;
}

if (this.containerStyle) {
if (containerStyle) {
return <View style={containerStyle}>{content}</View>;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/components/ScrollView.js
Expand Up @@ -74,7 +74,7 @@ class ScrollView extends React.PureComponent {

ScrollView.propTypes = {
delegate: T.shape({
event: T.func,
event: T.object,
reset: T.func,
}),
onScroll: T.func,
Expand Down
31 changes: 17 additions & 14 deletions lib/components/TransitionAnimation.js
@@ -1,4 +1,5 @@
import React, { Component } from 'react';
import { InteractionManager } from 'react-native';
import T from 'prop-types';
import A from 'react-native-reanimated';
import { ANIMATION_STATE } from '../core/constants';
Expand All @@ -7,22 +8,20 @@ class TransitionAnimation extends Component {
constructor(props) {
super(props);

this.initialValue = props.value;

const {
values,
animationState,
animation,
operations,
} = props._internal;

this.initialValue = props.value;
values,
} = this.props.generate();

this._operations = operations;

this.animationState = animationState;

this.state = {
values,
animation,
};
}

Expand All @@ -31,6 +30,14 @@ class TransitionAnimation extends Component {
// we have to do it on a mounted component
// the user won't notice it
this.reset();

InteractionManager.runAfterInteractions(() => {
const animation = this._operations.createAnimation();

this.setState({
animation,
});
});
}

componentDidUpdate(prevProps) {
Expand All @@ -43,10 +50,6 @@ class TransitionAnimation extends Component {
}
}

componentWillUnmount() {
this.reset();
}

reset() {
this.resetTo(this.initialValue);
}
Expand All @@ -63,19 +66,19 @@ class TransitionAnimation extends Component {
render() {
return (
<React.Fragment>
<A.Code exec={this.state.animation} />
{this.state.animation && (
<A.Code exec={this.state.animation} />
)}
{this.props.children(this.state.values)}
</React.Fragment>
);
}
}

TransitionAnimation.propTypes = {
values: T.object,
animation: T.object,
value: T.bool,
children: T.func,
duration: T.number,
generate: T.func,
};

export default TransitionAnimation;
2 changes: 1 addition & 1 deletion lib/core/animations.js
Expand Up @@ -25,7 +25,7 @@ export const runTiming = ({
return A.block([
// stop opposite clock before running our animation
// to set last (previous) position as a current one
A.cond(A.clockRunning(oppositeClock), A.stopClock(oppositeClock)),
oppositeClock ? A.cond(A.clockRunning(oppositeClock), A.stopClock(oppositeClock)) : 0,
// run our animation clock
A.cond(
A.clockRunning(clock),
Expand Down
6 changes: 3 additions & 3 deletions lib/core/createConfig.js
Expand Up @@ -8,13 +8,13 @@ export default function createConfig(animationConfig) {

if (animationConfig.animation.delegate) {
config.type = ANIMATION_TYPE.DELEGATE;
config._internal = createDelegateAnimation(animationConfig);
config.generate = createDelegateAnimation(animationConfig);
} else if (animationConfig.keyframes) {
config.type = ANIMATION_TYPE.KEYFRAMES;
config._internal = createKeyframesAnimation(animationConfig);
config.generate = createKeyframesAnimation(animationConfig);
} else {
config.type = ANIMATION_TYPE.TRANSITION;
config._internal = createTransitionAnimation(animationConfig);
config.generate = createTransitionAnimation(animationConfig);
}

return config;
Expand Down
4 changes: 2 additions & 2 deletions lib/core/createDelegateAnimation.js
Expand Up @@ -69,7 +69,7 @@ export default function createDelegateAnimation(config) {
baseValue: delegate.value,
});

return {
return () => ({
values,
};
});
}

0 comments on commit 36120ad

Please sign in to comment.