[React Native]动画-LayoutAnimation

实现动画的几种方式:

  • requestAnimationFrame
  • setNativeProps
  • LayoutAnimation
  • Animated

本篇文章我们会介绍前三种方式,以及它们的区别。下一篇文章会介绍高级API—Animated的用法。

requestAnimationFrame
如果不使用任何动画API,我会想到一种简单粗暴的方式来实现动画效果—通过修改state不断改变视图的样式。

我们来个简单的示例:

class Demo9 extends Component {
  constructor(props) {
      super(props);
      this.state = {
          width: 100,
          height: 100
      };
  }
  startAnimation() {
      var count = 0;
      while (++count < 50) {
          requestAnimationFrame(() = >{
              this.setState({
                  width: this.state.width + 1,
                  height: this.state.height + 1
              });
          });
      }
  }
  render() {
      return ( 
         <View style = {styles.container}> 
           <Image source = { require('./icon.jpg') }
              style={{width: this.state.width, height: this.state.height}}/>
           <TouchableOpacity style={styles.instructions} onPress={()=>this.startAnimation()}>
              <Text style={{alignSelf: 'center', color: '#FFFFFF'}}>Press me!</Text> 
           </TouchableOpacity>
          </View> 
      );
  }
}

效果图如下:

preview1.gif

这个方式实现的动画有几个问题:
1、实现方式是通过不断销毁、创建视图来完成,一方面如果你的视图的数据是动态获取的,那么就需要以合适的方式恢复数据;另外一方面,这种方式必然造成性能和内存开销的问题。
2、如果需要刷新的View的层级比较深,那么这种方式会带来严重的性能问题。
3、requestAnimationFrame毕竟是webcss的用法,在手机上,动画的效果比较生硬,如果需要‘弹性动画’,‘淡入淡出’等效果,则是比较难以实现的(需要辅助各种函数)。

setNativeProps
如果执意使用修改state的方式,觉得这种方式更符合当前需求对动画的控制,那么则应当使用原生组件的setNativeProps方法来做对应实现,它会直接修改组件底层特性,不会重绘组件,因此性能也远胜动态修改组件内联style的方法。

我们稍微修改下startAnimation方法:

startAnimation() {
  var count = 0;
  while (++count < 50) {
      requestAnimationFrame(() = >{
          this.refs.image.setNativeProps({
              style: {
                  width: this.state.width++,
                  height: this.state.height++
              }
          });
      });
  }
}

其中this.refs.image指向的是Image视图,效果图如下(比上一种方式流畅多了~):

preview2.gif

优点:
setNativeProps直接修改组件底层特性,不会重绘组件,因此性能也远胜动态修改组件内联style的方法。
缺点:
1、setNativeProps属于原生视图的方法,如果我们使用一个动画,单纯只是为了跟踪它的值,那么这么方法有点不合时宜。
2、还是和上面一种方式一样,如果需要实现‘弹性动画’,‘淡入淡出’等效果,则还是比较麻烦的。


重点,本篇文章的主角要登场了(此处有掌声~)

LayoutAnimation
当布局变化时,自动将视图运动到它们新的位置上。
一个常用的调用此API的办法是调用LayoutAnimation.configureNext(config),然后调用setState

建议大家阅读的时候打开LayoutAnimation源码,路径为:
xxx/node_modules/react-native/Libraries/LayoutAnimation/LayoutAnimation.js,其中‘xxx’为当前项目文件夹。

一个标准的config格式如下:(createupdatedelete,分别表示视图创建更新删除时候的动画)

Config.png

示例:

{   
  duration: 700,   //持续时间   
  create: {   // 视图创建         
    type: LayoutAnimation.Types.linear,      
    property: LayoutAnimation.Properties.scaleXY // opacity、scaleXY   
  },   
  update: { // 视图更新      
    type: LayoutAnimation.Types.spring,      
    springDamping: 0.4   
  },
}

其中createupdatedeleteAnim格式如下:

Anim.png

delay:延迟指定时间(单位:毫秒)
springDamping:弹跳动画阻尼系数(配合spring使用)
initialVelocity:初始速度
type:类型定义在LayoutAnimation.Types中:

  • spring:弹跳
  • linear:线性
  • easeInEaseOut:缓入缓出
  • easeIn:缓入
  • easeOut:缓出

property:类型定义在LayoutAnimation.Properties中:

  • opacity:透明度
  • scaleXY:缩放

让我们来看一段示例代码,同样是修改startAnimation方法:

startAnimation() {
  LayoutAnimation.configureNext({
    duration: 700, //持续时间
    create: { // 视图创建
        type: LayoutAnimation.Types.spring,
        property: LayoutAnimation.Properties.scaleXY,// opacity、scaleXY
    },
    update: { // 视图更新
        type: LayoutAnimation.Types.spring,
    },
  });
  this.setState({width: this.state.width + 10, height: this.state.height + 10});
}

效果图如下:


config1.gif

观察下这个动画:
视图创建的时候是缩放动画,点击‘Press Me!’,图片也会有个缩放动画。

我们还可以通过LayoutAnimation.create这个函数更简单的创建一个config,同样可以实现和上图一样的效果。

startAnimation() {
  LayoutAnimation.configureNext(LayoutAnimation.create(700, 
             LayoutAnimation.Types.spring, 
             LayoutAnimation.Properties.scaleXY));
  this.setState({width: this.state.width + 10, height: this.state.height + 10});
}

create函数接受三个参数:

  • duration:动画持续时间。
  • type:createupdate时的动画类型,定义在* LayoutAnimation.Types
  • creationProp:create时的动画属性,定义在LayoutAnimation.Properties

create的源码:

create.png

效果图和上图一样,这里不在贴出来了。

实际上,系统已经为我们提供了3个默认的动画,定义在LayoutAnimation.Presets中:

  • easeInEaseOut:缓入缓出
  • linear:线性
  • spring:弹性

一个简单的示例:

startAnimation() {
  LayoutAnimation.configureNext(LayoutAnimation.Presets.linear);
  this.setState({width: this.state.width + 10, height: this.state.height + 10});
}

具体参数配置,请查看Presets源码:

Presets.png

我们来分析下LayoutAnimation的优缺点:
优点:
1、效果非常的流畅,而且动画的过程很柔和,丝毫没有生硬的感觉。
2、可以灵活的配置动画参数,基本能满足单个动画的需求。
缺点:
1、如果要实现‘组合顺序’动画,比如先缩小50%、再向左平移100像素,那么就比较麻烦了,需要监听上一个动画的结束事件,再进行下一个。那么问题来了,configureNext第二个参数是可以监听动画结束的,但是只在IOS平台有效!
2、如果动画的效果更为复杂,比如同时执行动画,再顺序执行,对于编程来讲,需要做的事情很多,复杂度也大大提升。

那么如何定制更灵活丰富的动画效果呢,这就需要使用到高级动画API Animated。下一篇文章我们会介绍高级动画API—Animated的使用,感兴趣的朋友请继续阅读[React Native]动画-Animated

本文的源码地址Demo9

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • React Native 进阶(二)--动画 动画 流畅、有意义的动画对于移动应用用户体验来说是非常必要的。我们可...
    呼呼哥阅读 2,769评论 2 5
  • 内容抽屉菜单ListViewWebViewSwitchButton按钮点赞按钮进度条TabLayout图标下拉刷新...
    皇小弟阅读 46,733评论 22 665
  • 许是在家和高中同桌、初中同桌碰面太嗨了,忘了盯孩子的作业;许是走那天的叮咛太多,让孩子爸有些不耐烦,我也就及时打住...
    知书家庭阅读 235评论 0 0
  • 曾经各种小打小闹的抑郁,在这毕业半年来,总于迫不及待的爆发开来。封闭自己,暗无天日,没有色彩,可以回避,可以假装,...
    Maxdiane阅读 219评论 0 0