资讯专栏INFORMATION COLUMN

【译】React Native 动画 API 入门实例

qianfeng / 1829人阅读

摘要:简而言之,它将对动画中变化的属性数值做插值运算并且刷新视图。注意我们所建立的的是的一个实例。最后我们使用,表示这个组件是可动画组件。一直不停动动画序列的方法可以传一个回调函数,在动画全部执行完时触发。

翻译自 React-native Animated API Basic Example
翻译过程中有删改

简介

本文是探索 react-native 中实现的的 Animated API,Web 版本上的 React 没有该 API,不过可以使用在 react-europe 大会上发布的 react-motion。
本文中将会完成一个动画例子,效果如下图

原理

Animated API的原理并非通过 setState 方法使 react 重渲染,而是使用 setNativeProps 方法更新 native 视图。
Animated API 导出了几个特殊的 components:Animated.View, Animated.Text, 和 Animated.Image。Animated API 直接在 Objective-C 的 native 环境中调整这些 components 的外观样式,跳过了 JS 环境中 react 的 diff 与 reconciliation 过程,从而获得流畅、高效的动画。
简而言之,它将对动画中变化的属性数值做插值运算并且刷新 native 视图。

动画效果:沿屏幕移动的方块

我们将实现一个简单的动画效果:沿手机屏幕四个边,按照左上角 -> 左下角 -> 右下角 -> 右上角的顺序,移动一个正方形。示意图大概如下

< -- <           
|    |          
V -- ^  
开始 导入依赖
import React, {  
    AppRegistry,
    Component, 
    Dimensions,  
    StyleSheet,  
    View,  
    Animated 
} from "react-native";
const { width,  height } = Dimensions.get("window");
const SQUARE_DIMENSIONS = 30;
样式
const styles = StyleSheet.create({  
    container: {    
        flex: 1  
    },  
    square: {    
        width: SQUARE_DIMENSIONS,    
        height: SQUARE_DIMENSIONS,    
        backgroundColor: "blue"  
    } 
});
基本逻辑
class AnimatedSquare extends Component {
    constructor(props) {
        super(props);

        this.state = {
            pan: new Animated.ValueXY()
        }
    }
    
    getStyle() {
        return [styles.square, {
            transform: this.state.pan.getTranslateTransform()
        }];
    }
    
    render() {
        return (
          
              
          
        );
    }
}

上面代码中有几个需要解释的地方。
注意我们所建立的 componentstateAnimated.ValueXY 的一个实例。这个 API 将在 XY 两个值上进行插值。

getStyle() 方法,返回一个样式对象数组。包括描述了方块宽高大小的 square 基本样式,以及最为重要的,一个 transform 样式对象。
我们使用 getTranslateTransform 这个 Animated API 中的 helper 方法,来返回一个适合 transform 属性结构的值。
这个返回值的结构类似于[{ translateX: xValue}, {translateY: yValue}],xValue 和 yValue 是计算后的插值。

最后我们使用 Animated.View,表示这个组件是可动画组件。

移动正方形

