React Native动画入门

React Native动画是研讨会和课程的热门话题,也许是因为许多开发人员发现使用它具有挑战性。 尽管许多在线博客和资源都专注于React Native的性能方面,但很少有人带您了解基础知识。 在本文中,我将讨论如何实现React Native动画的基础知识。

首先,让我们回顾一些背景和历史。

历史与演变

要使用跨平台JavaScript代码,手机的本机组件必须通过称为网桥的元素来传达信息。 该桥是异步的,这会导致基于JavaScript的React Native应用程序滞后,因为通过桥的异步请求会阻塞JavaScript代码与本机部件交互的路径。

为了获得高性能,必须在本机UI线程上渲染动画。 由于数据需要通过网桥进行序列化,因此这通常会阻塞JavaScript线程,从而导致帧数下降。 自2015年动画成为React Native的最大限制之一以来,这个问题一直很普遍。

幸运的是,此后,由于社区成员的大力支持,情况有所改善。 现在,React Native动画通常达到每秒60帧(FPS)。 诸如Animated之类的声明性API简化了实现交互式动画的过程。

使用动画API来提高性能

尽管如此,对于开发人员而言,遇到性能问题还是很常见的,特别是当他们正在处理复杂的动画时。

如上所述,React Native动画中的性能瓶颈是由JavaScript线程上的繁重工作负载引起的,这降低了帧速率并导致缓慢的用户体验。 为解决此问题,您需要保持每秒60帧的帧速率。

使用Animated API是最佳解决方案,因为它可以优化所需的序列化/反序列化时间。 它通过使用声明性API来描述动画来做到这一点。 其背后的想法是提前声明整个动画,以便可以将JavaScript中的声明序列化并发送到桥。 然后,驱动程序逐帧执行动画。

如何在React Native中实现动画

有多种方法可以在React Native中实现动画。 这是我觉得最有用的一些。

动画值

作为任何React Native应用中动画的构建块,动画值在我的列表中居于首位。 这些通常指向实数,当与动画组件一起传递时,该实数将转换回实数。

让我们看一个例子:


   
   
Animated.timing(this.valueToAnimate, {
    toValue: 42;
    duration: 1000;
}).start()

在上面的示例中,我将value.ToAnimate声明为42,它将在1000毫秒后执行。

您还可以使用Animated值来声明属性,例如不透明度或位置。 这是带有Animated值的不透明度的示例实现:

 <Animated.View style={{ opacity: myAnimatedOpacity }} />   

动画驱动程序:Animated.timing,Animated.event,Animated.decay

可以将驱动程序想像为图中的节点,这些节点会在每个帧中更改一个Animated值。 例如, Animated.timing将增加一个值,而Animated.decay将减少每个帧的值。

让我们看一个例子:


   
   
Animated.decay(this.valueToAnimate, {
   velocity: 2.0,
   deceleration: 0.9
}).start();

本示例以特定的速度启动动画,并在特定的时间逐渐减速。 当材质设计的文档最初出现时,我喜欢在跨平台应用程序中执行此操作。 感觉很棒,有很多方法可以使动画产生令人难忘的体验。

您还可以在用户滚动时使用Animated.event驱动值:


   
   
<ScrollView onScroll={Animated.event(
  [{nativeEvent: {contentOffset: {y: this.state.scrollY}}}]
)}
>
</ScrollView>

在上面的示例中, Animated.event返回一个函数,该函数将scrollView's nativeEvent.contentOffset.y为当前的scrollY状态。

总而言之,动画驱动程序可以与Animated值或其他Animated驱动程序结合使用。

作为一个侧面说明,请记住,当驱动程序更新每个帧时,新值将立即更新View属性。 因此,在声明变量时要小心,并在使用它们时注意其范围。

转换方法

转换方法使您可以将Animated值转换为新的Animated值。

您可以使用Animated.add()Animated.multiply()Animated.interpolate()来实现变换操作。 您可以使用以下命令在“动画”图中的任何节点上执行变换操作:

 newAnimated.Value(55).interpolate(.....) // Transformation operation using Animated.interpolate() method 

动画道具

动画道具是将动画值映射到组件上的道具的特殊节点。 当您渲染Animated.view并为其分配属性时,将生成该文件。

让我们看下面的代码片段:


   
   
