如何使用ART和Animated来实现自定义圆圈组件的动画

ART是React Naive下的绘图框架。

Android项目默认就包含ART库,而iOS需要单独添加依赖库。

方式一:

1.右键点击项目 -> ‘Add Files to ProjectName -> 选择 node_modules/react-native/React/Libraries/ART/ART.xcodeproj’
2.将 libART.a 添加到 Linked Frameworks and Libraries。

方式二:

cocoapods方式引入:
pod 'React-ART', :path => '../node_modules/react-native/Libraries/ART'

ART具体使用:官方文档

如果是自己通过ART写的自定义组件,而又希望能在该组件下编写动画。可以参考以下解决方案。

1.Animated具体使用: 官方文档

通过文档我们可以了解到,Animated默认所支持View类型只有:

Animated.Image
Animated.ScrollView
Animated.Text
Animated.View

这四种类型。所以,如果想要通过ART绘制的自定义View,我们需要借助

Animated.createAnimatedComponent()

接下来,我们通过ART绘制的圆圈,来配合Animted 实现一个简单的动画。

  1. 导入文件。(Circle是自定义绘制的圆圈组件)
import { Easing ,Animated} from 'react-native';
import Circle from './Circle'
  1. 处理Circle组件,让其具备有做动画的能力。
const AnimatedProgres = Animated.createAnimatedComponent(Circle);

3.定义动画value属性。

    constructor(props) {
        super(props);
        this.state = {
            fillAnimation: new Animated.Value(props.preValue),
        };
    }

4.设值。

    render() {
        return ;
    }

5.执行动画。

    componentDidMount() {
        this.animate();
    }
    animate(toVal, dur, ease) {
        const toValue = toVal >= 0 ? toVal : this.props.progress;
        const duration = dur || this.props.duration;
        const easing = ease || this.props.easing;
        const anim = Animated.timing(this.state.fillAnimation, {
            toValue,
            easing,
            duration,
        });
        anim.start(this.props.animatedCompelte);
        return anim;
    }

具体代码可以查看我的Demo:https://github.com/AutoJiang/animated-circle-progress

效果图

接下来,我们来了解一下,这个动态递增的Text动画是怎么做的。

刚开始,我想了一个比较粗糙的方法。
直接设置一个定时器,每隔0.01秒重复去更新值,然后刷新页面。
代码如下:

state = {
    count: 0,
}

countBegin(){
    setInterval(()=>{
        if(this.state.count != this.props.progress * 100){
            this.state.count++;
            this.setState({});
        }
    },10)
}

componentDidMount(){
    this.countBegin()
}

render(){  
    const {fontSize,progress,...other} = this.props;
    let progress1 = this.props.progress >= 1 ? 0.9999: this.props.progress;
    return 
        {this.state.count}
            %
         
    ;
}

通过上面的GIF动画可以观察到两个明显的问题。

  1. 两个动画是独立的,圆圈动画已经结束了,但是数字递增动画还没有。
  2. 数字递增动画不连贯,有明显的卡顿现象。

仔细琢磨一下也能够知道为什么,原因在于setState()调用得太频繁了,render函数不断的被调用,这是非常消耗性能的事情,再加上setInterval本身就不是一个很精准的定时器,所以这种方案本质上就是行不通的。
那么应该如何优雅的解决这个问题呢?
我通过观察官方文档得到了灵感:


未命名.png

既然Animated的设计缘由就是为了防止react重新渲染和重新调和的开销,那么我们为何不继续以Animated的方式去做这个数字递增的动画呢?
接下来,我只增加了一句代码。
在Circle.js的正中间,增加了一个基于progress字段的Text。


       {Math.round(progress*100)}%

优化后

由于圆圈progress的动画已经是做好的,所以我们利用这个字段写好代码,也能做出其他动画效果。

另附demo源码

你可能感兴趣的:(如何使用ART和Animated来实现自定义圆圈组件的动画)