Summary:
Changelog: [Internal] - Update Animation examples to toggle useNativeDriver

There are issues when we toggle the native driver on and off. Where once off, the animations don't seem to update anymore, until we turn nativeDriver back on. See videos in testplan

Reviewed By: yungsters

Differential Revision: D29774939

fbshipit-source-id: cf6d70c1b574a87bb803510196dfb273b36de5e1
This commit is contained in:
Luna Wei 2021-07-22 17:22:30 -07:00 коммит произвёл Facebook GitHub Bot
Родитель 04b1ef5155
Коммит 63e0f7d767
10 изменённых файлов: 492 добавлений и 250 удалений

Просмотреть файл

@ -0,0 +1,43 @@
/**
* 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 strict-local
*/
'use strict';
import * as React from 'react';
import {StyleSheet, View} from 'react-native';
import {RNTesterThemeContext} from './RNTesterTheme';
type Props = $ReadOnly<{|
children?: ?React.Node,
testID?: string,
|}>;
/**
* Container view for a block of configuration options for an example.
*/
export default function RNTConfigurationBlock(props: Props): React.Node {
const theme = React.useContext(RNTesterThemeContext);
return (
<View
style={StyleSheet.compose(styles.container, {
borderColor: theme.SeparatorColor,
})}
testID={props.testID}>
{props.children}
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 10,
borderBottomWidth: 1,
},
});

