Slide 1

Slide 1 text

Declarative future of gestures and animations in React Native Krzysztof Magiera (@kzzzf)

Slide 2

Slide 2 text

Animations hold

Slide 3

Slide 3 text

Animations skip

Slide 4

Slide 4 text

Animations t VSync

Slide 5

Slide 5 text

Animations t VSync ?

Slide 6

Slide 6 text

Animations UI thread JS thread requestAnimationFrame clb

Slide 7

Slide 7 text

Animations UI thread JS queue background thread readFromStorage HTTPResponse

Slide 8

Slide 8 text

Animations UI thread JS queue background thread readFromStorage HTTPResponse

Slide 9

Slide 9 text

Perf monitor

Slide 10

Slide 10 text

Animated state = { fade: new Animated.Value(0) }; 1. Create value 2. Hook it up as a view attribute Animated.timing( this.state.fade, { toValue: 1, } ).start(); 3. Animate value 4. Or attach it to an event 5. Combine/process values const fade = Animated.multiply( this.state.factor, this.state.scrollY.interpolate({ inputRange: [0, 300], outputRange: [1, 0] }) );

Slide 11

Slide 11 text

useNativeDriver Animated T-minus 2 years

Slide 12

Slide 12 text

What about gestures?

Slide 13

Slide 13 text

JS responder system ! Show this slide Show this slide

Slide 14

Slide 14 text

JS responder system ! Show this slide Show this slide

Slide 15

Slide 15 text

JS responder system ! TOUCH DOWN TOUCH MOVE TOUCH MOVE TOUCH MOVE TOUCH UP JS Thread UI Thread

Slide 16

Slide 16 text

JS responder system ! TOUCH DOWN TOUCH MOVE TOUCH MOVE TOUCH MOVE TOUCH UP JS Thread UI Thread BUBBLING

Slide 17

Slide 17 text

What about gestures? this._pan = PanResponder.create({ onMoveShouldSetPanResponder: YES, onMoveShouldSetPanResponderCapture: YES, onPanResponderMove: Animated.event( [ null, { dx: this._translateValue } ], { useNativeDriver: false } ) }); DIRECT BUBBLING

Slide 18

Slide 18 text

What about gestures?

Slide 19

Slide 19 text

react-native-gesture-handler 1.0.0 is out! " react-native-gesture-handler https://kmagiera.github.io/react-native-gesture-handler/

Slide 20

Slide 20 text

react-native-gesture-handler Handler Parameters Event attributes Pan minDist, minPointers translationXY, absoluteXY Pinch scale, focalXY, velocity Tap numberOfTaps, maxDuration numberOfPointers Rotation angle, anchorXY, velocity

Slide 21

Slide 21 text

‣Component for each gesture type (pan, pinch, etc) ‣Natively backed “touchables” ‣Declarative API for defining cross handler interactions ‣Extras: drawer, swipeable row, more to come… react-native-gesture-handler

Slide 22

Slide 22 text

react-native-gesture-handler ; DIRECT

Slide 23

Slide 23 text

class Snappable extends Component { translateX = new Animated.Value(0); render() { return ( ); } }

Slide 24

Slide 24 text

class Snappable extends Component { translateX = new Animated.Value(0); render() { return ( ); } }

Slide 25

Slide 25 text

class Snappable extends Component { translateX = new Animated.Value(0); render() { return ( { if (event.nativeEvent.oldState === State.ACTIVE) { // Check if the last state was "ACTIVE" Animated.spring(this.translateX, { toValue: 0, velocity: event.nativeEvent.velocityX, useNativeDriver: true, }).start(); } }}> ); } }

Slide 26

Slide 26 text

DECLARATIVE ALL THE THINGS!!!

Slide 27

Slide 27 text

Side effects

Slide 28

Slide 28 text

IF-ELSE node

Slide 29

Slide 29 text

ImagePreview component challenge ‣ Correctly centred pinch ‣ Pan with inertia ‣ Pan friction on edges ‣ Bouncing from edges ‣ Pinch friction ‣ Bouncing zoom ‣ Pinch&Pan simultaneously

Slide 30

Slide 30 text

ImagePreview component challenge IMPE RATIVE FREE IMPE RATIVE FREE

Slide 31

Slide 31 text

github.com/kmagiera/react-native-reanimated

Slide 32

Slide 32 text

{ // Animated 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), 0) ), ] ); }

Slide 33

Slide 33 text

Clocks export default function decay(clock, state, config) { const lastTime = cond(state.time, state.time, clock); const deltaTime = sub(clock, lastTime); // v0 = v / 1000 // v = v0 * powf(deceleration, dt); // v = v * 1000; // x0 = x; // x = x0 + v0 * deceleration * (1 - powf(deceleration, dt)) / (1 - deceleration) const kv = pow(config.deceleration, deltaTime); const kx = divide( multiply(config.deceleration, sub(1, kv)), sub(1, config.deceleration) ); const v0 = divide(state.velocity, 1000); const v = multiply(v0, kv, 1000); const x = add(state.position, multiply(v0, kx)); return [ set(state.position, x), set(state.velocity, v), set(state.time, clock), cond(lessThan(abs(v), VELOCITY_EPS), set(state.finished, 1)), ]; }

Slide 34

Slide 34 text

Lower level abstraction export const diffClamp = function(a, minVal, maxVal) { const value = new AnimatedValue(); return set( value, min( max( add(cond(defined(value), value, a), diff(a)), minVal ), maxVal ) ); };

Slide 35

Slide 35 text

‣ More generic primitive node types ‣ Can be used to implement Animated compatible API w/o writing specific native code for things like: ‣ Complex nodes such as “diffClamp” ‣ Interactions such as animated value tracking or animation staggering ‣ Conditional evaluation & nodes with side effects ‣ Less native code & more cross platform JS code ‣ No more “useNativeDriver” – all animations runs on UI thread by default Reanimated highlights

Slide 36

Slide 36 text

Thank you! Krzysztof Magiera [email protected] @kzzzf