React Native开发之动画(Animations)
博主这个系列的文章
- React Native开发之IDE(Atom+Nuclide)
- React Native开发之FlexBox代码+图解
- React Native的Navigator详解
另外,我在Github上建立了一个仓库来搜集优秀的React Native库和优秀的博客等
ReactNativeMaterials
资料
- 官方关于动画的介绍
- 官方给出的复杂动画的示例
- 开源项目react-native-animatable
- React Native Animation Book
- 可以用在实际项目里的:react-motion
概述
目前,React Native的版本是0.28,主要的动画分为两大类
- LayoutAnimation 用来实现布局切换的动画
- Animated 更加精确的交互式的动画
目前React native的release速度还是比较快的,每隔2周左右就release一次。
准备工作
本文默认读者已经
- 安装好了React Native
- 安装好了IDE(本文使用Atom+Nuclide),如果没有安装过,可以参照最上面的链接进行安装
- 使用
react-native init Demo --verbose
初始化了一个Demo项目
一个简单的动画
一个最基本的Animated创建过程如下
- 创建
Animated.Value
,设置初始值,比如一个视图的opacity
属性,最开始设置Animated.Value(0)
,来表示动画的开始时候,视图是全透明的。 - AnimatedValue绑定到Style的可动画属性,比如透明度,{opacity: this.state.fadeAnim}
- 使用
Animated.timing
来创建自动的动画,或者使用Animated.event
来根据手势,触摸,Scroll的动态更新动画的状态(本文会侧重讲解Animated.timing
) - 调用
Animated.timeing.start()
开始动画
基于上述的原理,我们来实现第一个动画。
创建一个Demo工程的时候,运行后,模拟器截图应该是酱紫的。
然后,只保留第一行文字,然后我们给这个默认的视图创建fade in动画,效果如下
代码
class Demo extends React.Component {state: { //可以不写,我这里写是为了去除flow警告fadeAnim: Object,};constructor(props) {super(props);this.state = {fadeAnim: new Animated.Value(0), //设置初始值};}componentDidMount() {Animated.timing(this.state.fadeAnim,//初始值{toValue: 1}//结束值).start();//开始}render() {return (<View style={styles.container}><Animated.Text style={{opacity: this.state.fadeAnim}}>//绑定到属性Welcome to React Native!</Animated.Text></View>);}
}
所以说,简单的动画就是用Animated.Value
指定初始值,然后在Animated.timing
中设置结束值,其他的交给React native让它自动创建,我们只需要调用start
开始动画即可。
在当前版本0.27种,可动画的视图包括
- View
- Text
- Image
- createAnimatedComponent(自定义)
Animated详解
方法
static decay(value, config)
阻尼,将一个值根据阻尼系数动画到 0static timing(value, config
根据时间函数来处理,常见的比如线性,加速开始减速结束等等,支持自定义时间函数static spring(value, config)
弹性动画static add(a, b)
将两个Animated.value
相加,返回一个新的static multiply(a, b)
将两个Animated.value
相乘,返回一个新的static modulo(a, modulus)
,将a对modulus取余,类似操作符%static delay(time)
延迟一段时间static sequence(animations)
依次开始一组动画,后一个在前一个结束后才会开始,如果其中一个动画中途停止,则整个动画组停止static parallel(animations, config?)
,同时开始一组动画,默认一个动画中途停止,则全都停止。可以通过设置stopTogether
来重写这一特性static stagger(time, animations)
,一组动画可以同时执行,但是会按照延迟依次开始static event(argMapping, config?)
,利用手势,Scroll来手动控制动画的状态static createAnimatedComponent(Component)
,自定义的让某一个Component支持动画
属性
Value
,类型是AnimatedValue
,驱动基本动画AnimatedValueXY
,类型是AnimatedValueXY
,驱动二维动画
AnimatedValue类型
一个AnimatedValue一次可以驱动多个可动画属性,但是一个AnimatedValue一次只能由一个机制驱动。比如,一个Value可以同时动画View的透明度和位置,但是一个Value一次只能采用线性时间函数
方法
constructor(value)
构造器setValue(value)
直接设置值,会导致动画终止setOffset(offset)
设置当前的偏移量flattenOffset()
将偏移量合并到最初值中,并把偏移量设为0,addListener(callback) ,removeListener(id),removeAllListeners()
,增加一个异步的动画监听者stopAnimation(callback?)
终止动画,并在动画结束后执行callbackinterpolate(config)
插值,在更新可动画属性前用插值函数对当前值进行变换animate(animation, callback)
通常在React Native内部使用stopTracking(),track(tracking)
通常在React Native内部使用
AnimatedValueXY
和AnimatedValue类似,用在二维动画,使用起来和AnimatedValue类似,这里不在介绍,这里是文档。
一个更加复杂动画
有了上文的知识支撑,我们可以设计并实现一个更加复杂的动画了。
- 这个动画由button驱动
- 一个AnimatedValue同时驱动两三个属性,透明度,Y的位置以及scale
效果
代码(省略了import和style)
class Demo extends React.Component {state: {fadeAnim: Animated,currentAlpha:number,};constructor(props) {super(props);this.state = {//设置初值currentAlpha: 1.0,//标志位,记录当前valuefadeAnim: new Animated.Value(1.0)};}startAnimation(){this.state.currentAlpha = this.state.currentAlpha == 1.0?0.0:1.0;Animated.timing(this.state.fadeAnim,{toValue: this.state.currentAlpha}).start();}render() {return (<View style={styles.container}><Animated.Text style={{opacity: this.state.fadeAnim, //透明度动画transform: [//transform动画{translateY: this.state.fadeAnim.interpolate({inputRange: [0, 1],outputRange: [60, 0] //线性插值,0对应60,0.6对应30,1对应0}),},{scale:this.state.fadeAnim},],}}>Welcome to React Native!</Animated.Text><TouchableOpacity onPress = {()=> this.startAnimation()} style={styles.button}><Text>Start Animation</Text></TouchableOpacity></View>);}
}
手动控制动画
通过上文的讲解,相信读者已经对如何用Animated创建动画有了最基本的认识。而有些时候,我们需要根据Scroll或者手势来手动的控制动画的过程。这就是我接下来要讲的。
手动控制动画的核心是Animated.event
,
这里的Aniamted.event的输入是一个数组,用来做数据绑定
比如,
ScrollView中
onScroll={Animated.event([{nativeEvent: {contentOffset: {x: this.state.xOffset}}}]//把contentOffset.x绑定给this.state.xOffset
)}
Pan手势中
onPanResponderMove: Animated.event([null,//忽略native event{dx: this.state.pan.x, dy: this.state.pan.y},//dx,dy分别绑定this.state.pan.x和this.state.pan.y])
Scroll驱动
目标效果 - 随着ScrollView的相左滑动,最左边的一个Image透明度逐渐降低为0
核心代码
var deviceHeight = require('Dimensions').get('window').height;
var deviceWidth = require('Dimensions').get('window').width;
class Demo extends React.Component {state: {xOffset: Animated,};constructor(props) {super(props);this.state = {xOffset: new Animated.Value(1.0)};}render() {return (<View style={styles.container}><ScrollView horizontal={true} //水平滑动showsHorizontalScrollIndicator={false}style={{width:deviceWidth,height:deviceHeight}}//设置大小onScroll={Animated.event([{nativeEvent: {contentOffset: {x: this.state.xOffset}}}]//把contentOffset.x绑定给this.state.xOffset)}scrollEventThrottle={100}//onScroll回调间隔><Animated.Image source={require('./s1.jpg')}style={{height:deviceHeight,width:deviceWidth,opacity:this.state.xOffset.interpolate({//映射到0.0,1.0之间inputRange: [0,375],outputRange: [1.0, 0.0]}),}}resizeMode="cover"/><Image source={require('./s2.jpg')} style={{height:deviceHeight, width:deviceWidth}} resizeMode="cover" /><Image source={require('./s3.jpg')} style={{height:deviceHeight, width:deviceWidth}} resizeMode="cover" /></ScrollView></View>);}
}
手势驱动
React Native最常用的手势就是PanResponser,
由于本文侧重讲解动画,所以不会特别详细的介绍PanResponser,仅仅介绍用到的几个属性和回调方法
onStartShouldSetPanResponder: (event, gestureState) => {}//是否相应pan手势
onPanResponderMove: (event, gestureState) => {}//在pan移动的时候进行的回调
onPanResponderRelease: (event, gestureState) => {}//手离开屏幕
onPanResponderTerminate: (event, gestureState) => {}//手势中断
其中,
- 通过event可以获得触摸de位置,时间戳等信息。
- 通过gestureState可以获取移动的距离,速度等
目标效果- View随着手拖动而移动,手指离开会到原点
核心代码
class Demo extends React.Component {state:{trans:AnimatedValueXY,}_panResponder:PanResponder;constructor(props) {super(props);this.state = {trans: new Animated.ValueXY(),};this._panResponder = PanResponder.create({onStartShouldSetPanResponder: () => true, //响应手势onPanResponderMove: Animated.event([null, {dx: this.state.trans.x, dy:this.state.trans.y}] // 绑定动画值),onPanResponderRelease: ()=>{//手松开,回到原始位置Animated.spring(this.state.trans,{toValue: {x: 0, y: 0}}).start();},onPanResponderTerminate:()=>{//手势中断,回到原始位置Animated.spring(this.state.trans,{toValue: {x: 0, y: 0}}).start();},});}render() {return (<View style={styles.container}><Animated.View style={{width:100,height:100,borderRadius:50,backgroundColor:'red',transform:[{translateY:this.state.trans.y},{translateX:this.state.trans.x},],}}{...this._panResponder.panHandlers}></Animated.View></View>);}
}
LayoutAnimation
LayoutAnimation在View由一个位置变化到另一个位置的时候,在下一个Layout周期自动创建动画。通常在setState前掉用LayoutAnimation.configureNext
一个简单的Demo
代码
class Demo extends React.Component {state: {marginBottom:number,};constructor(props) {super(props);this.state = {//设置初值marginBottom:0};}_textUp(){LayoutAnimation.spring();this.setState({marginBottom:this.state.marginBottom + 100})}render() {return (<View style={styles.container}><TouchableOpacity onPress = {()=>this._textUp()}style={{ width:120,height:40,alignItems:'center',marginBottom:this.state.marginBottom,justifyContent:'center',backgroundColor:'#00ffff',borderRadius:20}}><Text>Text UP</Text></TouchableOpacity></View>);}
}
其实代码里只是调用了这一行LayoutAnimation.spring();
,布局修改的时候就显得不那么生硬了
LayoutAnimation详解
配置相关
//配置下一次切换的效果,其中config可配置的包括duration(时间),create(配置新的View),update(配置更新的View)
static configureNext(config, onAnimationDidEnd?)
//configureNext的方便方法
static create(duration, type, creationProp) #
属性
对应三种时间函数
easeInEaseOut: CallExpression #
linear: CallExpression #
spring: CallExpression #
Navigator转场动画
我们先创建一个默认的Navigator转场Demo
回拉的时候,前一个时图的移动距离要小于后一个视图
这时候的核心代码如下,MainScreen和DetailScreen就是带一个Button的视图
class Demo extends React.Component{render(){return (<Navigatorstyle = {styles.container}initialRoute={{id:"main",}}renderScene={this.renderNav}configureScene={(route, routeStack) => Navigator.SceneConfigs.PushFromRight}/>);}renderNav(route,nav){switch (route.id) {case 'main':return <MainScreen navigator={nav} title="Main"/ >;case 'detail':return (<DetailScreen navigator={nav} title="Detail"/ >);}}}
Navigator的默认的转场动画的实现都可以在这里找到NavigatorSceneConfigs.js。
So,我们有两种方式来实现自定义的转场动画
- 彻底的按照NavigatorSceneConfigs.js写一个转场
- 修改NavigatorSceneConfigs.js中已配置的转场的若干属性
篇幅限制,本文只修改默认的转场
比如,我想把默认的PushFromRight动画中,第一个视图的移动距离改为全屏幕。
var ToTheLeftCustom = {transformTranslate: {from: {x: 0, y: 0, z: 0},to: {x: -SCREEN_WIDTH, y: 0, z: 0},//修改这一行min: 0,max: 1,type: 'linear',extrapolate: true,round: PixelRatio.get(),},opacity: {value: 1.0,type: 'constant',},
};var baseInterpolators = Navigator.SceneConfigs.PushFromRight.animationInterpolators;
var customInterpolators = Object.assign({}, baseInterpolators, {out: buildStyleInterpolator(ToTheLeftCustom),
});
var baseConfig = Navigator.SceneConfigs.PushFromRight;
var CustomPushfromRight = Object.assign({}, baseConfig, {animationInterpolators: customInterpolators,
});
然后,修改Navigator的configScene
configureScene={(route, routeStack) => baseConfig}
这时候的动画如下
React Native开发之动画(Animations)相关推荐
- React Native开发(一)
本React Native讲解专题:主要讲解了React Native开发,由基础环境搭建配置入门,基础,进阶相关讲解. 关于React Native各种疑难杂症,问题深坑总结方案请点击查看: Mac ...
- 【转】【React Native开发】
[React Native开发]React Native控件之ListView组件讲解以及最齐全实例(19) [React Native开发]React Native控件之Touchable*系列组 ...
- windows 下配置 react native 开发环境
windows 下配置 react native 开发环境 安装nvm 由于react native 需要使用 NodeJs 4.0以上版本,为了方便切换NodeJs,首先我们需要安装nvm. 你可以 ...
- React Native开发之必备React基础
为了帮助大家快速上手React Native开发,在这本节中将向大家介绍开发React Native所需要的一些React必备基础知识. 概述 本节课将从React的特点.如何使用React.JSX语 ...
- React Native开发错误警告处理总结(已解决 !持续更新)
注:本文是我在开发过程中遇到问题解决方法的总结,之后会持续更新,希望帮助到更多的学习者.文中有不妥的地方希望指出共同学习,同时欢迎大神补充.(之后我会放出自己开发整理的笔记和GithubDemo地址, ...
- 使用React Native进行气泡动画
by Narendra N Shetty 由纳伦德拉·N·谢蒂(Narendra N Shetty) 使用React Native进行气泡动画 (Bubble animation with React ...
- Windows环境下安装React Native开发环境----记一次填坑过程
前言 集成React Native开发环境遇到各个坑,调试了很久出现过找不到设备,百度上个别人的资料有误被绕来绕去耽误了很多时间,下载慢等待时间过长等问题,最后多方查阅资料,电脑重启等操作终于部署好了 ...
- iOS新知识学习之React Native开发工具集
本文整理了React Native iOS开发过程中有用的工具.服务.测试.库以及网站等. 工具 你可以选择不同的开发环境:DECO.EXPO或者你可以使用Nuclide+Atom,目前我使用EXPO ...
- React Native开发之——Webstorm开发RN配置
前言 前文React Native开发之--Webstorm快捷开发介绍了使用Webstorm快捷开发React Native, 本文介绍Webstorm开发RN配置. Webstorm开发RN配置 ...
最新文章
- 网易 for linux,NetEaseMusic
- python3函数中lambda/filter/map/reduce的用法
- Android 错误: 找不到符号 符号: 类 x 位置: 类 MainActivity
- 小学计算机几年级学3d建模,学了4年手绘和建模,你终于不会思考了
- centos7上的图形化界面svn客户端_基于windows平台的SVN教程。
- iPhone 13 Pro手机壳曝光 网友:更丑了
- 40 道数据挖掘面试真题大放送!
- LoadRunner第一次压测实践后的心得体会 收获
- centos8镜像_CentOS8服务器进阶(一)
- java 方法描述符_整理Java编程中常用的基本描述符与运算符
- 120款超浪漫❤HTML5七夕情人节表白网页源码❤ HTML+CSS+JavaScript
- Win10菜单栏卡顿无响应的解决方法
- 电脑开机加速,一下子就提升了20几秒
- 小程序“成语猜题”部分答案
- 前端获取微信头像 base64 数据的踩坑实践
- win10安装xshell免费版
- QT-ico图片的生成
- linux、windows nginx启动 重启 关闭命令
- 客户端与服务器信息交互的流程,客户端与服务器的交互流程
- vue.cli3.0版本的用axios调用本地JSON数据报404解决方法