一开始正方形是静止在左上角的,现在我们把它从左上角(x = 0, y = 0)移动到左下角(x = 0, y = (屏幕高 - 正方形高)

const SPRING_CONFIG = {tension: 2, friction: 3}; //Soft spring
//...
    componentDidMount() {
        Animated.spring(this.state.pan, {
          ...SPRING_CONFIG,
          toValue: {x: 0, y: height - SQUARE_DIMENSIONS}  // return to start
        }).start();
    }

在组件装载后,我们通过 Animated.spring 进行 Spring(弹性)动画 ,我们给弹性动画设置了 SPRING_CONFIG 配置,包括 tension(张力)和 friction(摩擦)值,所以正方形到达左下角后,会有一个小小回弹动画。

再动,又动,还动

我们会建立一个顺序的动画序列,让动画一个接一个进行。当然除了 sequence(顺序),你还可以按 parallel(并行)组合动画效果,让动画同时进行。

componentDidMount() {
    Animated.sequence([
      Animated.spring(this.state.pan, {
        ...SPRING_CONFIG,
        toValue: {x: 0, y: height - SQUARE_DIMENSIONS} //animate to bottom left
      }),
      Animated.spring(this.state.pan, {
          ...SPRING_CONFIG,
          toValue: {x: width - SQUARE_DIMENSIONS, y: height - SQUARE_DIMENSIONS} // animated to bottom right
      }),
      Animated.spring(this.state.pan, {
          ...SPRING_CONFIG,
          toValue: {x: width - SQUARE_DIMENSIONS, y: 0} //animate to top right
      }),
      Animated.spring(this.state.pan, {
          ...SPRING_CONFIG,
          toValue: {x: 0, y: 0} // return to start
      })
    ]).start();
}

如之前设想的一样,我们定义了4个弹性动画。注释解释了动画移动方向。

一直不停动
Animated.sequence(animtionList: Arrary).start(cb: Function);

动画序列的start方法可以传一个回调函数,在动画全部执行完时触发。在我们的例子中,这时候正方形回到了起点,我们可以重新开始一遍动画。

componentDidMount() {
    this.startAndRepeat();
}

startAndRepeat() {
    this.triggerAnimation(this.startAndRepeat);
}

triggerAnimation(cb) {
    Animated.sequence([
        Animated.spring(this.state.pan, {
            ...SPRING_CONFIG,
            toValue: {x: 0, y: height - SQUARE_DIMENSIONS} //animate to bottom left
        }),
        Animated.spring(this.state.pan, {
            ...SPRING_CONFIG,
            toValue: {x: width - SQUARE_DIMENSIONS, y: height - SQUARE_DIMENSIONS} // animated to bottom right
        }),
        Animated.spring(this.state.pan, {
            ...SPRING_CONFIG,
            toValue: {x: width - SQUARE_DIMENSIONS, y: 0} //animate to top right
        }),
        Animated.spring(this.state.pan, {
            ...SPRING_CONFIG,
            toValue: {x: 0, y: 0} // return to start
        })
     ]).start(cb);
 }

我们把动画逻辑提取为一个方法,在完成回调函数中触发它。

全部代码
import React, {  
    AppRegistry,
    Component, 
    Dimensions,  
    StyleSheet,  
    View,  
    Animated 
} from "react-native";
const { width,  height } = Dimensions.get("window");
const SQUARE_DIMENSIONS = 30;

const SPRING_CONFIG = {tension: 2, friction: 3};


class AnimatedSquare extends Component {
    constructor(props) {
        super(props);

        this.state = {
            pan: new Animated.ValueXY()
        }
    }
    
    componentDidMount() {
        this.startAndRepeat();
    }

    startAndRepeat() {
        this.triggerAnimation(this.startAndRepeat);
    }
    
    triggerAnimation(cb) {
        Animated.sequence([
            Animated.spring(this.state.pan, {
                ...SPRING_CONFIG,
                toValue: {x: 0, y: height - SQUARE_DIMENSIONS} //animate to bottom left
            }),
            Animated.spring(this.state.pan, {
                ...SPRING_CONFIG,
                toValue: {x: width - SQUARE_DIMENSIONS, y: height - SQUARE_DIMENSIONS} // animated to bottom right
            }),
            Animated.spring(this.state.pan, {
                ...SPRING_CONFIG,
                toValue: {x: width - SQUARE_DIMENSIONS, y: 0} //animate to top right
            }),
            Animated.spring(this.state.pan, {
                ...SPRING_CONFIG,
                toValue: {x: 0, y: 0} // return to start
            })
         ]).start(cb);
    }
     
    getStyle() {
        return [styles.square, {
            transform: this.state.pan.getTranslateTransform()
        }];
    }
    
    render() {
        return (
          
              
          
        );
    }
}

const styles = StyleSheet.create({  
    container: {    
        flex: 1  
    },  
    square: {    
        width: SQUARE_DIMENSIONS,    
        height: SQUARE_DIMENSIONS,    
        backgroundColor: "blue"  
    } 
});

AppRegistry.registerComponent("AnimatedSquare", () => AnimatedSquare);
其它一些范例

react-native-animated-demo-tinder
UIExplorer Animated example

相关资源

Cheng Lou – The State of Animation in React at react-europe 2015
react-motion – Github
React Native Animation API
Spencer Ahrens – React Native: Building Fluid User Experiences at react-europe 2015

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78952.html

相关文章

  • 3月份前端资源分享

    摘要:面试如何防骗一份优秀的前端开发工程师简历是怎么样的作为,有哪些一般人我都告诉他,但是他都不听的忠告如何面试前端工程师 更多资源请Star:https://github.com/maidishike... 文章转自:https://github.com/jsfront/mo... 3月份前端资源分享 1. Javascript 使用judge.js做信息判断 javascript...

    nanchen2251 评论0 收藏0
  • 正在失业中的《课多周刊》(第3期)

    摘要:正在失业中的课多周刊第期我们的微信公众号,更多精彩内容皆在微信公众号,欢迎关注。若有帮助,请把课多周刊推荐给你的朋友,你的支持是我们最大的动力。是一种祸害译本文浅谈了在中关于的不好之处。浅谈超时一运维的排查方式。 正在失业中的《课多周刊》(第3期) 我们的微信公众号:fed-talk,更多精彩内容皆在微信公众号,欢迎关注。 若有帮助,请把 课多周刊 推荐给你的朋友,你的支持是我们最大的...

    robin 评论0 收藏0
  • 正在失业中的《课多周刊》(第3期)

    摘要:正在失业中的课多周刊第期我们的微信公众号,更多精彩内容皆在微信公众号,欢迎关注。若有帮助,请把课多周刊推荐给你的朋友,你的支持是我们最大的动力。是一种祸害译本文浅谈了在中关于的不好之处。浅谈超时一运维的排查方式。 正在失业中的《课多周刊》(第3期) 我们的微信公众号:fed-talk,更多精彩内容皆在微信公众号,欢迎关注。 若有帮助,请把 课多周刊 推荐给你的朋友,你的支持是我们最大的...

    Joyven 评论0 收藏0
  • 1月份前端资源分享

    摘要:更多资源请文章转自月份前端资源分享视频前端技术论坛融合不可错过的迷你库测试框架实例教程为你详细解读请求头的具体含意解析的库如果要用前端框架,开发流程是怎样的与有什么区别正确使用的方法是什么流程图插件小如何让元素只能输入纯文本前端技术中 更多资源请Star:https://github.com/maidishike... 文章转自:https://github.com/jsfront...

    solocoder 评论0 收藏0

发表评论

0条评论

qianfeng

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<