-
Notifications
You must be signed in to change notification settings - Fork 442
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[译]详解React Native动画 #41
Comments
nice |
例子很详细,很棒 |
666666666 |
请问下,如何暂停一个动画呢?我在渲染一个360度旋转动画的时候(代码和你上面的一样),对Animaten.timing这个返回的对象调用stop()方法,但是却并不是停止旋转动画,而是重新开始动画,这是啥情况? |
666 |
@dwqs 不行啊, 代码连接全部打不开?求解! |
@wh469012917 关于暂停动画我写过一个 https://github.com/pheromone/react-native-videoDemo |
有没有办法做成绘制移动路线 L 型?不只是单独的左右移动? |
nice |
如何做一个展开收起的动画啊 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
大多数情况下,在 React Native 中创建动画是推荐使用 Animated API 的,其提供了三个主要的方法用于创建动画:
Easing
模块定义了很多缓冲曲线函数。toValue
值更新的同时跟踪当前的速度状态,以确保动画连贯。以我的经验来看,Animated.timing() 和 Animated.spring() 在创建动画方面是非常有效的。
除了这三个创建动画的方法,对于每个独立的方法都有三种调用该动画的方式:
stopTogether
选项来改变这个效果。1. Animated.timing()
第一个要创建的动画是使用
Animated.timing
创建的旋转动画。这种方式常用于创建需要loading指示的动画,在我使用React Native的项目中,这也是创建动画最有效的方式。这个理念也可以用于其它诸如按比例放大和缩小类型的指示动画。
开始之前,我们需要创建一个新的React Native 项目或者一个空的React Native项目。创建新项目之前,需要输入
react-native init
来初始化一个项目,并切换到该项目目录:然后打开
index.android.js
和index.ios.js
。现在已经创建了一个新项目,则第一件事是在已经引入的 View 之后从
react native
中引入 Animated,Image 和 Easing:Animated 是我们将用于创建动画的库,和React Native交互的载体。
Image 用于在UI中显示图片。
Easing 也是用React Native创建动画的载体,它允许我们使用已经定义好的各种缓冲函数,例如:linear, ease, quad, cubic, sin, elastic, bounce, back, bezier, in, out, inout 。由于有直线运动,我们将使用 linear。在这节(阅读)完成之后,对于实现直线运动的动画,你或许会有更好的实现方式。
接下来,需要在构造函数中初始化一个带动画属性的值用于旋转动画的初始值:
我们使用 ** Animated.Value** 声明了一个 spinValue 变量,并传了一个 0 作为初始值。
然后创建了一个名为
spin
的方法,并在componentDidMount
中调用它,目的是在 app 加载之后运行动画:spin()
方法的作用如下:this.spinValue
的值以Easing.linear
的动画方式在 4000 毫秒从 0 变成 1。Animated.timing 需要两个参数,一个要变化的值(本文中是 this.spinValue) 和一个可配置对象。这个配置对象有四个属性:toValue(终值)、duration(一次动画的持续时间)、easing(缓存函数)和delay(延迟执行的时间)start
,它将在(一次)动画完成之后调用,这也是创建无穷动画的一种基本方式。start()
需要一个完成回调,该回调在动画正常的运行完成之后会被调用,并有一个参数是{finished: true}
,但如果动画是在它正常运行完成之前而被停止了(如:被手势动作或者其它动画中断),则回调函数的参数变为{finished: false}
。现在方法已经创建好了,接下来就是在UI中渲染动画了。为了渲染动画,需要更新
render
方法:render
方法中,创建了一个 spin 变量,并调用了 this.spinValue 的 interpolate 方法。interpolate 方法可以在任何一个 Animated.Value 返回的实例上调用,该方法会在属性更新之前插入一个新值,如将 01 映射到 110。在我们的demo中,利用 interpolate 方法将数值 01 映射到了 0deg360deg。我们传递了inputRange
和outputRange
参数给interpolate 方法,并分别赋值为 [0,1] 和 &[‘0deg’, ‘360deg’]。container
样式值的 View和 带 height, width和 transform 属性的Animated.Image,并将 spin 的值赋给transform
的 rotate 属性,这也是动画发生的地方:最后,在
container
样式中,使所有元素都居中:这个示例动画的最终代码在这里。
关于Easing
这是
Easing
模块的源码链接,从源码中可以看到每一个 easing 方法。我创建了另外一个示例项目,里面包含了大部分 easing 动画的实现,可以供你参考,链接在这里。(项目的运行截图)依据在下面:
该项目实现的 easing 动画在 RNPlay 的地址在这里。
2. Animated.timing 示例
上文已经说过了 Animated.timing 的基础知识,这一节会例举更多使用 Animated.timing 与 interpolate 结合实现的动画示例。
下一个示例中,会声明一个单一的动画值,
this.animatedValue
,然后将该值和interpolate
一起使用来驱动下列属性值的变化来创建复杂动画:在开始之前,可以创建一个新分支或者清除上一个项目的旧代码。
第一件事是在构造函数中初始化一个需要用到的动画属性值:
接下来,创建一个名为
animate
的方法,并在 componentDidMount() 中调用该方法:在
render
方法中,我们创建 5 个不同的插值变量:interpolate 是一个很强大的方法,允许我们用多种方式来使用单一的动画属性值:this.animatedValue。因为
this.animatedValue
只是简单的从0变到1,因而我们能将这个值插入到 opacity、margins、text sizes 和 rotation 等样式属性中。最后,返回实现了上述变量的 Animated.View 和 Animated.Text 组件:
当然,也需要更新下
container
样式:这个示例动画的最终代码在这里。
3. Animated.spring()
接下来,我们将会使用 Animated.spring() 方法创建动画。
我们继续使用上一个项目,并只需要更新少量代码就行。在构造函数中,创建一个 springValue 变量,初始化其值为0.3:
然后,删除
animated
方法和componentDidMount
方法,创建一个新的spring
方法:springValue
的值重置为 0.3Animated.spring
方法,并传递两个参数:一个要变化的值和一个可配置对象。可配置对象的属性可以是下列的任何值:toValue (number), overshootClamping (boolean), restDisplacementThreshold (number), restSpeedThreshold (number), velocity (number), bounciness (number), speed (number), tension(number), 和 friction (number)。除了 toValue 是必须的,其他值都是可选的,但 friction 和 tension 能帮你更好地控制 spring 动画。start()
启动动画动画已经设置好了,我们将其放在 View 的click事件中,动画元素依然是之前使用过的 React logo 图片:
Animated.Image
,并为其scale
属性添加this.springValue
这个示例动画的最终代码在这里。
4. Animated.parallel()
Animated.parallel() 会同时开始一个动画数组里的全部动画。
先看一下这个api是怎么调用的:
开始之前,我们先直接创建三个我们需要的动画属性值:
然后,创建一个
animate
方法并在 componendDidMount() 中调用它:在
animate
方法中,我们将三个动画属性值重置为0。此外,还创建了一个 createAnimation 方法,该方法接受四个参数:value, duration, easing, delay(默认值是0),返回一个新的动画。然后,调用
Animated.parallel()
,并将三个使用createAnimation
创建的动画作为参数传递给它。在
render
方法中,我们需要设置插值:最后,我们用一个主 View 包裹三个 Animated.Views:
当
animate()
被调用时,三个动画会同时执行。这个示例动画的最终代码在这里。
5. Animated.Sequence()
先看一下这个api是怎么调用的:
和 Animated.parallel() 一样, Animated.sequence() 接受一个动画数组。但不同的是,Animated.sequence() 是按顺序执行一个动画数组里的动画,等待一个完成后再执行下一个。
由于
Animated.sequence()
和Animated.parallel()
很相似,因而对Animated.sequence()
就不多作介绍了。主要不同的一点是我们是使用循环创建 Animated.Values。这个示例动画的最终代码在这里。
6. Animated.Stagger()
(图片太大,上传不了) gif动态图
先看一下这个api是怎么调用的:
和 Animated.parallel() 和 Animated.sequence() 一样, Animated.Stagger 接受一个动画数组。但不同的是,Animated.Stagger 里面的动画有可能会同时执行(重叠),不过会以指定的延迟来开始。
与上述两个动画主要的不同点是 Animated.Stagger 的第一个参数,
delay
会被应用到每一个动画:这个示例动画的最终代码在这里。
参考
React Native Animations Using the Animated API
Animated Docs
The text was updated successfully, but these errors were encountered: