React Native动画之Animated仿网易云音乐启动动画

    xiaoxiao2021-03-25  122

      动画对于一款APP的重要性,我想不用多说,想必不是搞开发的也明白,虽说APP的简洁实用性很重要,但UE也是同等重要的。http://blog.csdn.net/jj120522/article/details/52164714

          下面分析下网易云音乐的启动动画,一张开启图片缩放的同时首页也进行缩放,不过首页初始化的scale可能是1.5,总是初始化放大,然后缩放至正常状态,造成一种视觉冲击的效果,如果无法感受到的话,还是下载一枚用用。其实这种效果如果用原生开发的话,很简单,Activity之间跳转的动画配置下就完事了,这里简单讲下如何用React Native来实现跨平台的效果。

          Animated是一个动画库,用来创造流畅、强大、并且易于构建和维护的动画。

          最简单的工作流程就是创建一个Animated.Value,把它绑定到组件的一个或多个样式属性上。然后可以通过动画驱动它,譬如Animated.timing,或者通过Animated.event把它关联到一个手势上,譬如拖动或者滑动操作。除了样式,Animated.value还可以绑定到props上,并且一样可以被插值。

          用到的方法:

         static timing(value: AnimatedValue | AnimatedValueXY, config: TimingAnimationConfig) 

         推动一个值按照一个过渡曲线而随时间变化。Easing模块定义了一大堆曲线,你也可以使用你自己的函数。

         addListener(callback: ValueXYListenerCallback) 

         监测动画的变化,因为它并没有提供像原生那么全的方法:如:onAnimationStart,onAnimationEnd等,因此只能不停的进行检测。

    这里我们创建个splash组件,一般会在其constructor中进行声明:

    [javascript]  view plain  copy   constructor(props){       super(props);       //初始化两个变量,一个用于操作scale,一个用于操作opacity.       this.state={         bounceAnimValue:new Animated.Value(1),         opacityAnimValue:new Animated.Value(1),       };     }   然后在componentDidMount中进行启动:

    [javascript]  view plain  copy   componentDidMount(){       //第一参数是要修改的变量,第二个是配置config,       Animated.timing(         this.state.bounceAnimValue,         {           toValue: 0.8,           duration: 400,           delay:1000,           easing:Easing.linear,         }       ).start();       Animated.timing(         this.state.opacityAnimValue,         {           toValue:0,           duration:400,           delay:1000,           easing:Easing.linear,         }       ).start();          this.state.bounceAnimValue.addListener(value=>{         if(value.value=='0.8'){          this.props.onAnimEnd();         }       });     }  

    代码相对还算清晰,easing其实类似于安卓中的Interpolator,可以设置多种形式。

    这里用到addListener进行检测动画结束后进行回调给主页面。

    下面我们来看下如何render:

    [javascript]  view plain  copy   render(){       return(         <View style={[styles.container,this.props.style]}>           <Animated.Image             source={require('./images/splash.jpg')}             style={{               flex: 1,               width: Util.size.width,               height:null,               opacity: this.state.opacityAnimValue,               transform: [                 {scale: this.state.bounceAnimValue},               ],             }} />         </View>       );     }  

    注意:只有声明为可动画化的组件才能被关联动画。ViewText,还有Image都是可动画化的。

    如果你想让自定义组件可动画化,可以用createAnimatedComponent。如:

    [javascript]  view plain  copy   const AnimatedIcon = Animated.createAnimatedComponent(Icon);   。。。   <AnimatedIcon            size={60}            style={[styles.twitter,{transform:[{scale:this.state.transformAnim}]}]}            name="social-twitter"/>  

    以上是针对splash启动页的操作,同理我们也要对首页进行相应的动画,下面主要看下首页的render函数:

    [javascript]  view plain  copy   render(){       let defaultName='app';       let defaultComponent=App;          return (        <View style={styles.container}>           <View style={styles.main}>           <Animated.View        style={{               flex:1,               transform: [                 {scale: this.state.bounceAnimValue},                ]             }}>              <Navigator                initialRoute={{name:defaultName,component:defaultComponent}}                configureScene={()=>Navigator.SceneConfigs.PushFromRight}                renderScene={(route, navigator) => {                  let Component = route.component;                  return <Component {...route.params} navigator={navigator} />               }} />         </Animated.View>         </View>            {this.state.splashed?            null:            <Splash            style={{height:Util.size.height,position:'absolute'}}            onAnimEnd={this.onAnimEnd}            />          }            </View>       );     }  

    style:

    [javascript]  view plain  copy   var styles = StyleSheet.create({     container: {       flex: 1,       backgroundColor:'#fff'     },     main:{       height:Platform.OS==='android'?Util.size.height-24:Util.size.height,       width:Util.size.width,       position:'absolute',     }   });  

    看上去不难理解,将我们的Animated.View包裹住首页内容实现其整体动画效果。但这里有个需要注意的地方,由于splash组件和首页的Navigator组件是属于同一个页面内部,其实也就是splash组件在navigator组件的上方,但React Native并没有原生那么多种布局(直接用RelativeLayout包裹两个控件就成了),但在React Native中,想要实现其效果,需要用到absolute布局并且 设置宽和高。

    如图:红色:是最外层的组件,蓝色和黑色要想处于前后效果,需要都设置:

    {position:'absolute',width:300,height:500}固定大小,选用absolute布局这样就实现了这种形式。

    至此我们就写完了,下面我们看下效果吧

    源码链接

    转载请注明原文地址: https://ju.6miu.com/read-13006.html

    最新回复(0)