mirror of
https://github.com/zhigang1992/react-native-reanimated.git
synced 2026-04-24 04:25:12 +08:00
Add interpolate function from kmagiera with example. [WIP] (#11)
Interpolate function from https://github.com/kmagiera/react-native-reanimated/issues/10#issuecomment-392066106 with extrapolation handling, examples, and documentation. Closes #10 .
This commit is contained in:
committed by
Krzysztof Magiera
parent
8d3ece3356
commit
b9ba694ace
@@ -1,11 +1,12 @@
|
||||
import React from 'react';
|
||||
import { Text, View, FlatList, StyleSheet, YellowBox } from 'react-native';
|
||||
import { StackNavigator } from 'react-navigation';
|
||||
import { createStackNavigator } from 'react-navigation';
|
||||
import { RectButton, ScrollView } from 'react-native-gesture-handler';
|
||||
|
||||
import Snappable from './snappable';
|
||||
import ImageViewer from './imageViewer';
|
||||
import Test from './test';
|
||||
import Interpolate from './src/interpolate';
|
||||
|
||||
YellowBox.ignoreWarnings([
|
||||
'Warning: isMounted(...) is deprecated',
|
||||
@@ -18,11 +19,12 @@ const SCREENS = {
|
||||
Snappable: { screen: Snappable, title: 'Snappable' },
|
||||
Test: { screen: Test, title: 'Test' },
|
||||
ImageViewer: { screen: ImageViewer, title: 'Image Viewer' },
|
||||
Interpolate: { screen: Interpolate, title: 'Interpolate' },
|
||||
};
|
||||
|
||||
class MainScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: '🎬 Reanimated Demo',
|
||||
title: '🎬 Reanimated Examples',
|
||||
};
|
||||
render() {
|
||||
const data = Object.keys(SCREENS).map(key => ({ key }));
|
||||
@@ -57,7 +59,7 @@ class MainScreenItem extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const ExampleApp = StackNavigator(
|
||||
const ExampleApp = createStackNavigator(
|
||||
{
|
||||
Main: { screen: MainScreen },
|
||||
...SCREENS,
|
||||
|
||||
@@ -420,6 +420,9 @@ class Viewer extends Component {
|
||||
}
|
||||
|
||||
export default class Example extends Component {
|
||||
static navigationOptions = {
|
||||
title: 'Image Viewer Example',
|
||||
};
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"react-native": "0.55.3",
|
||||
"react-native-gesture-handler": "^1.0.0",
|
||||
"react-native-reanimated": "file:../",
|
||||
"react-navigation": "^1.5.11"
|
||||
"react-navigation": "^2.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-jest": "22.4.3",
|
||||
|
||||
@@ -128,6 +128,9 @@ class Snappable extends Component {
|
||||
}
|
||||
|
||||
export default class Example extends Component {
|
||||
static navigationOptions = {
|
||||
title: 'Snappable Example',
|
||||
};
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
|
||||
25
Example/src/Box.js
Normal file
25
Example/src/Box.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet } from 'react-native';
|
||||
import Animated, { Easing } from 'react-native-reanimated';
|
||||
|
||||
/**
|
||||
* Needs to be a class component for react-native-gesture-handler to put a ref on it.
|
||||
*/
|
||||
export default class Box extends React.Component {
|
||||
render() {
|
||||
const { style, ...props } = this.props;
|
||||
return <Animated.View style={[styles.box, style]} {...props} />;
|
||||
}
|
||||
}
|
||||
|
||||
const BOX_SIZE = 44;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
box: {
|
||||
width: BOX_SIZE,
|
||||
height: BOX_SIZE,
|
||||
alignSelf: 'center',
|
||||
backgroundColor: 'blue',
|
||||
margin: 10,
|
||||
},
|
||||
});
|
||||
14
Example/src/Row.js
Normal file
14
Example/src/Row.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import { View, StyleSheet } from 'react-native';
|
||||
|
||||
const Row = ({ style, ...props }) => (
|
||||
<View style={[styles.style, style]} {...props} pointerEvents="box-none" />
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
style: {
|
||||
height: 64,
|
||||
},
|
||||
});
|
||||
|
||||
export default Row;
|
||||
233
Example/src/interpolate/AnimatedBounds.js
Normal file
233
Example/src/interpolate/AnimatedBounds.js
Normal file
@@ -0,0 +1,233 @@
|
||||
import React, { Component } from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import Animated, { Easing } from 'react-native-reanimated';
|
||||
import { PanGestureHandler, State } from 'react-native-gesture-handler';
|
||||
import Box from '../Box';
|
||||
import Row from '../Row';
|
||||
|
||||
const {
|
||||
set,
|
||||
cond,
|
||||
sub,
|
||||
eq,
|
||||
and,
|
||||
add,
|
||||
call,
|
||||
multiply,
|
||||
lessThan,
|
||||
startClock,
|
||||
stopClock,
|
||||
clockRunning,
|
||||
block,
|
||||
timing,
|
||||
debug,
|
||||
spring,
|
||||
Value,
|
||||
Clock,
|
||||
event,
|
||||
interpolate,
|
||||
defined,
|
||||
} = Animated;
|
||||
|
||||
function runSpring(clock, value, velocity, dest) {
|
||||
const state = {
|
||||
finished: new Value(0),
|
||||
velocity: new Value(0),
|
||||
position: new Value(0),
|
||||
time: new Value(0),
|
||||
};
|
||||
|
||||
const config = {
|
||||
damping: 7,
|
||||
mass: 1,
|
||||
stiffness: 121.6,
|
||||
overshootClamping: false,
|
||||
restSpeedThreshold: 0.001,
|
||||
restDisplacementThreshold: 0.001,
|
||||
toValue: new Value(0),
|
||||
};
|
||||
|
||||
return [
|
||||
cond(clockRunning(clock), 0, [
|
||||
set(state.finished, 0),
|
||||
set(state.velocity, velocity),
|
||||
set(state.position, value),
|
||||
set(config.toValue, dest),
|
||||
startClock(clock),
|
||||
]),
|
||||
cond(state.finished, stopClock(clock)),
|
||||
state.position,
|
||||
];
|
||||
}
|
||||
|
||||
function runTiming(clock, value, dest) {
|
||||
const state = {
|
||||
finished: new Value(1),
|
||||
position: new Value(value),
|
||||
time: new Value(0),
|
||||
frameTime: new Value(0),
|
||||
};
|
||||
|
||||
const config = {
|
||||
duration: 500,
|
||||
toValue: new Value(0),
|
||||
easing: Easing.inOut(Easing.ease),
|
||||
};
|
||||
|
||||
const reset = [
|
||||
set(state.finished, 0),
|
||||
set(state.time, 0),
|
||||
set(state.frameTime, 0),
|
||||
];
|
||||
|
||||
return block([
|
||||
cond(and(state.finished, eq(state.position, value)), [
|
||||
...reset,
|
||||
set(config.toValue, dest),
|
||||
]),
|
||||
cond(and(state.finished, eq(state.position, dest)), [
|
||||
...reset,
|
||||
set(config.toValue, value),
|
||||
]),
|
||||
cond(clockRunning(clock), 0, startClock(clock)),
|
||||
timing(clock, state, config),
|
||||
state.position,
|
||||
]);
|
||||
}
|
||||
|
||||
const getAnimation = (min, max) => {
|
||||
const clock = new Clock();
|
||||
const state = {
|
||||
finished: new Value(1),
|
||||
position: new Value(min),
|
||||
time: new Value(0),
|
||||
frameTime: new Value(0),
|
||||
};
|
||||
|
||||
const config = {
|
||||
duration: 500,
|
||||
toValue: new Value(0),
|
||||
easing: Easing.inOut(Easing.ease),
|
||||
};
|
||||
|
||||
const reset = [
|
||||
set(state.finished, 0),
|
||||
set(state.time, 0),
|
||||
set(state.frameTime, 0),
|
||||
];
|
||||
|
||||
return block([
|
||||
cond(and(state.finished, eq(state.position, min)), [
|
||||
...reset,
|
||||
set(config.toValue, max),
|
||||
]),
|
||||
cond(and(state.finished, eq(state.position, max)), [
|
||||
...reset,
|
||||
set(config.toValue, min),
|
||||
]),
|
||||
cond(clockRunning(clock), 0, startClock(clock)),
|
||||
timing(clock, state, config),
|
||||
state.position,
|
||||
]);
|
||||
};
|
||||
|
||||
export default class AnimatedBounds extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const TOSS_SEC = 0.2;
|
||||
|
||||
const dragX = new Value(0);
|
||||
const state = new Value(-1);
|
||||
const dragVX = new Value(0);
|
||||
const transX = new Value();
|
||||
const prevDragX = new Value(0);
|
||||
const clock = new Clock();
|
||||
|
||||
this._onGestureEvent = event([
|
||||
{ nativeEvent: { translationX: dragX, velocityX: dragVX, state: state } },
|
||||
]);
|
||||
|
||||
const snapPoint = cond(
|
||||
lessThan(add(transX, multiply(TOSS_SEC, dragVX)), 0),
|
||||
-100,
|
||||
100
|
||||
);
|
||||
|
||||
this._transX = cond(
|
||||
eq(state, State.ACTIVE),
|
||||
[
|
||||
stopClock(clock),
|
||||
set(transX, add(transX, sub(dragX, prevDragX))),
|
||||
set(prevDragX, dragX),
|
||||
transX,
|
||||
],
|
||||
[
|
||||
set(prevDragX, 0),
|
||||
set(
|
||||
transX,
|
||||
cond(defined(transX), runSpring(clock, transX, dragVX, snapPoint), 0)
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
this._transX = interpolate(this._transX, {
|
||||
inputRange: [-100, 100],
|
||||
outputRange: [-100, 100],
|
||||
extrapolate: 'clamp',
|
||||
});
|
||||
|
||||
const min = getAnimation(-100, -50);
|
||||
const max = getAnimation(100, 50);
|
||||
this._transXA = interpolate(this._transX, {
|
||||
inputRange: [-100, 100],
|
||||
outputRange: [min, max],
|
||||
extrapolate: 'clamp',
|
||||
});
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Row>
|
||||
<Animated.View
|
||||
style={[styles.line, { transform: [{ translateX: -100 }] }]}
|
||||
/>
|
||||
<Animated.View
|
||||
style={[styles.line, { transform: [{ translateX: 100 }] }]}
|
||||
/>
|
||||
<PanGestureHandler
|
||||
maxPointers={1}
|
||||
onGestureEvent={this._onGestureEvent}
|
||||
onHandlerStateChange={this._onGestureEvent}>
|
||||
<Box style={{ transform: [{ translateX: this._transX }] }} />
|
||||
</PanGestureHandler>
|
||||
</Row>
|
||||
<Row>
|
||||
<Animated.View
|
||||
style={[styles.line, { transform: [{ translateX: this.min }] }]}
|
||||
/>
|
||||
<Animated.View
|
||||
style={[styles.line, { transform: [{ translateX: this.max }] }]}
|
||||
/>
|
||||
<Box style={{ transform: [{ translateX: this._transXA }] }} />
|
||||
</Row>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
line: {
|
||||
position: 'absolute',
|
||||
alignSelf: 'center',
|
||||
backgroundColor: 'red',
|
||||
height: 64,
|
||||
width: 1,
|
||||
},
|
||||
});
|
||||
81
Example/src/interpolate/Basic.js
Normal file
81
Example/src/interpolate/Basic.js
Normal file
@@ -0,0 +1,81 @@
|
||||
import React, { Component } from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import Animated, { Easing } from 'react-native-reanimated';
|
||||
import Box from '../Box';
|
||||
import Row from '../Row';
|
||||
|
||||
const {
|
||||
set,
|
||||
cond,
|
||||
eq,
|
||||
and,
|
||||
add,
|
||||
call,
|
||||
multiply,
|
||||
lessThan,
|
||||
startClock,
|
||||
stopClock,
|
||||
clockRunning,
|
||||
block,
|
||||
timing,
|
||||
debug,
|
||||
spring,
|
||||
Value,
|
||||
Clock,
|
||||
event,
|
||||
interpolate,
|
||||
} = Animated;
|
||||
|
||||
function runTiming(clock, value, dest) {
|
||||
const state = {
|
||||
finished: new Value(1),
|
||||
position: new Value(value),
|
||||
time: new Value(0),
|
||||
frameTime: new Value(0),
|
||||
};
|
||||
|
||||
const config = {
|
||||
duration: 500,
|
||||
toValue: new Value(0),
|
||||
easing: Easing.inOut(Easing.ease),
|
||||
};
|
||||
|
||||
const reset = [
|
||||
set(state.finished, 0),
|
||||
set(state.time, 0),
|
||||
set(state.frameTime, 0),
|
||||
];
|
||||
|
||||
return block([
|
||||
cond(and(state.finished, eq(state.position, value)), [
|
||||
...reset,
|
||||
set(config.toValue, dest),
|
||||
]),
|
||||
cond(and(state.finished, eq(state.position, dest)), [
|
||||
...reset,
|
||||
set(config.toValue, value),
|
||||
]),
|
||||
cond(clockRunning(clock), 0, startClock(clock)),
|
||||
timing(clock, state, config),
|
||||
state.position,
|
||||
]);
|
||||
}
|
||||
|
||||
export default class Basic extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const clock = new Clock();
|
||||
const base = runTiming(clock, -1, 1);
|
||||
this._transX = interpolate(base, {
|
||||
inputRange: [-1, 1],
|
||||
outputRange: [-100, 100],
|
||||
});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Row>
|
||||
<Box style={{ transform: [{ translateX: this._transX }] }} />
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
}
|
||||
176
Example/src/interpolate/WithDrag.js
Normal file
176
Example/src/interpolate/WithDrag.js
Normal file
@@ -0,0 +1,176 @@
|
||||
import React, { Component } from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import Animated, { Easing } from 'react-native-reanimated';
|
||||
import { PanGestureHandler, State } from 'react-native-gesture-handler';
|
||||
import Box from '../Box';
|
||||
import Row from '../Row';
|
||||
|
||||
const {
|
||||
set,
|
||||
cond,
|
||||
sub,
|
||||
eq,
|
||||
and,
|
||||
add,
|
||||
call,
|
||||
multiply,
|
||||
lessThan,
|
||||
startClock,
|
||||
stopClock,
|
||||
clockRunning,
|
||||
block,
|
||||
timing,
|
||||
debug,
|
||||
spring,
|
||||
Value,
|
||||
Clock,
|
||||
event,
|
||||
interpolate,
|
||||
defined,
|
||||
} = Animated;
|
||||
|
||||
function runSpring(clock, value, velocity, dest) {
|
||||
const state = {
|
||||
finished: new Value(0),
|
||||
velocity: new Value(0),
|
||||
position: new Value(0),
|
||||
time: new Value(0),
|
||||
};
|
||||
|
||||
const config = {
|
||||
damping: 7,
|
||||
mass: 1,
|
||||
stiffness: 121.6,
|
||||
overshootClamping: false,
|
||||
restSpeedThreshold: 0.001,
|
||||
restDisplacementThreshold: 0.001,
|
||||
toValue: new Value(0),
|
||||
};
|
||||
|
||||
return [
|
||||
cond(clockRunning(clock), 0, [
|
||||
set(state.finished, 0),
|
||||
set(state.velocity, velocity),
|
||||
set(state.position, value),
|
||||
set(config.toValue, dest),
|
||||
startClock(clock),
|
||||
]),
|
||||
cond(state.finished, stopClock(clock)),
|
||||
state.position,
|
||||
];
|
||||
}
|
||||
|
||||
function runTiming(clock, value, dest) {
|
||||
const state = {
|
||||
finished: new Value(1),
|
||||
position: new Value(value),
|
||||
time: new Value(0),
|
||||
frameTime: new Value(0),
|
||||
};
|
||||
|
||||
const config = {
|
||||
duration: 500,
|
||||
toValue: new Value(0),
|
||||
easing: Easing.inOut(Easing.ease),
|
||||
};
|
||||
|
||||
const reset = [
|
||||
set(state.finished, 0),
|
||||
set(state.time, 0),
|
||||
set(state.frameTime, 0),
|
||||
];
|
||||
|
||||
return block([
|
||||
cond(and(state.finished, eq(state.position, value)), [
|
||||
...reset,
|
||||
set(config.toValue, dest),
|
||||
]),
|
||||
cond(and(state.finished, eq(state.position, dest)), [
|
||||
...reset,
|
||||
set(config.toValue, value),
|
||||
]),
|
||||
cond(clockRunning(clock), 0, startClock(clock)),
|
||||
timing(clock, state, config),
|
||||
state.position,
|
||||
]);
|
||||
}
|
||||
|
||||
export default class WithDrag extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const TOSS_SEC = 0.2;
|
||||
|
||||
const dragX = new Value(0);
|
||||
const state = new Value(-1);
|
||||
const dragVX = new Value(0);
|
||||
const transX = new Value();
|
||||
const prevDragX = new Value(0);
|
||||
const clock = new Clock();
|
||||
|
||||
this._onGestureEvent = event([
|
||||
{ nativeEvent: { translationX: dragX, velocityX: dragVX, state: state } },
|
||||
]);
|
||||
|
||||
const snapPoint = cond(
|
||||
lessThan(add(transX, multiply(TOSS_SEC, dragVX)), 0),
|
||||
-100,
|
||||
100
|
||||
);
|
||||
|
||||
this._transX = cond(
|
||||
eq(state, State.ACTIVE),
|
||||
[
|
||||
stopClock(clock),
|
||||
set(transX, add(transX, sub(dragX, prevDragX))),
|
||||
set(prevDragX, dragX),
|
||||
transX,
|
||||
],
|
||||
[
|
||||
set(prevDragX, 0),
|
||||
set(
|
||||
transX,
|
||||
cond(defined(transX), runSpring(clock, transX, dragVX, snapPoint), 0)
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
this._transXA = interpolate(this._transX, {
|
||||
inputRange: [-120, 120],
|
||||
outputRange: [-100, 100],
|
||||
});
|
||||
this._transXB = interpolate(this._transX, {
|
||||
inputRange: [-120, -60, 60, 120],
|
||||
outputRange: [-60, -10, 10, 60],
|
||||
});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Row>
|
||||
<PanGestureHandler
|
||||
maxPointers={1}
|
||||
onGestureEvent={this._onGestureEvent}
|
||||
onHandlerStateChange={this._onGestureEvent}>
|
||||
<Box style={{ transform: [{ translateX: this._transX }] }} />
|
||||
</PanGestureHandler>
|
||||
</Row>
|
||||
<Row>
|
||||
<Box style={{ transform: [{ translateX: this._transXA }] }} />
|
||||
</Row>
|
||||
<Row>
|
||||
<Box style={{ transform: [{ translateX: this._transXB }] }} />
|
||||
</Row>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const BOX_SIZE = 44;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
});
|
||||
69
Example/src/interpolate/index.js
Normal file
69
Example/src/interpolate/index.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import React from 'react';
|
||||
import { Text, View, FlatList, StyleSheet, YellowBox } from 'react-native';
|
||||
import { StackNavigator } from 'react-navigation';
|
||||
import { RectButton, ScrollView } from 'react-native-gesture-handler';
|
||||
|
||||
import Basic from './Basic';
|
||||
import WithDrag from './WithDrag';
|
||||
import AnimatedBounds from './AnimatedBounds';
|
||||
|
||||
const examples = [Basic, WithDrag, AnimatedBounds].map(v => ({
|
||||
key: v.displayName,
|
||||
title: v.displayName,
|
||||
Component: v,
|
||||
}));
|
||||
|
||||
class Item extends React.Component {
|
||||
render() {
|
||||
const item = this.props.item;
|
||||
const Comp = this.props.item.Component;
|
||||
|
||||
return (
|
||||
<View style={styles.button}>
|
||||
<Text>{item.title}</Text>
|
||||
<Comp />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MainScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: 'Interpolation Examples',
|
||||
};
|
||||
renderItem = props => <Item {...props} />;
|
||||
render() {
|
||||
return (
|
||||
<FlatList
|
||||
style={styles.list}
|
||||
data={examples}
|
||||
ItemSeparatorComponent={ItemSeparator}
|
||||
renderItem={this.renderItem}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const ItemSeparator = () => <View style={styles.separator} />;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
list: {
|
||||
backgroundColor: '#EFEFF4',
|
||||
},
|
||||
separator: {
|
||||
height: 1,
|
||||
backgroundColor: '#DBDBE0',
|
||||
},
|
||||
buttonText: {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
button: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#fff',
|
||||
padding: 20,
|
||||
},
|
||||
});
|
||||
|
||||
export default MainScreen;
|
||||
@@ -1657,6 +1657,13 @@ create-react-class@^15.6.3:
|
||||
loose-envify "^1.3.1"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
create-react-context@^0.2.1:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.2.2.tgz#9836542f9aaa22868cd7d4a6f82667df38019dca"
|
||||
dependencies:
|
||||
fbjs "^0.8.0"
|
||||
gud "^1.0.0"
|
||||
|
||||
cross-spawn@^5.0.1, cross-spawn@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
|
||||
@@ -2089,7 +2096,7 @@ fbjs-scripts@^0.8.1:
|
||||
semver "^5.1.0"
|
||||
through2 "^2.0.0"
|
||||
|
||||
fbjs@^0.8.14, fbjs@^0.8.16, fbjs@^0.8.9:
|
||||
fbjs@^0.8.0, fbjs@^0.8.14, fbjs@^0.8.16, fbjs@^0.8.9:
|
||||
version "0.8.16"
|
||||
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
|
||||
dependencies:
|
||||
@@ -2323,6 +2330,10 @@ growly@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
|
||||
|
||||
gud@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
|
||||
|
||||
handlebars@^4.0.3:
|
||||
version "4.0.11"
|
||||
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc"
|
||||
@@ -2408,7 +2419,7 @@ hoek@4.x.x:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb"
|
||||
|
||||
hoist-non-react-statics@^2.2.0, hoist-non-react-statics@^2.3.1:
|
||||
hoist-non-react-statics@^2.2.0, hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz#d2ca2dfc19c5a91c5a6615ce8e564ef0347e2a40"
|
||||
|
||||
@@ -4160,9 +4171,9 @@ react-is@^16.3.1:
|
||||
version "16.3.2"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.2.tgz#f4d3d0e2f5fbb6ac46450641eb2e25bf05d36b22"
|
||||
|
||||
react-lifecycles-compat@^1.0.2:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-1.1.4.tgz#fc005c72849b7ed364de20a0f64ff58ebdc2009a"
|
||||
react-lifecycles-compat@^3, react-lifecycles-compat@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||
|
||||
react-native-dismiss-keyboard@1.0.0:
|
||||
version "1.0.0"
|
||||
@@ -4197,9 +4208,21 @@ react-native-safe-area-view@^0.7.0:
|
||||
dependencies:
|
||||
hoist-non-react-statics "^2.3.1"
|
||||
|
||||
"react-native-tab-view@github:react-navigation/react-native-tab-view":
|
||||
version "0.0.74"
|
||||
resolved "https://codeload.github.com/react-navigation/react-native-tab-view/tar.gz/36ebd834d78b841fc19778c966465d02fd1213bb"
|
||||
react-native-safe-area-view@^0.8.0:
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-safe-area-view/-/react-native-safe-area-view-0.8.0.tgz#22d78cb8e8658d04a10cd53c1546e0bc86cb7aea"
|
||||
dependencies:
|
||||
hoist-non-react-statics "^2.3.1"
|
||||
|
||||
react-native-tab-view@^0.0.77:
|
||||
version "0.0.77"
|
||||
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-0.0.77.tgz#11ceb8e7c23100d07e628dc151b57797524d00d4"
|
||||
dependencies:
|
||||
prop-types "^15.6.0"
|
||||
|
||||
react-native-tab-view@~0.0.78:
|
||||
version "0.0.78"
|
||||
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-0.0.78.tgz#9b90730d89cbd34a03f0e0ab10e74ca7af945560"
|
||||
dependencies:
|
||||
prop-types "^15.6.0"
|
||||
|
||||
@@ -4267,18 +4290,36 @@ react-native@0.55.3:
|
||||
xmldoc "^0.4.0"
|
||||
yargs "^9.0.0"
|
||||
|
||||
react-navigation@^1.5.11:
|
||||
version "1.5.11"
|
||||
resolved "https://registry.yarnpkg.com/react-navigation/-/react-navigation-1.5.11.tgz#fba6ab45d7b9987c1763a5aaac53b4f6d62b7f5c"
|
||||
react-navigation-deprecated-tab-navigator@1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/react-navigation-deprecated-tab-navigator/-/react-navigation-deprecated-tab-navigator-1.3.0.tgz#015dcae1e977b984ca7e99245261c15439026bb7"
|
||||
dependencies:
|
||||
react-native-tab-view "^0.0.77"
|
||||
|
||||
react-navigation-tabs@0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.3.0.tgz#b1fe7ef1c665dd8928fafcc8622616e220ae5efa"
|
||||
dependencies:
|
||||
hoist-non-react-statics "^2.5.0"
|
||||
prop-types "^15.6.0"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
react-native-safe-area-view "^0.7.0"
|
||||
react-native-tab-view "~0.0.78"
|
||||
|
||||
react-navigation@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-navigation/-/react-navigation-2.0.4.tgz#efc09de09799c2117a54002a6ea0e9b80e92828d"
|
||||
dependencies:
|
||||
clamp "^1.0.1"
|
||||
create-react-context "^0.2.1"
|
||||
hoist-non-react-statics "^2.2.0"
|
||||
path-to-regexp "^1.7.0"
|
||||
prop-types "^15.5.10"
|
||||
react-lifecycles-compat "^1.0.2"
|
||||
react-lifecycles-compat "^3"
|
||||
react-native-drawer-layout-polyfill "^1.3.2"
|
||||
react-native-safe-area-view "^0.7.0"
|
||||
react-native-tab-view "github:react-navigation/react-native-tab-view"
|
||||
react-native-safe-area-view "^0.8.0"
|
||||
react-navigation-deprecated-tab-navigator "1.3.0"
|
||||
react-navigation-tabs "0.3.0"
|
||||
|
||||
react-proxy@^1.1.7:
|
||||
version "1.1.8"
|
||||
|
||||
28
README.md
28
README.md
@@ -70,7 +70,6 @@ All the functionality that missing elements provide in Animated can be already a
|
||||
- [ ] value tracking (can be achieved in different way, reanimated also allows for tracking all the animation parameters not only destination params)
|
||||
- [ ] animation delays
|
||||
- [ ] animation staggering
|
||||
- [ ] interpolate method
|
||||
|
||||
## Clocks
|
||||
|
||||
@@ -422,6 +421,29 @@ Returns an accumulated value of the given node. This node stores a sum of all ev
|
||||
|
||||
Works the same way as with the original Animated library.
|
||||
|
||||
---
|
||||
### `interpolate`
|
||||
```js
|
||||
interpolate(node, {
|
||||
// Input range for the interpolation. Should be monotonically increasing.
|
||||
inputRange: [nodeOrValue...],
|
||||
// Output range for the interpolation, should be the same length as the input range.
|
||||
outputRange: [nodeOrValue...],
|
||||
// Sets the left and right extrapolate modes.
|
||||
extrapolate?: Extrapolate.EXTEND | Extrapolate.CLAMP | Extrapolate.IDENTITY,
|
||||
// Set the left extrapolate mode, the behavior if the input is less than the first value in inputRange.
|
||||
extrapolateLeft?: Extrapolate.EXTEND | Extrapolate.CLAMP | Extrapolate.IDENTITY,
|
||||
// Set the right extrapolate mode, the behavior if the input is greater than the last value in inputRange.
|
||||
extrapolateRight?: Extrapolate.EXTEND | Extrapolate.CLAMP | Extrapolate.IDENTITY,
|
||||
})
|
||||
|
||||
Extrapolate.EXTEND; // Will extend the range linearly.
|
||||
Extrapolate.CLAMP; // Will clamp the input value to the range.
|
||||
Extrapolate.IDENTITY; // Will return the input value if the input value is out of range.
|
||||
```
|
||||
|
||||
Maps an input value within a range to an output value within a range. Also supports different types of extrapolation for when the value falls outside the range.
|
||||
|
||||
<!-- Anims -->
|
||||
|
||||
---
|
||||
@@ -434,7 +456,7 @@ decay(clock, { finished, velocity, position, time }, { deceleration })
|
||||
Updates `position` and `velocity` nodes by running a single step of animation each time this node evaluates. State variable `finished` is set to `1` when the animation gets to the final point (that is the velocity drops under the level of significance). The `time` state node is populated automatically by this node and refers to the last clock time this node got evaluated. It is expected to be reset each time we want to restart the animation. Decay animation can be configured using `deceleration` config param and it controls how fast the animation decelerates. The value should be between `0` and `1` but only values that are close to `1` would yield meaningful results.
|
||||
|
||||
---
|
||||
#### `timing`
|
||||
### `timing`
|
||||
|
||||
```js
|
||||
timing(clock, { finished, position, frameTime, time }, { toValue, duration, easing })
|
||||
@@ -444,7 +466,7 @@ Updates `position` node by running timing based animation from a given position
|
||||
The `frameTime` node will also get updated and represents the progress of animation in milliseconds (how long the animation has lasted so far). Similarly to the `time` node that just indicates the last clock time the animation node has been evaluated. Both of these variables are expected to be reset before restarting the animation. Finally `finished` node will be set to `1` when the position reaches the final value or when `frameTime` exceeds `duration`.
|
||||
|
||||
---
|
||||
#### `spring`
|
||||
### `spring`
|
||||
|
||||
```js
|
||||
spring(clock, { finished, position, velocity, time }, { damping, mass, stiffness, overshootClamping, restSpeedThreshold, restDisplacementThreshold, toValue })
|
||||
|
||||
@@ -7,13 +7,14 @@ import {
|
||||
sub,
|
||||
set,
|
||||
add,
|
||||
divide,
|
||||
} from './base';
|
||||
import AnimatedValue from './core/AnimatedValue';
|
||||
import { adapt } from './utils';
|
||||
|
||||
export function abs(a) {
|
||||
export const abs = function(a) {
|
||||
return cond(lessThan(a, 0), multiply(-1, a), a);
|
||||
}
|
||||
};
|
||||
|
||||
export const min = function(a, b) {
|
||||
a = adapt(a);
|
||||
@@ -49,3 +50,76 @@ export const diffClamp = function(a, minVal, maxVal) {
|
||||
min(max(add(cond(defined(value), value, a), diff(a)), minVal), maxVal)
|
||||
);
|
||||
};
|
||||
|
||||
const interpolateInternalSingle = function(
|
||||
value,
|
||||
inputRange,
|
||||
outputRange,
|
||||
offset
|
||||
) {
|
||||
const inS = inputRange[offset];
|
||||
const inE = inputRange[offset + 1];
|
||||
const outS = outputRange[offset];
|
||||
const outE = outputRange[offset + 1];
|
||||
const progress = divide(sub(value, inS), sub(inE, inS));
|
||||
return add(outS, multiply(progress, sub(outE, outS)));
|
||||
};
|
||||
|
||||
const interpolateInternal = function(
|
||||
value,
|
||||
inputRange,
|
||||
outputRange,
|
||||
offset = 0
|
||||
) {
|
||||
if (inputRange.length - offset === 2) {
|
||||
return interpolateInternalSingle(value, inputRange, outputRange, offset);
|
||||
}
|
||||
return cond(
|
||||
lessThan(value, inputRange[offset + 1]),
|
||||
interpolateInternalSingle(value, inputRange, outputRange, offset),
|
||||
interpolateInternal(value, inputRange, outputRange, offset + 1)
|
||||
);
|
||||
};
|
||||
|
||||
export const Extrapolate = {
|
||||
EXTEND: 'EXTEND',
|
||||
CLAMP: 'CLAMP',
|
||||
IDENTITY: 'IDENTITY',
|
||||
};
|
||||
|
||||
export const interpolate = function(value, config) {
|
||||
const {
|
||||
inputRange,
|
||||
outputRange,
|
||||
extrapolate = Extrapolate.EXTEND,
|
||||
extrapolateLeft,
|
||||
extrapolateRight,
|
||||
} = config;
|
||||
const left = extrapolateLeft || extrapolate;
|
||||
const right = extrapolateRight || extrapolate;
|
||||
let output = interpolateInternal(value, inputRange, outputRange);
|
||||
|
||||
if (left === Extrapolate.EXTEND) {
|
||||
} else if (left === Extrapolate.CLAMP) {
|
||||
output = cond(lessThan(value, inputRange[0]), outputRange[0], output);
|
||||
} else if (left === Extrapolate.IDENTITY) {
|
||||
output = cond(lessThan(value, inputRange[0]), value, output);
|
||||
}
|
||||
|
||||
if (right === Extrapolate.EXTEND) {
|
||||
} else if (right === Extrapolate.CLAMP) {
|
||||
output = cond(
|
||||
greaterThan(value, inputRange[inputRange.length - 1]),
|
||||
outputRange[outputRange.length - 1],
|
||||
output
|
||||
);
|
||||
} else if (right === Extrapolate.IDENTITY) {
|
||||
output = cond(
|
||||
greaterThan(value, inputRange[inputRange.length - 1]),
|
||||
value,
|
||||
output
|
||||
);
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user