今天继续更新RN相关的博客。上篇博客详细的聊了RN中关于Flex布局的相关东西,具体请参见《ReactNative之参照具体示例来看RN中的FlexBox布局》。本篇博客继续更新RN的动画部分,博客中的内容依然是依托于具体的示例来进行的。html
下方是官网对RN动画的的一个综述,意思就是说在RN的组件中View、Text、Image 和ScrollView是支持动画的,不过你可使用Animated.createAnimatedComponent()这个方法来建立一个支持动画的组件稍后会介绍到。这些支持动画的组件在使用动画是都差很少,本篇博客中的示例主要以View为主,也会有Text、Image的部分动画。react
Animated
exports four animatable component types:View
,Text
,Image
, andScrollView
, but you can also create your own usingAnimated.createAnimatedComponent()
.react-native
第一部分咱们先从一个简单的Moving动画来入手。这个Moving动画是很是简单的,就是一个View,而后点击这个View,会从一个地方移动到另外一个地方。而后再次点击会回归到原位。下方是效果实现的分析:数组
首先咱们会为View添加一个点击事件,点击View时,从一个位置移到另外一个位置。
再次点击时,会回到上次的一个位置。
在移动时咱们加了一个Bounce的一个动画效果。
下方代码段是上述动画效果的部分代码。代码比较简单:ide
上面这段代码是动画设置的相关代码,下方这块代码是动画使用的相关代码片断。下方是对这段代码的解析:函数
首先是从state中取出了动画值,咱们将该值付给了moveValue。
而后咱们是根据这个 moveValue 经过差值函数建立了一个 toValue的值,这个值就是咱们动画的目标值,也是咱们真正要使用的值。
这个 interpolate() 差值函数负责用来指定 toValue的生成规则, 该函数能够把这个
完整代码片断:oop
1 type States = { 2 moveValue: Animated.Value // 存储动画的值 3 } 4 5 class MoveViewTestComponent extends Component<null, States> { 6 toValue = 0 7 constructor (props) { 8 super(props) 9 this.state = { 10 moveValue: new Animated.Value(0) 11 } 12 } 13 14 pressView = () => { 15 this.toValue = this.toValue === 0 ? 1 : 0 16 Animated.timing( 17 this.state.moveValue, // 初始化从0开始 18 { 19 toValue: this.toValue, // 目标值 20 duration: 1000, // 时间间隔 21 easing: Easing.bounce // 缓动函数 22 } 23 ).start() 24 } 25 26 render () { 27 let { moveValue } = this.state 28 29 let toValue = moveValue.interpolate({ 30 inputRange: [0,1], 31 outputRange: ['10%', '60%'] 32 }) 33 return ( 34 <TouchableOpacity onPress={this.pressView}> 35 <Animated.View // 使用专门的可动画化的View组件 36 style={{ 37 width: 100, 38 height: 50, 39 backgroundColor: 'red', 40 left: toValue, 41 }} 42 > 43 <Text style={{ color: '#fff' }}> Tap Me Move </Text> 44 </Animated.View> 45 </TouchableOpacity> 46 ) 47 } 48 }
上面设设置的left属性,咱们还能够对上述代码进行修改,使用动画来改变每一个角的弧度,具体动画效果以下所示:布局
代码就比较简单了,就是把动画的值直接赋值给咱们的 borderRadius 属性便可。flex
在上面的示例中咱们指定的移动动画的Bounce效果,下方咱们将经过一个示例来看一下Easing中全部的效果,具体动画效果以下所示。从下方的示例中咱们不难看出,每种效果的动画运动轨迹都不一样,咱们在平时开发中能够根据本身的须要来选择相关的效果。固然咱们还能够经过矩阵来定义动画的变换路径,在此就不作过多赘述了。动画
接下来咱们来看一下上述动画实现的一个Demo的设计与实现。
首先咱们定义了一个MoveView组件,也就是对应着上述Demo中的每一个Button,上面可点击可移动的每一个View就是一个MoveView。该View会从外部接收一个easing参数,该参数会被设置为该View的动画效果。具体代码以下所示:
而后咱们建立了一个 TestMoveView 的一个组件,这个组件就是上述演示的内容。在 TestMoveView 中咱们定义了两个数组,第一个数组用来存放每一个按钮的Title, 第二个数组则用来存放相关按钮的动画类型。稍后会用到下方的这两个数组。
下方就是两个比较核心的方法了, 下方是对这两个方法的介绍
第一个 item 方法用来建立一个 MoveView,该View对应的就是上述一个按钮。第一个参数Title就是按钮上的title, 二后边的easing则是动画效果。
在Item方法中咱们给 MoveView 设置了一个ref的属性,该属性的Value值咱们用的是按钮上的Title。设置完这个ref值后,咱们可使用 this.refs 来获取相关key值的对象。稍后咱们会用到。
而后就是 createItem 方法了,该方法负责调用 上面咱们事先建立好的数组,从数组中取出相关的值,而后调用 item 方法建立一系列的 MoveView 放到相关的数组里并返回。
在 Render 方法中咱们就能够调用下方的这个 createItem 方法来建立相关的按钮了。上的图片中能动的按钮都是经过这个 CreateItem 方法来建立的。
最后部分咱们就来看一下 点击Tap Me 按钮所执行的相关方法了,下方的Click就是该方法。 在Click方法中主要作的就是调用 this.refs 方法获取全部可移动的MoveView的对象,而后调用该对象的pressView方法执行相关的动画。全部点击 Tap Me 按钮,下方全部的按钮都会运动。
完整代码:
1 import React,{ Component } from 'react' 2 // import MoveView from './MoveView' 3 import { Animated, Easing, Text, TouchableOpacity, View } from 'react-native' 4 5 type EasingType = (value: number) => number 6 7 export default class TestMoveView extends Component { 8 animatedKey: string[] = [ 9 'linear', 10 'quad', 11 'cubic', 12 'sin', 13 'exp', 14 'bounce', 15 'poly-5', 16 'elastic-2', 17 'back-2', 18 'bezier' 19 ] 20 21 animatedEasingType: EasingType[] = [ 22 Easing.linear, 23 Easing.quad, 24 Easing.cubic, 25 Easing.sin, 26 Easing.exp, 27 Easing.bounce, 28 Easing.poly(5), 29 Easing.elastic(2), 30 Easing.back(2), 31 Easing.bezier(0,1.6, 1,-0.67) 32 ] 33 34 click = () => { 35 for (let i = 0; i < this.animatedKey.length; i++) { 36 this.refs[this.animatedKey[i]].pressView() 37 } 38 } 39 40 item = (title: string, easing: EasingType) => { 41 return ( 42 <MoveView 43 easing= {easing} 44 ref = {title}> 45 <Text style={{ fontSize: 17, textAlign: 'center' }}> 46 {title} 47 </Text> 48 </MoveView> 49 ) 50 } 51 52 createItems = () => { 53 let items = [] 54 for (let i = 0; i < this.animatedKey.length; i++) { 55 items.push(this.item(this.animatedKey[i], this.animatedEasingType[i])) 56 } 57 return items 58 } 59 60 render () { 61 console.log('lizelu') 62 return ( 63 <View style={{ flex: 1, justifyContent: 'center' }}> 64 <TouchableOpacity onPress={this.click}> 65 <Text>Tap Me</Text> 66 </TouchableOpacity> 67 { this.createItems() } 68 </View> 69 ) 70 } 71 } 72 73 // MoveView 74 75 type MoveViewProps = { 76 easing?: (value: number) => number 77 } 78 79 class MoveView extends Component<MoveViewProps> { 80 toValue = 0 81 state = { 82 moveValue: new Animated.Value(0) 83 } 84 85 pressView = () => { 86 this.toValue = this.toValue === 0 ? 1 : 0 87 Animated.timing( 88 this.state.moveValue, // 初始化从0开始 89 { 90 toValue: this.toValue, // 目标值 91 duration: 1000, // 时间间隔 92 easing: this.props.easing // 动画效果 93 } 94 ).start() 95 } 96 97 render () { 98 let { moveValue } = this.state 99 let toValue = moveValue.interpolate({ 100 inputRange: [0,1], 101 outputRange: ['10%', '70%'] 102 }) 103 return ( 104 <TouchableOpacity onPress={this.pressView}> 105 <Animated.View // 使用专门的可动画化的View组件 106 style={[{ 107 width: 80, 108 height: 30, 109 backgroundColor: 'powderblue', 110 margin: 2, 111 left: toValue // 动画的目标值 112 }]} 113 > 114 {this.props.children} 115 </Animated.View> 116 </TouchableOpacity> 117 ) 118 } 119 }
接下来咱们经过一个Loading中常常使用的旋转动画,来看一下RN动画中的插值函数。下方的Loading动画本质上就是一张图片在不停的转圈,不过在转圈的时候咱们设置了一个Circle的动画效果。
须要实现的效果就是上面这个效果,而后咱们看一下代码实现以及插值函数的使用。首先咱们来看一下上述动画启动时的相关代码:
首先在 ComponentDidMount 方法中调用了启动方法的函数 startAnimation
在 startAnimation 函数中,咱们经过 Animation的 loop 方法来执行循环动画动画的值从 0 到 1
而且咱们设置了动画效果为 circle
最后就是调用start方法启动动画了。
而后就是Render方法中获取动画值,给相关的组件设置动画了,具体代码以下所示:
首先咱们从state中获取到相关的动画值 animationValue
而后调用该动画值的插值函数 interpolate,将动画值中的 0~1的范围映射成角度 0deg ~ 360deg。
最后就是将这个插值函数生成的值 rotateZValue设置给 Image的transform便可。
通过上述步骤咱们的图片就转起来了。插值函数在动画中仍是比较经常使用的,上面是把 0 ~ 1映射成角度,咱们还能够将该值映射成透明度、颜色等等,总之插值函数是RN动画中比较重要的角色。并且咱们能够给一个RN元素设置多个插值动画,这样这个元素就会有多个动画效果。
下方这个动画就由多个插值函数结合着多种变换方式组合而成的,分别是移动、旋转、放大这三种变换同时做用到一个View上所展现的效果,具体效果以下所示:
上述效果是在第一个转圈的动画中丰富了一下而造成的,具体代码以下:
前两个负责生成移动和缩放效果使用的值的插值函数和上面那个转圈的比较一致,只不过映射的值不一样。
而后看第三个旋转使用的插值函数就稍微有点不一样了,该插值函数能够将 0 ~ 1 不一样的区间的值映射成不一样范围的值, 从这个旋转的插值函数的映射关系不难看出,上述View的旋转路径是先快后慢的,这一点在插值函数中也是比较经常使用的。
最后就是将这三个插值函数所生成的结果设置在View的 transform 的各个key中就能够了。
上面是缩放、移动、旋转的变换。下面咱们来看一下斜切的变换。下方第一个是X方向上的斜切,第二个是Y轴方向上的斜切。
代码也比较简单,下方是设置斜切的相关代码:
天不早了,今天博客就先到这儿,下篇博客继续RN动画的相关内容。下篇博客咱们会经过一系列的“拉皮条”操做来看一下RN中的Spring动画。下篇的“拉皮条”的示例仍是比较有意思的。稍后会更新。