Var opacity = new Animated.Value(0.7);
<Animated.View style={{ opacity }} />

在这里,我添加了一个动画道具,该道具将值0.7转换为属性。 如果方法更新了值,则更改将反映在视图的属性中。

上述方法与React Native中的对象动画配合使用,并在其中起着至关重要的作用。

动画驱动程序( Animated.TimingAnimated.EventAnimated.Decay )会更改动画每一帧的动画值。 然后将结果传递到任何转换操作,在此将其存储为视图的属性(不透明度或转换值)。

然后将结果通过JavaScript移交给本机领域,在调用setNativeProps时更新视图。 最后,将其传递到iOS或Android,更新UIView或Android.View。

使用Animated API和Native Driver实施动画

自从React Native Animated API诞生以来,就已经使用JavaScript驱动程序执行框架,但是由于业务逻辑直接落在JavaScript线程上,因此导致框架丢失。

request_animation_frame.png

为了解决帧丢失问题,驱动程序的最新版本是纯本地制作的,现在它能够在本地领域中逐帧执行动画。

机驱动程序与Animated API一起使用时,允许本机动画模块直接更新视图,而无需计算JavaScript中的值。

为了使用本机驱动程序,必须在配置动画时将useNativeDriver指定为true

 useNativeDriver: true 

使用PanResponder在React Native中处理手势

ScrollView

尽管您可以使用简单的ScrollView组件执行许多操作,但您可能会同意没有手势就无法完成移动,手势是用户使用动画(例如滚动或平移)执行的动作。

在React Native中,可以通过将PanResponder与Animated API结合使用来无缝处理手势。

PanResponder将各种触摸组合到特定手势中。 它可以对额外的触摸进行一次触摸,从而使手势功能顺畅。

默认情况下,PanResponder包含一个InteractionManager句柄,该句柄阻止JS线程上运行的事件中断手势。

延长正常运行时间以实现缓慢的Navigator转换

任何涉及从一个应用程序屏幕切换到另一应用程序屏幕的React Native动画通常都应使用导航组件来完成。 导航组件(例如React Navigation)通常用于导航过渡。

在React Native中,导航转换通常发生在JavaScript线程中,这可能导致低端/低内存设备(通常为Android,因为iOS设备更有效地处理这些设备)的转换缓慢。 当React Native在动画仍在后台执行而试图渲染新屏幕时,通常会发生缓慢的导航过渡。

为了避免这种情况, InteractionManager允许在JavaScript线程中执行动画或交互之后安排长时间运行的任务。

布局动画

LayoutAnimation是一个简单的API,可在下一个布局发生时自动将视图动画化到下一个连续位置。 它可以在UI线程上运行,从而使其具有高性能。

与Animated(动画)相比,使用LayoutAnimation配置的动画将在调用后应用于所有组件,在Animated中,您可以控制要设置动画的特定值。 LayoutAnimation可以对下一次渲染时发生的所有变化进行动画处理,因此您应该在调用setState之前先对其进行调用。

在调用setState之前配置布局动画将确保本机线程中的动画流畅,并防止在触发另一个setState diff中的代码时影响您的动画(在正常情况下,这会损害您应用的动画)。

使用LayoutAnimation的另一种方法是在组件WillReceiveProps方法内部调用它。 只需传递适当的动画配置参数即可调用LayoutAnimation.configureNext ,如下所示:


   
   
LayoutAnimation.configureNext(animationConfiguration, callbackCompletionMethod);
this.setState({ stateToChange: newStateValue });

LayoutAnimation仅支持两个属性:不透明度和可伸缩性。

它通过使用视图的唯一键并计算其预期位置来标识视图。 此外,只要视图在状态更改之间保持相同的关键点,它就可以对帧更改进行动画处理。

使用LayoutAnimation实现的动画是本地发生的,从性能角度来看这是很好的,但是如果需要在状态之间对所有属性进行动画处理,则可能会遇到挑战。

总结思想

本文仅涉及React Native动画的表面。 在React Native中工作的经验法则是尽可能使用Animated API。 对于手势,请将PanResponder与Animated API一起使用。

利用Native Driver和Animated API可以消除您可能遇到的大多数问题,但是如果性能仍然落后,请坚持使用LayoutAnimation。

翻译自: https://opensource.com/article/18/6/getting-started-react-native-animations

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值