• 主页
  • 标签
  • 归档
  • 搜索
  • Github

March 15, 2021

Animated Transition in React Native!

本文为转载文章, 仅用于自己的知识管理收集, 如果涉及侵权,请联系 suziwen1@gmail.com,会第一时间删除
收集该文章,并非代表本人支持文中观点,只是觉得文章内容容易引起思考,讨论,有它自有的价值

转载自: https://medium.com/react-native-motion/transition-challenge-9bc9fdef56c7

Recently I’ve tried to get an inspiration for a next animation challenge. And here we go — created by Ivan Parfenov. I was curious if I am able to do this transition effect with React Native. You can check out a result on my expo account! Why we even need the animations like these? Read Good to great UI animation tips by Pablo Stanley.


For PLΛTES by Ivan Parfenov

We can see there is a couple of animations. Toolbar tile (show/hide), bottom bar (show/hide), move a selected item, hide all others, show detail items and maybe even more.


Timeline of animations

The hard thing about the transition is to synchronize all of those animations. We can’t really unmount the List Page and show the Detail Page because we need to wait till all animations are done. Also, I am a fan of having a clean code. Easy to maintenance. If you have ever tried to implement an animation to your project, the code usually gets messy. Full of helper variables, crazy calculations, etc. That’s why I would like to introduce react-native-motion.


An idea of react-native-motion

Can you see the animation of toolbar’s title? You just need to move the title a bit and animate an opacity to zero/one. No big deal! But because of that, you need to write a code like this. Even before you actually start to write UI for that component.

  1. 1class TranslateYAndOpacity extends PureComponent { 

  2. 2 constructor(props) { 

  3. 3 // ... 

  4. 4 this.state = { 

  5. 5 opacityValue: new Animated.Value(opacityMin), 

  6. 6 translateYValue: new Animated.Value(translateYMin), 

  7. 7 }; 

  8. 8 // ... 

  9. 9 } 

  10. 10 componentDidMount() { 

  11. 11 // ... 

  12. 12 this.show(this.props); 

  13. 13 // ... 

  14. 14 } 

  15. 15 componentWillReceiveProps(nextProps) { 

  16. 16 if (!this.props.isHidden && nextProps.isHidden) { 

  17. 17 this.hide(nextProps); 

  18. 18 } 

  19. 19 if (this.props.isHidden && !nextProps.isHidden) { 

  20. 20 this.show(nextProps); 

  21. 21 } 

  22. 22 } 

  23. 23 show(props) { 

  24. 24 // ... 

  25. 25 Animated.parallel([ 

  26. 26 Animated.timing(opacityValue, { /* ... */ }), 

  27. 27 Animated.timing(translateYValue, { /* ... */ }), 

  28. 28 ]).start(); 

  29. 29 } 

  30. 30 hide(props) { 

  31. 31 // ... 

  32. 32 Animated.parallel([ 

  33. 33 Animated.timing(opacityValue, { /* ... */ }), 

  34. 34 Animated.timing(translateYValue, { /* ... */ }), 

  35. 35 ]).start(); 

  36. 36 } 

  37. 37 render() { 

  38. 38 const { opacityValue, translateYValue } = this.state; 

  39. 39 

  40. 40 const animatedStyle = { 

  41. 41 opacity: opacityValue, 

  42. 42 transform: [{ translateY: translateYValue }], 

  43. 43 }; 

  44. 44 

  45. 45 return ( 

  46. 46 <Animated.View style={animatedStyle}>{this.props.children}</Animated.View> 

  47. 47 ); 

  48. 48 } 

  49. 49} 

Now let’s take a look how we can use react-native-motion for this. I know the animations are quite often very specific. And I know React Native provides very powerful Animated API. Anyway, it would be great to have a library with basic animations.

  1. 1import { TranslateYAndOpacity } from 'react-native-motion'; 

  2. 2 

  3. 3class ToolbarTitle extends PureComponent { 

  4. 4 render() { 

  5. 5 return ( 

  6. 6 <TranslateYAndOpacity duration={250}> 

  7. 7 <View> 

  8. 8 // ... 

  9. 9 </View> 

  10. 10 </TranslateYAndOpacity> 

  11. 11 ); 

  12. 12 } 

  13. 13} 

Shared element

The biggest problem of this challenge was moving of selected list item. The item that is shared between List Page and Detail Page. How to move the item from FlatList to the top of Detail’s Page when the element is actually not absolutely positioned? It is quite easy with react-native-motion.

  1. 1// List items page with source of SharedElement 

  2. 2import { SharedElement } from 'react-native-motion'; 

  3. 3 

  4. 4class ListPage extends Component { 

  5. 5 render() { 

  6. 6 return ( 

  7. 7 <SharedElement id="source"> 

  8. 8 <View>{listItemNode}</View> 

  9. 9 </SharedElement> 

  10. 10 ); 

  11. 11 } 

  12. 12} 

We specified source element of the SharedElement on List Page. Now we need to do almost the same for destination element on the Detail Page. To know the position where we want to move the shared element.

  1. 1// Detail page with a destination shared element 

  2. 2import { SharedElement } from 'react-native-motion'; 

  3. 3 

  4. 4class DetailPage extends Component { 

  5. 5 render() { 

  6. 6 return ( 

  7. 7 <SharedElement sourceId="source"> 

  8. 8 <View>{listItemNode}</View> 

  9. 9 </SharedElement> 

  10. 10 ); 

  11. 11 } 

  12. 12} 

Where is the magic?

How can we move a relatively positioned element from one page to the another one? Actually, we can’t. The SharedElement works like this:

  • get a position of the source element
  • get position of the destination element (obviously, without this step the animation can’t be initiated)
  • create a clone of the shared element (The magic!)
  • render a new layer above the screen
  • render the cloned element that will cover the source element (in his position)
  • initiate move to the destination position
  • once the destination position was reached, remove the cloned element


You can probably imagine there are 3 elements of the same React Node at the same moment. That’s because List Page is covered up by Detail Page during that moving animation. That’s why we can see all 3 elements. But we want to create an illusion that we actually moving the original source item.


SharedElement timeline

You can see point A and point B. That’s a time period when the moving is performing. You can also see the SharedElement fires some useful events. In this case, we use WillStart and DidFinish events. It is up to you to set an opacity for source and destination element to 0 when a moving to destination was initiated, and back to 1 for destination element once the animation was finished.

What do you think?

There is still work on react-native-motion. It is definitely not a final and stable version of this library. But it is a good start I hope :) I would love to hear what do you think about that!

Tagged with 文章 | 转载 | 技术 | react-native | 前端
Time Flies, No Time for Nuts
Copyright © 2020 suziwen
Build with  Gatsbyjs  and  Sculpting theme