/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow * @format */ 'use strict'; import type {RNTesterModuleExample} from '../../types/RNTesterTypes'; import type AnimatedValue from 'react-native/Libraries/Animated/nodes/AnimatedValue'; import RNTesterSettingSwitchRow from '../../components/RNTesterSettingSwitchRow'; import RNTesterText from '../../components/RNTesterText'; import useJsStalls from '../../utils/useJsStalls'; import React from 'react'; import { Animated, StyleSheet, TouchableWithoutFeedback, View, } from 'react-native'; class Tester extends React.Component<$FlowFixMe, $FlowFixMe> { state: any | {js: AnimatedValue, native: AnimatedValue} = { native: new Animated.Value(0), js: new Animated.Value(0), }; current = 0; onPress = () => { const animConfig = this.current && this.props.reverseConfig ? this.props.reverseConfig : this.props.config; this.current = this.current ? 0 : 1; const config: Object = { ...animConfig, toValue: this.current, }; Animated[this.props.type](this.state.native, { ...config, useNativeDriver: true, }).start(); Animated[this.props.type](this.state.js, { ...config, useNativeDriver: false, }).start(); }; render(): React.Node { return ( Native: {this.props.children(this.state.native)} JavaScript{':'} {this.props.children(this.state.js)} ); } } class ValueListenerExample extends React.Component<{...}, $FlowFixMe> { state: any | {anim: AnimatedValue, progress: number} = { anim: new Animated.Value(0), progress: 0, }; _current = 0; componentDidMount() { this.state.anim.addListener(e => this.setState({progress: e.value})); } componentWillUnmount() { this.state.anim.removeAllListeners(); } _onPress = () => { this._current = this._current ? 0 : 1; const config = { duration: 1000, toValue: this._current, }; Animated.timing(this.state.anim, { ...config, useNativeDriver: true, }).start(); }; render(): React.Node { return ( Value: {this.state.progress} ); } } class LoopExample extends React.Component<{...}, $FlowFixMe> { state: any | {value: AnimatedValue} = { value: new Animated.Value(0), }; componentDidMount() { Animated.loop( Animated.timing(this.state.value, { toValue: 1, duration: 5000, useNativeDriver: true, }), ).start(); } render(): React.Node { return ( ); } } const InternalSettings = () => { const { state, onDisableForceJsStalls, onEnableForceJsStalls, onEnableJsStallsTracking, onDisableJsStallsTracking, } = useJsStalls(); const {stallIntervalId, filteredStall, busyTime, tracking} = state; return ( {tracking && ( {`JS Stall filtered: ${Math.round(filteredStall)}, `} {`last: ${busyTime !== null ? busyTime.toFixed(8) : ''}`} )} ); }; class EventExample extends React.Component<{...}, $FlowFixMe> { state: any | {anim: AnimatedValue} = { anim: new Animated.Value(0), }; render(): React.Node { return ( Scroll me sideways! ); } } class TrackingExample extends React.Component<$FlowFixMe, $FlowFixMe> { state: | any | { js: AnimatedValue, native: AnimatedValue, toJS: AnimatedValue, toNative: AnimatedValue, } = { native: new Animated.Value(0), toNative: new Animated.Value(0), js: new Animated.Value(0), toJS: new Animated.Value(0), }; componentDidMount() { // we configure spring to take a bit of time to settle so that the user // have time to click many times and see "toValue" getting updated and const longSettlingSpring = { tension: 20, friction: 0.5, }; Animated.spring(this.state.native, { ...longSettlingSpring, toValue: this.state.toNative, useNativeDriver: true, }).start(); Animated.spring(this.state.js, { ...longSettlingSpring, toValue: this.state.toJS, useNativeDriver: false, }).start(); } onPress = () => { // select next value to be tracked by random const nextValue = Math.random() * 200; this.state.toNative.setValue(nextValue); this.state.toJS.setValue(nextValue); }; renderBlock = ( anim: any | AnimatedValue, dest: any | AnimatedValue, ): Array => [ , , ]; render(): React.Node { return ( Native: {this.renderBlock(this.state.native, this.state.toNative)} JavaScript{':'} {this.renderBlock(this.state.js, this.state.toJS)} ); } } const styles = StyleSheet.create({ row: { padding: 10, zIndex: 1, }, block: { width: 50, height: 50, backgroundColor: 'blue', }, line: { position: 'absolute', left: 35, top: 0, bottom: 0, width: 1, backgroundColor: 'red', }, }); exports.framework = 'React'; exports.title = 'Native Animated Example'; exports.category = 'UI'; exports.description = 'Test out Native Animations'; exports.examples = [ { title: 'Multistage With Multiply and rotation', render: function (): React.Node { return ( {anim => ( )} ); }, }, { title: 'Multistage With Multiply', render: function (): React.Node { return ( {anim => ( )} ); }, }, { title: 'Multistage With Subtract', render: function (): React.Node { return ( {anim => ( )} ); }, }, { title: 'Scale interpolation with clamping', render: function (): React.Node { return ( {anim => ( )} ); }, }, { title: 'Opacity with delay', render: function (): React.Node { return ( {anim => ( )} ); }, }, { title: 'Rotate interpolation', render: function (): React.Node { return ( {anim => ( )} ); }, }, { title: 'translateX => Animated.spring (bounciness/speed)', render: function (): React.Node { return ( {anim => ( )} ); }, }, { title: 'translateX => Animated.spring (stiffness/damping/mass)', render: function (): React.Node { return ( {anim => ( )} ); }, }, { title: 'translateX => Animated.decay', render: function (): React.Node { return ( {anim => ( )} ); }, }, { title: 'Animated value listener', render: function (): React.Node { return ; }, }, { title: 'Animated loop', render: function (): React.Node { return ; }, }, { title: 'Animated events', render: function (): React.Node { return ; }, }, { title: 'Animated Tracking - tap me many times', render: function (): React.Node { return ; }, }, { title: 'Internal Settings', render: function (): React.Node { return ; }, }, ] as Array;