Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Shared element transition with React Native

Shared element transition with React Native

Narendra N Shetty

September 12, 2017
Tweet

More Decks by Narendra N Shetty

Other Decks in Technology

Transcript

  1. What is Transition? Transition is an animation which guides users

    to focus on what you want Keep Users from getting lost Transitions between different screens involves enter and exit transitions
  2. What is Shared Element Transition? As the name suggest, there

    is a single element being shared and moved from one screen to another during transition
  3. What is Shared Element Transition? As the name suggest, there

    is a single element being shared and moved from one screen to another during transition This emphasizes continuity between transitions and breaks screen boundaries as the user navigates the app. This forces the human eye to focus on the content and its representation
  4. App

  5. Do you really believe that there is a single image

    being shared between the grid and detail screens?
  6. Do you really believe that there is a single image

    being shared between the grid and detail screens? NO! :)
  7. Things to know import { Animated } from 'react-native'; let

    AnimatedValue = new Animated.Value(0);
  8. Things to know import { Animated } from 'react-native'; Animated.timing(AnimatedValue,

    { toValue: 1, duration: 3000 }).start(); let AnimatedValue = new Animated.Value(0);
  9. Things to know import { Animated } from 'react-native'; let

    AnimatedValue = new Animated.Value(0); Animated.timing(AnimatedValue, { toValue: 1, duration: 3000 }).start(); AnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [1, 0] });
  10. Adding Exit Transition Animated.timing(AnimatedValue, { toValue: 1, duration: 3000, }).start();

    Trigger { opacity: AnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [1, 0] }) }
  11. Adding Entry Transition { transform: [{ translateY: AnimatedValue.interpolate({ inputRange: [0,

    0.5, 1], outputRange: [100, 100, 0] }) }] } Animated.timing(AnimatedValue, { toValue: 1, duration: 3000, }).start(); Trigger
  12. Grid Screen Detail Screen Transition Layer x: 0 y: 600

    width: 200 height: 112 x: 0 y: 0 width: 360 height: 300
  13. Grid Screen Detail Screen Transition Layer x: 0 y: 600

    width: 200 height: 112 x: 0 y: 0 width: 360 height: 300
  14. { position: 'absolute', width: AnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [source.width,

    destination.width] }), height: AnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [source.height, destination.height] }) }
  15. { position: 'absolute', width: AnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [source.width,

    destination.width] }), height: AnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [source.height, destination.height] }), left: AnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [source.pageX, destination.pageX] }) }
  16. { position: 'absolute', width: AnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [source.width,

    destination.width] }), height: AnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [source.height, destination.height] }), left: AnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [source.pageX, destination.pageX] }), top: AnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [source.pageY, destination.pageY] }) }
  17. JS thread Native thread Click Uses requestAnimationFrame Generates new input

    value Generates new output value Passed as props to the View View is updated using setNativeProps Passed to Native over the bridge Native View is updated
  18. JS thread Native thread Uses Native Driver Generates new input

    value Generates new output value Serializes animated nodes Native View is updated Click Passed to Native over the bridge
  19. useNativeDriver can only animate non-layout properties, things like transform and

    opacity will work but flexbox and position properties won't. Disadvantage
  20. const sourceAspectRatio = source.width / source.height; const destAspectRatio = dest.width

    / dest.height; if (sourceAspectRatio - destAspectRatio > 0) { // Landscape image } else { // Portrait image }
  21. if (sourceAspectRatio - destAspectRatio > 0) { // Landscape image

    const newWidth = sourceAspectRatio * dest.height; } else { // Portrait image const newHeight = dest.width / sourceAspectRatio; } const sourceAspectRatio = source.width / source.height; const destAspectRatio = dest.width / dest.height;
  22. const sourceAspectRatio = source.width / source.height; const destAspectRatio = dest.width

    / dest.height; if (sourceAspectRatio - destAspectRatio > 0) { // Landscape image } else { // Portrait image }
  23. if (sourceAspectRatio - destAspectRatio > 0) { // Landscape image

    dest.posX -= (newWidth - dest.width) / 2; } else { // Portrait image dest.posY -= (newHeight - dest.height) / 2; } const sourceAspectRatio = source.width / source.height; const destAspectRatio = dest.width / dest.height;
  24. const translateInitX = source.posX + source.width / 2; const translateInitY

    = source.posY + source.height / 2; const translateDestX = dest.posX + dest.width / 2; const translateDestY = dest.posY + dest.height / 2;
  25. const translateInitX = source.posX + source.width / 2; const translateInitY

    = source.posY + source.height / 2; const translateDestX = dest.posX + dest.width / 2; const translateDestY = dest.posY + dest.height / 2; openingInitTranslateX = translateInitX - translateDestX; openingInitTranslateY = translateInitY - translateDestY;
  26. { position: 'absolute', width: destination.width, height: destination.height, left: destination.posX, top:

    destination.posY, transform: [ { translateX: AnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [openingInitTranslateX, 0] }) }, { translateY: AnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [openingInitTranslateY, 0] }) }, { scale: AnimatedValue.interpolate({ inputRange: [0, 1], outputRange: [openingInitScale, 1] }) } ] }
  27. Hiding the source and destination image during transition { opacity:

    AnimatedValue.interpolate({ inputRange: [0.005, 0.01], outputRange: [1, 0] }) }
  28. Hiding the source and destination image during transition { opacity:

    AnimatedValue.interpolate({ inputRange: [0, 0.99, 0.995], outputRange: [0, 0, 1] }) }
  29. <Image click> <back> Animated.timing(AnimatedValue, { toValue: 1, duration: 3000, useNativeDriver:

    true }).start(); Animated.timing(AnimatedValue, { toValue: 0, duration: 3000, useNativeDriver: true }).start();