Просмотреть файл

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
* @flow strict-local
*/
import * as React from 'react';
@ -13,13 +13,11 @@ import {View, Text, StyleSheet, Button} from 'react-native';
import {type RNTesterTheme} from './RNTesterTheme';
function RNTTestDetails({
test,
description,
expect,
title,
theme,
}: {
test?: string,
description?: string,
expect?: string,
title: string,
@ -27,27 +25,22 @@ function RNTTestDetails({
}): React.Node {
const [collapsed, setCollapsed] = React.useState(false);
const content =
test != null ? (
<>
const content = (
<>
{description == null ? null : (
<View style={styles.section}>
<Text style={styles.heading}>How to Test</Text>
<Text style={styles.paragraph}>{test}</Text>
<Text style={styles.heading}>Description</Text>
<Text style={styles.paragraph}>{description}</Text>
</View>
{expect != null && (
<View style={styles.section}>
<Text style={styles.heading}>Expectation</Text>
<Text style={styles.paragraph}>{expect}</Text>
</View>
)}
</>
) : description != null ? (
<View style={styles.section}>
<Text style={styles.heading}>Description</Text>
<Text style={styles.paragraph}>{description}</Text>
</View>
) : null;
)}
{expect == null ? null : (
<View style={styles.section}>
<Text style={styles.heading}>Expectation</Text>
<Text style={styles.paragraph}>{expect}</Text>
</View>
)}
</>
);
return (
<View
style={StyleSheet.compose(styles.container, {

Просмотреть файл

@ -12,6 +12,7 @@ import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
import * as React from 'react';
import RNTesterButton from '../../components/RNTesterButton';
import {Text, Easing, StyleSheet, View, Animated} from 'react-native';
import RNTConfigurationBlock from '../../components/RNTConfigurationBlock';
const styles = StyleSheet.create({
content: {
@ -25,103 +26,111 @@ const styles = StyleSheet.create({
},
});
function CompositeAnimationsWithEasingExample(): React.Node {
const anims = [1, 2, 3].map(() => new Animated.Value(0));
return (
<View>
<RNTConfigurationBlock>
<Text>Note you cannot `useNativeDriver` for layout properties.</Text>
</RNTConfigurationBlock>
<RNTesterButton
onPress={() => {
Animated.sequence([
// One after the other
Animated.timing(anims[0], {
toValue: 200,
// $FlowFixMe[method-unbinding]
easing: Easing.linear,
useNativeDriver: false,
}),
Animated.delay(400), // Use with sequence
Animated.timing(anims[0], {
toValue: 0,
// Springy
easing: Easing.elastic(2),
useNativeDriver: false,
}),
Animated.delay(400),
Animated.stagger(
200,
anims
.map(anim =>
Animated.timing(anim, {
toValue: 200,
useNativeDriver: false,
}),
)
.concat(
anims.map(anim =>
Animated.timing(anim, {
toValue: 0,
useNativeDriver: false,
}),
),
),
),
Animated.delay(400),
Animated.parallel(
[
// $FlowFixMe[method-unbinding]
Easing.inOut(Easing.quad), // Symmetric
Easing.back(1.5), // Goes backwards first
Easing.ease, // Default bezier
].map((easing, ii) =>
Animated.timing(anims[ii], {
toValue: 320,
// $FlowFixMe[method-unbinding]
easing,
duration: 3000,
useNativeDriver: false,
}),
),
),
Animated.delay(400),
Animated.stagger(
200,
anims.map(anim =>
Animated.timing(anim, {
toValue: 0,
// Like a ball
// $FlowFixMe[method-unbinding]
easing: Easing.bounce,
duration: 2000,
useNativeDriver: false,
}),
),
),
]).start();
}}>
Press to Animate
</RNTesterButton>
{['Composite', 'Easing', 'Animations!'].map((text, ii) => (
<Animated.View
key={text}
style={[
styles.content,
{
left: anims[ii],
},
]}>
<Text>{text}</Text>
</Animated.View>
))}
</View>
);
}
export default ({
title: 'Composite Animations with Easing',
name: 'compositeAnimationsWithEasing',
description: ('Sequence, parallel, delay, and ' +
'stagger with different easing functions.': string),
render: function(): React.Node {
const anims = [1, 2, 3].map(() => new Animated.Value(0));
return (
<View>
<RNTesterButton
onPress={() => {
Animated.sequence([
// One after the other
Animated.timing(anims[0], {
toValue: 200,
// $FlowFixMe[method-unbinding]
easing: Easing.linear,
useNativeDriver: false,
}),
Animated.delay(400), // Use with sequence
Animated.timing(anims[0], {
toValue: 0,
// Springy
easing: Easing.elastic(2),
useNativeDriver: false,
}),
Animated.delay(400),
Animated.stagger(
200,
anims
.map(anim =>
Animated.timing(anim, {
toValue: 200,
useNativeDriver: false,
}),
)
.concat(
anims.map(anim =>
Animated.timing(anim, {
toValue: 0,
useNativeDriver: false,
}),
),
),
),
Animated.delay(400),
Animated.parallel(
[
// $FlowFixMe[method-unbinding]
Easing.inOut(Easing.quad), // Symmetric
Easing.back(1.5), // Goes backwards first
Easing.ease, // Default bezier
].map((easing, ii) =>
Animated.timing(anims[ii], {
toValue: 320,
// $FlowFixMe[method-unbinding]
easing,
duration: 3000,
useNativeDriver: false,
}),
),
),
Animated.delay(400),
Animated.stagger(
200,
anims.map(anim =>
Animated.timing(anim, {
toValue: 0,
// Like a ball
// $FlowFixMe[method-unbinding]
easing: Easing.bounce,
duration: 2000,
useNativeDriver: false,
}),
),
),
]).start();
}}>
Press to Animate
</RNTesterButton>
{['Composite', 'Easing', 'Animations!'].map((text, ii) => (
<Animated.View
key={text}
style={[
styles.content,
{
left: anims[ii],
},
]}>
<Text>{text}</Text>
</Animated.View>
))}
</View>
);
},
expect:
'The 3 views will animate their `left` position based on their animation configurations.',
render: () => <CompositeAnimationsWithEasingExample />,
}: RNTesterModuleExample);

Просмотреть файл

@ -12,68 +12,86 @@ import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
import type {CompositeAnimation} from 'react-native/Libraries/Animated/AnimatedMock';
import * as React from 'react';
import RNTesterButton from '../../components/RNTesterButton';
import RNTConfigurationBlock from '../../components/RNTConfigurationBlock';
import ToggleNativeDriver from './utils/ToggleNativeDriver';
import {Text, StyleSheet, View, Animated, FlatList} from 'react-native';
type Props = $ReadOnly<{||}>;
const leftToRightTimingConfig = {
const leftToRightTimingConfig = useNativeDriver => ({
toValue: 200,
useNativeDriver: true,
};
const rightToLeftTimingConfig = {
useNativeDriver,
});
const rightToLeftTimingConfig = useNativeDriver => ({
toValue: 0,
useNativeDriver: true,
};
useNativeDriver,
});
const items = [
{
title: 'Parallel',
compositeAnimation: values =>
compositeAnimation: (values, useNativeDriver) =>
Animated.sequence([
Animated.parallel(
values.map(value => Animated.timing(value, leftToRightTimingConfig)),
values.map(value =>
Animated.timing(value, leftToRightTimingConfig(useNativeDriver)),
),
),
Animated.parallel(
values.map(value => Animated.timing(value, rightToLeftTimingConfig)),
values.map(value =>
Animated.timing(value, rightToLeftTimingConfig(useNativeDriver)),
),
),
]),
},
{
title: 'Sequence',
compositeAnimation: values =>
compositeAnimation: (values, useNativeDriver) =>
Animated.sequence([
Animated.sequence(
values.map(value => Animated.timing(value, leftToRightTimingConfig)),
values.map(value =>
Animated.timing(value, leftToRightTimingConfig(useNativeDriver)),
),
),
Animated.sequence(
values.map(value => Animated.timing(value, rightToLeftTimingConfig)),
values.map(value =>
Animated.timing(value, rightToLeftTimingConfig(useNativeDriver)),
),
),
]),
},
{
title: 'Stagger',
compositeAnimation: values =>
compositeAnimation: (values, useNativeDriver) =>
Animated.sequence([
Animated.stagger(
150,
values.map(value => Animated.timing(value, leftToRightTimingConfig)),
values.map(value =>
Animated.timing(value, leftToRightTimingConfig(useNativeDriver)),
),
),
Animated.stagger(
150,
values.map(value => Animated.timing(value, rightToLeftTimingConfig)),
values.map(value =>
Animated.timing(value, rightToLeftTimingConfig(useNativeDriver)),
),
),
]),
},
{
title: 'Delay',
compositeAnimation: values =>
compositeAnimation: (values, useNativeDriver) =>
Animated.sequence([
Animated.delay(2000),
Animated.parallel(
values.map(value => Animated.timing(value, leftToRightTimingConfig)),
values.map(value =>
Animated.timing(value, leftToRightTimingConfig(useNativeDriver)),
),
),
Animated.delay(2000),
Animated.parallel(
values.map(value => Animated.timing(value, rightToLeftTimingConfig)),
values.map(value =>
Animated.timing(value, rightToLeftTimingConfig(useNativeDriver)),
),
),
]),
},
@ -82,9 +100,14 @@ const items = [
function ComposingExampleItem({
title,
compositeAnimation,
useNativeDriver,
}: {
title: string,
compositeAnimation: (values: Animated.Value[]) => CompositeAnimation,
compositeAnimation: (
values: Animated.Value[],
useNativeDriver: boolean,
) => CompositeAnimation,
useNativeDriver: boolean,
}): React.Node {
const boxes = [0, 1, 2, 3, 4];
const xTranslations = React.useRef(boxes.map(() => new Animated.Value(0)))
@ -96,7 +119,7 @@ function ComposingExampleItem({
<Text style={styles.itemTitle}>{title}</Text>
<RNTesterButton
onPress={() => {
compositeAnimation(xTranslations).start();
compositeAnimation(xTranslations, useNativeDriver).start();
}}>
Animate
</RNTesterButton>
@ -119,17 +142,27 @@ function ComposingExampleItem({
}
function ComposingExample(props: Props): React.Node {
const [useNativeDriver, setUseNativeDriver] = React.useState(false);
return (
<FlatList
data={items}
renderItem={({item}) => (
<ComposingExampleItem
key={item.title}
title={item.title}
compositeAnimation={item.compositeAnimation}
<>
<RNTConfigurationBlock>
<ToggleNativeDriver
value={useNativeDriver}
onValueChange={setUseNativeDriver}
/>
)}
/>
</RNTConfigurationBlock>
<FlatList
data={items}
renderItem={({item}) => (
<ComposingExampleItem
key={item.title}
title={item.title}
compositeAnimation={item.compositeAnimation}
useNativeDriver={useNativeDriver}
/>
)}
/>
</>
);
}

Просмотреть файл

@ -11,7 +11,9 @@
import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
import * as React from 'react';
import RNTesterButton from '../../components/RNTesterButton';
import ToggleNativeDriver from './utils/ToggleNativeDriver';
import {Text, StyleSheet, View, Animated} from 'react-native';
import RNTConfigurationBlock from '../../components/RNTConfigurationBlock';
const styles = StyleSheet.create({
content: {
@ -25,7 +27,13 @@ const styles = StyleSheet.create({
},
});
function FadeInView({children}: {children: React.Node}) {
function FadeInView({
useNativeDriver,
children,
}: {
useNativeDriver: boolean,
children: React.Node,
}) {
//opacity 0
const [fadeAnim, setFadeAnim] = React.useState(() => new Animated.Value(0));
React.useEffect(() => {
@ -39,10 +47,10 @@ function FadeInView({children}: {children: React.Node}) {
// Configuration
duration: 2000,
useNativeDriver: false,
useNativeDriver,
},
).start(); // Don't forget start!
}, [fadeAnim]);
}, [fadeAnim, useNativeDriver]);
return (
<Animated.View // Special animatable View
@ -56,13 +64,20 @@ function FadeInView({children}: {children: React.Node}) {
function FadeInExample(): React.Node {
const [show, setShow] = React.useState(true);
const [useNativeDriver, setUseNativeDriver] = React.useState(false);
return (
<View>
<RNTConfigurationBlock>
<ToggleNativeDriver
value={useNativeDriver}
onValueChange={setUseNativeDriver}
/>
</RNTConfigurationBlock>
<RNTesterButton testID="toggle-button" onPress={() => setShow(!show)}>
Press to {show ? 'Hide' : 'Show'}
</RNTesterButton>
{show && (
<FadeInView>
<FadeInView useNativeDriver={useNativeDriver}>
<View testID="fade-in-view" style={styles.content}>
<Text>FadeInView</Text>
</View>

Просмотреть файл

@ -12,7 +12,9 @@ import RNTesterButton from '../../components/RNTesterButton';
import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
import {Animated, StyleSheet, Text, View} from 'react-native';
import * as React from 'react';
import {useEffect, useState} from 'react';
import {useEffect} from 'react';
import ToggleNativeDriver from './utils/ToggleNativeDriver';
import RNTConfigurationBlock from '../../components/RNTConfigurationBlock';
export default ({
title: 'Looping Example',
@ -21,19 +23,25 @@ export default ({
render: () => <LoopingExample />,
}: RNTesterModuleExample);
function LoopingExample(props: {}): React.Node {
const [running, setRunning] = useState(false);
const [opacity] = useState(() => new Animated.Value(1));
const [scale] = useState(() => new Animated.Value(1));
function LoopingView({
useNativeDriver,
running,
}: {
useNativeDriver: boolean,
running: boolean,
}) {
const opacity = React.useMemo(() => new Animated.Value(1), []);
const scale = React.useMemo(() => new Animated.Value(1), []);
useEffect(() => {
if (!running) {
return;
}
const options = {
duration: 1000,
toValue: 0,
useNativeDriver: true,
useNativeDriver,
};
const animation = Animated.loop(
Animated.parallel([
@ -42,19 +50,42 @@ function LoopingExample(props: {}): React.Node {
]),
);
animation.start();
return () => {
animation.reset();
};
}, [opacity, running, scale]);
}, [opacity, scale, running, useNativeDriver]);
return (
<Animated.View style={[styles.view, {opacity, transform: [{scale}]}]}>
<Text>Looping!</Text>
</Animated.View>
);
}
function LoopingExample(props: {}): React.Node {
const [running, setRunning] = React.useState(false);
const [useNativeDriver, setUseNativeDriver] = React.useState(false);
return (
<View>
<RNTConfigurationBlock>
<ToggleNativeDriver
value={useNativeDriver}
onValueChange={value => {
setRunning(false);
setUseNativeDriver(value);
}}
/>
</RNTConfigurationBlock>
<RNTesterButton onPress={() => setRunning(!running)}>
Press to {running ? 'Reset' : 'Start'}
</RNTesterButton>
<Animated.View style={[styles.view, {opacity, transform: [{scale}]}]}>
<Text>Looping!</Text>
</Animated.View>
<LoopingView
key={`looping-view-${useNativeDriver ? 'native' : 'js'}-driver`}
useNativeDriver={useNativeDriver}
running={running}
/>
</View>
);
}

Просмотреть файл

@ -12,6 +12,8 @@ import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
import * as React from 'react';
import RNTesterButton from '../../components/RNTesterButton';
import {Text, StyleSheet, View, Animated} from 'react-native';
import RNTConfigurationBlock from '../../components/RNTConfigurationBlock';
import ToggleNativeDriver from './utils/ToggleNativeDriver';
const containerWidth = 200;
const boxSize = 50;
@ -53,15 +55,16 @@ const styles = StyleSheet.create({
type Props = $ReadOnly<{||}>;
function MovingBoxExample(props: Props): React.Node {
function MovingBoxView({useNativeDriver}: {useNativeDriver: boolean}) {
const x = React.useRef(new Animated.Value(0));
const [update, setUpdate] = React.useState(0);
const [boxVisible, setBoxVisible] = React.useState(true);
const moveTo = (pos: number) => {
Animated.timing(x.current, {
toValue: pos,
duration: 1000,
useNativeDriver: true,
useNativeDriver,
}).start();
};
@ -71,12 +74,12 @@ function MovingBoxExample(props: Props): React.Node {
const toggleText = boxVisible ? 'Hide' : 'Show';
const onReset = () => {
x.current.resetAnimation();
setUpdate(update + 1);
};
return (
<View style={styles.container}>
{boxVisible ? (
<View style={styles.boxContainer}>
<View style={styles.boxContainer}>
{boxVisible ? (
<Animated.View
testID="moving-view"
style={[
@ -85,12 +88,10 @@ function MovingBoxExample(props: Props): React.Node {
{transform: [{translateX: x.current}]},
]}
/>
</View>
) : (
<View style={styles.boxContainer}>
) : (
<Text>The box view is not being rendered</Text>
</View>
)}
)}
</View>
<View style={styles.buttonsContainer}>
<RNTesterButton testID="move-left-button" onPress={() => moveTo(0)}>
{'<-'}
@ -107,10 +108,31 @@ function MovingBoxExample(props: Props): React.Node {
);
}
function MovingBoxExample(props: Props): React.Node {
const [useNativeDriver, setUseNativeDriver] = React.useState(false);
return (
<>
<RNTConfigurationBlock>
<ToggleNativeDriver
value={useNativeDriver}
onValueChange={setUseNativeDriver}
/>
</RNTConfigurationBlock>
<MovingBoxView
key={`moving-box-view-${useNativeDriver ? 'native' : 'js'}-driver`}
useNativeDriver={useNativeDriver}
/>
</>
);
}
export default ({
title: 'Moving box example',
name: 'movingView',
description:
'Click arrow buttons to move the box. Then hide the box and reveal it again. The box will stay its last position. Reset will reset the animation to its starting position',
'Click arrow buttons to move the box. Hide will remove the box from layout.',
expect:
'During animation, removing box from layout will stop the animation and box will stay in its current position.\nStarting animation when box is not rendered and rendering mid-way does not affect animation.\nReset will reset the animation to its starting position.',
render: (): React.Node => <MovingBoxExample />,
}: RNTesterModuleExample);

Просмотреть файл

@ -12,6 +12,8 @@ import * as React from 'react';
import RNTesterButton from '../../components/RNTesterButton';
import {Animated, View, StyleSheet} from 'react-native';
import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
import RNTConfigurationBlock from '../../components/RNTConfigurationBlock';
import ToggleNativeDriver from './utils/ToggleNativeDriver';
const styles = StyleSheet.create({
rotatingImage: {
@ -20,27 +22,28 @@ const styles = StyleSheet.create({
},
});
function RotatingImagesExample(): React.Node {
const anim = React.useRef(new Animated.Value(0));
function RotatingImagesView({useNativeDriver}: {useNativeDriver: boolean}) {
const anim = new Animated.Value(0);
const rotatingAnimation = Animated.spring(anim, {
// Returns to the start
toValue: 0,
// Velocity makes it move
velocity: 3,
// Slow
tension: -10,
// Oscillate a lot
friction: 1,
useNativeDriver,
});
return (
<View>
<>
<RNTesterButton
onPress={() => {
Animated.spring(anim.current, {
// Returns to the start
toValue: 0,
// Velocity makes it move
velocity: 3,
// Slow
tension: -10,
// Oscillate a lot
friction: 1,
useNativeDriver: false,
}).start();
rotatingAnimation.start();
}}>
Press to Spin it!
</RNTesterButton>
@ -51,19 +54,19 @@ function RotatingImagesExample(): React.Node {
{
transform: [
{
scale: anim.current.interpolate({
scale: anim.interpolate({
inputRange: [0, 1],
outputRange: ([1, 10]: $ReadOnlyArray<number>),
}),
},
{
translateX: anim.current.interpolate({
translateX: anim.interpolate({
inputRange: [0, 1],
outputRange: ([0, 100]: $ReadOnlyArray<number>),
}),
},
{
rotate: anim.current.interpolate({
rotate: anim.interpolate({
inputRange: [0, 1],
outputRange: ([
'0deg',
@ -75,6 +78,25 @@ function RotatingImagesExample(): React.Node {
},
]}
/>
</>
);
}
function RotatingImagesExample(): React.Node {
const [useNativeDriver, setUseNativeDriver] = React.useState(false);
return (
<View>
<RNTConfigurationBlock>
<ToggleNativeDriver
value={useNativeDriver}
onValueChange={setUseNativeDriver}
/>
</RNTConfigurationBlock>
<RotatingImagesView
key={`rotating-images-view-${useNativeDriver ? 'native' : 'js'}-driver`}
useNativeDriver={useNativeDriver}
/>
</View>
);
}
@ -83,5 +105,7 @@ export default ({
title: 'Rotating Images',
name: 'rotatingImages',
description: 'Simple Animated.Image rotation.',
expect:
'Transform animation on image in scale, rotation, and translation. JS driver will ignore any calls to `start` on running animation. Native driver will re-start the animation.',
render: RotatingImagesExample,
}: RNTesterModuleExample);

Просмотреть файл

@ -12,6 +12,8 @@ import * as React from 'react';
import RNTesterButton from '../../components/RNTesterButton';
import {Text, StyleSheet, View, Animated} from 'react-native';
import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
import RNTConfigurationBlock from '../../components/RNTConfigurationBlock';
import ToggleNativeDriver from './utils/ToggleNativeDriver';
const styles = StyleSheet.create({
content: {
@ -25,71 +27,97 @@ const styles = StyleSheet.create({
},
});
function TransformBounceView({useNativeDriver}: {useNativeDriver: boolean}) {
const anim = new Animated.Value(0);
const bounceAnimation = Animated.spring(anim, {
// Returns to the start
toValue: 0,
// Velocity makes it move
velocity: 3,
// Slow
tension: -10,
// Oscillate a lot
friction: 1,
useNativeDriver,
});
return (
<>
<RNTesterButton
onPress={() => {
bounceAnimation.start();
}}>
Press to Fling it!
</RNTesterButton>
<Animated.View
style={[
styles.content,
{
transform: [
// Array order matters
{
scale: anim.interpolate({
inputRange: [0, 1],
outputRange: ([1, 4]: $ReadOnlyArray<number>),
}),
},
{
translateX: anim.interpolate({
inputRange: [0, 1],
outputRange: ([0, 500]: $ReadOnlyArray<number>),
}),
},
{
rotate: anim.interpolate({
inputRange: [0, 1],
outputRange: ([
'0deg',
'360deg', // 'deg' or 'rad'
]: $ReadOnlyArray<string>),
}),
},
],
},
]}>
<Text>Transforms!</Text>
</Animated.View>
</>
);
}
function TransformBounceExample(): React.Node {
const [useNativeDriver, setUseNativeDriver] = React.useState(false);
return (
<View>
<RNTConfigurationBlock>
<ToggleNativeDriver
value={useNativeDriver}
onValueChange={setUseNativeDriver}
/>
</RNTConfigurationBlock>
<TransformBounceView
key={`transform-bounce-view-${
useNativeDriver ? 'native' : 'js'
}-driver`}
useNativeDriver={useNativeDriver}
/>
</View>
);
}
export default ({
title: 'Transform Bounce',
name: 'transformBounce',
expect: 'Transform animation on rotation, translation, scale of View',
description: ('One `Animated.Value` is driven by a ' +
'spring with custom constants and mapped to an ' +
'ordered set of transforms. Each transform has ' +
'an interpolation to convert the value into the ' +
'right range and units.': string),
render: function(): React.Node {
const anim = new Animated.Value(0);
return (
<View>
<RNTesterButton
onPress={() => {
Animated.spring(anim, {
// Returns to the start
toValue: 0,
// Velocity makes it move
velocity: 3,
// Slow
tension: -10,
// Oscillate a lot
friction: 1,
useNativeDriver: false,
}).start();
}}>
Press to Fling it!
</RNTesterButton>
<Animated.View
style={[
styles.content,
{
transform: [
// Array order matters
{
scale: anim.interpolate({
inputRange: [0, 1],
outputRange: ([1, 4]: $ReadOnlyArray<number>),
}),
},
{
translateX: anim.interpolate({
inputRange: [0, 1],
outputRange: ([0, 500]: $ReadOnlyArray<number>),
}),
},
{
rotate: anim.interpolate({
inputRange: [0, 1],
outputRange: ([
'0deg',
'360deg', // 'deg' or 'rad'
]: $ReadOnlyArray<string>),
}),
},
],
},
]}>
<Text>Transforms!</Text>
</Animated.View>
</View>
);
},
render: () => <TransformBounceExample />,
}: RNTesterModuleExample);

Просмотреть файл

@ -0,0 +1,44 @@
/**
* 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.
*
* @flow strict-local
* @format
*/
import {View, Text, StyleSheet, Switch} from 'react-native';
import * as React from 'react';
type Props = {
value: boolean,
onValueChange: $ElementType<
React.ElementConfig<typeof Switch>,
'onValueChange',
>,
};
export default function ToggleNativeDriver({
value,
onValueChange,
}: Props): React.Node {
return (
<View style={styles.row}>
<Text>Use Native Driver</Text>
<Switch
testID="toggle-use-native-driver"
onValueChange={onValueChange}
value={value}
/>
</View>
);
}
const styles = StyleSheet.create({
row: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
});