离上次写RN笔记有一段时间了,期间参与了一个新项目,只在最近的空余时间继续学习实践,因此进度比较缓慢,不过这并不代表没有新进展,其实这个小东西离上次发文时已经有了相当大的变化了,其中影响最大的变化就是引入了Redux,后面会系统介绍一下。
在开始主题之前,先补充一点上回说到的动画初探(像我这么靠谱严谨的攻城狮,必须精益求精,┗|`O′|┛ 嗷~~)。
上回文说到,经过我们自己定义了余弦动画函数之后,动态设定state的4个参数,实现了比较流畅的加载动画,这里可能有朋友已经注意到了,我们非常频繁的调用了setState方法,这在React和RN中都是相当忌讳的,每一次setState都会触发render方法,也就意味着更频繁的虚拟DOM对比,特别是在RN中,这还意味着更频繁的JSCore<==>iOS通信,尽管框架本身对多次setState做了优化,比如会合并同时调用的多个setState,但这对性能和体验还是会有较大影响。
上回我们只是单独实现了一个loading动画,所以还比较流畅,当视图中元素较多并且有各自的动画的时候,就会看到比较严重的卡顿,这些其实是可以避免的,因为在loading动画的实现部分,我们清楚地知道只需要loading动画的特定组成部分更新而不是组件的所有部分以及继承链上的所有组件都需要更新,并且确信这个节点一定发生了变化,因此不需要经过虚拟DOM对比,那么如果我们能绕开setState,动画就应该会更流畅,即使在复杂的视图里边。这就是Animations文档最后提到的setNativeProps方法。
As mentioned in the Direction Manipulation section, setNativeProps allows us to modify properties of native-backed components (components that are actually backed by native views, unlike composite components) directly, without having to setState and re-render the component hierarchy.
setNativeProps允许我们直接操纵原生组件的属性,而不需要用到setState,也不会重绘继承链上的其他组件。这正是我们想要的效果,加上我们明确知道正在操纵的组件以及它与视图其他组件的关系,因此,这里我们可以放心地使用它,而且相当简单。
更新前:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
loopAnimation(){ var t0=animationT,t1=t0+0.5,t2=t1+0.5,t3=t2+timeDelay,t4=t3+0.5;//这里分别是四个动画的当前时间,依次加上了0.5的延迟 var v1=Number(Math.cos(t0).toFixed(2))*animationN+animationM;//将cos函数的小数值只精确到小数点2位,提高运算效率 var v2=Number(Math.cos(t1).toFixed(2))*animationN+animationM; var v3=Number(Math.cos(t2).toFixed(2))*animationN+animationM; var v4=Number(Math.cos(t3).toFixed(2))*animationN+animationM; this.setState({ fV:v1, sV:v2, tV:v3, foV:v4 }); animationT+=0.35;//增加时间值,每次增值越大动画越快 requestAnimationFrame(this.loopAnimation.bind(this)); } |
更新后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
loopAnimation(){ var t0=··· var v1=··· var v2=··· var v3=··· var v4=··· this.refs.line1.setNativeProps({ style:{width:w1,height:v1} }); this.refs.line2.setNativeProps({ style:{width:w2,height:v2} }); this.refs.line3.setNativeProps({ style:{width:w3,height:v3} }); this.refs.line4.setNativeProps({ style:{width:w4,height:v4} }); animationT+=0.35;//增加时间值,每次增值越大动画越快 requestAnimationFrame(this.loopAnimation.bind(this)); } |
效果如下:
这里有意在注册请求完毕之后没有隐藏loading动画,因此同时执行了视图切换和loading两个动画,效果还行~
好了,该进入今天的正题了。先整体看一下这一阶段实现的效果(哒哒哒~):
主要是模拟了一个新用户注册流程,实现起来也并不复杂,整体结构是用一个RN组件Navigator来做导航,虽然有另一个NavigatorIOS组件在iOS系统上表现更加优异,但是考虑到RN本身希望能够同时在安卓和iOS上运行的初衷,我选择了可以兼容两个平台的Navigator来尝试,目前来看效果还能接受。
在最后的详细信息视图里边,尝试了各种组件,比如调用相机,Switch,Slider等,主要是尝鲜,哈哈~ 也自己实现了比较简单的check按钮。
首先最外层的结构是一个Navigator,它控制整个用户注册的视图切换:
1 2 3 4 5 6 7 8 9 |
<Navigator style={styles.navWrap} initialRoute={{name: 'login', component:LoginView}} configureScene={(route) => { return Navigator.SceneConfigs.FloatFromRight; }} renderScene={(route, navigator) => { let Component = route.component; return <Component {...route.params} navigator={navigator} /> }} /> |
其中,initialRoute配置了Navigator的初始组件,这里就是LoginView组件,它本身既可以直接登录,也可以点击【我要注册】进入注册流程。configureScene属性则是用来配置Navigator中视图切换的动画类型,这里可以灵活配置切换方式:
在开始主题之前,先补充一点上回说到的动画初探(像我这么靠谱严谨的攻城狮,必须精益求精,┗|`O′|┛ 嗷~~)。
上回文说到,经过我们自己定义了余弦动画函数之后,动态设定state的4个参数,实现了比较流畅的加载动画,这里可能有朋友已经注意到了,我们非常频繁的调用了setState方法,这在React和RN中都是相当忌讳的,每一次setState都会触发render方法,也就意味着更频繁的虚拟DOM对比,特别是在RN中,这还意味着更频繁的JSCore<==>iOS通信,尽管框架本身对多次setState做了优化,比如会合并同时调用的多个setState,但这对性能和体验还是会有较大影响。
上回我们只是单独实现了一个loading动画,所以还比较流畅,当视图中元素较多并且有各自的动画的时候,就会看到比较严重的卡顿,这些其实是可以避免的,因为在loading动画的实现部分,我们清楚地知道只需要loading动画的特定组成部分更新而不是组件的所有部分以及继承链上的所有组件都需要更新,并且确信这个节点一定发生了变化,因此不需要经过虚拟DOM对比,那么如果我们能绕开setState,动画就应该会更流畅,即使在复杂的视图里边。这就是Animations文档最后提到的setNativeProps方法。
As mentioned in the Direction Manipulation section, setNativeProps allows us to modify properties of native-backed components (components that are actually backed by native views, unlike composite components) directly, without having to setState and re-render the component hierarchy.
setNativeProps允许我们直接操纵原生组件的属性,而不需要用到setState,也不会重绘继承链上的其他组件。这正是我们想要的效果,加上我们明确知道正在操纵的组件以及它与视图其他组件的关系,因此,这里我们可以放心地使用它,而且相当简单。
更新前:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
loopAnimation(){ var t0=animationT,t1=t0+0.5,t2=t1+0.5,t3=t2+timeDelay,t4=t3+0.5;//这里分别是四个动画的当前时间,依次加上了0.5的延迟 var v1=Number(Math.cos(t0).toFixed(2))*animationN+animationM;//将cos函数的小数值只精确到小数点2位,提高运算效率 var v2=Number(Math.cos(t1).toFixed(2))*animationN+animationM; var v3=Number(Math.cos(t2).toFixed(2))*animationN+animationM; var v4=Number(Math.cos(t3).toFixed(2))*animationN+animationM; this.setState({ fV:v1, sV:v2, tV:v3, foV:v4 }); animationT+=0.35;//增加时间值,每次增值越大动画越快 requestAnimationFrame(this.loopAnimation.bind(this)); } |
更新后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
loopAnimation(){ var t0=··· var v1=··· var v2=··· var v3=··· var v4=··· this.refs.line1.setNativeProps({ style:{width:w1,height:v1} }); this.refs.line2.setNativeProps({ style:{width:w2,height:v2} }); this.refs.line3.setNativeProps({ style:{width:w3,height:v3} }); this.refs.line4.setNativeProps({ style:{width:w4,height:v4} }); animationT+=0.35;//增加时间值,每次增值越大动画越快 requestAnimationFrame(this.loopAnimation.bind(this)); } |
效果如下:
这里有意在注册请求完毕之后没有隐藏loading动画,因此同时执行了视图切换和loading两个动画,效果还行~
好了,该进入今天的正题了。先整体看一下这一阶段实现的效果(哒哒哒~):
主要是模拟了一个新用户注册流程,实现起来也并不复杂,整体结构是用一个RN组件Navigator来做导航,虽然有另一个NavigatorIOS组件在iOS系统上表现更加优异,但是考虑到RN本身希望能够同时在安卓和iOS上运行的初衷,我选择了可以兼容两个平台的Navigator来尝试,目前来看效果还能接受。
在最后的详细信息视图里边,尝试了各种组件,比如调用相机,Switch,Slider等,主要是尝鲜,哈哈~ 也自己实现了比较简单的check按钮。
首先最外层的结构是一个Navigator,它控制整个用户注册的视图切换:
1 2 3 4 5 6 7 8 9 |
<Navigator style={styles.navWrap} initialRoute={{name: 'login', component:LoginView}} configureScene={(route) => { return Navigator.SceneConfigs.FloatFromRight; }} renderScene={(route, navigator) => { let Component = route.component; return <Component {...route.params} navigator={navigator} /> }} /> |
其中,initialRoute配置了Navigator的初始组件,这里就是LoginView组件,它本身既可以直接登录,也可以点击【我要注册】进入注册流程。configureScene属性则是用来配置Navigator中视图切换的动画类型,这里可以灵活配置切换方式: