react-native-Art动画基础

一:基础:
ART:暴露了七个组件:
● Surface - 一个矩形可渲染的区域,是其他元素的容器!
● Group - 可容纳多个形状、文本和其他的分组
● Shape - 形状定义,可填充
● Text - 文本形状定义
props
● Surface
○ width : 渲染区域的宽
○ height : 定义渲染区域的高
● Shape
○ d : 定义绘制路径
○ stroke : 描边颜色
○ strokeWidth : 描边宽度
○ strokeDash : 定义虚线
○ fill : 填充颜色
● Text
○ funt : 字体样式,定义字体、大小、是否加粗 如: bold 35px Heiti SC
● Path
○ moveTo(x,y) : 移动到坐标(x,y)
○ lineTo(x,y) : 连线到(x,y)
○ arc() : 绘制弧线
○ close() : 封闭空间

二:实例
● 绘制直线:

import  React,{Component} from 'react';
import  {
 ART,
 View,
 StyleSheet,
} from 'react-native';

var {
  Surface,
  Group,
  Shape,
  Path
} = ART;

export default class  Note extends Component{
    render(){
         const path = Path()
            .moveTo(1,1)//移动起始点
            .lineTo(300,1);//绘制结束后的坐标点
        return(
            <View style={styles.container}>
                <Surface width={300} height={2}>
                    <Shape d={path} stroke="#000000" strokeWidth={1} />
                </Surface>
            </View>
        )
    }

}

var styles = StyleSheet.create({
  container: {
    paddingTop: 20,
  }
});
  注意Surface的宽高,就是视图能绘制的宽高

● 绘制虚线:

export default class  Note extends Component{
    render(){
         const path = Path()
            .moveTo(1,1)//移动起始点
            .lineTo(300,1);//绘制结束后的坐标点
        return(
           <View style={styles.container}>
                <Surface width={300} height={2}>
                    <Shape d={path} stroke="#000000" strokeWidth={2} strokeDash={[10,50]}/>
                </Surface>
            </View>
        )
    }

}
注意:strokeDash={[10,50]}表示:先绘制10像素的实线然后绘制50像素的虚线!

● 绘制矩形:

export default class  Note extends Component{
    render(){
         const path = new Path()
            .moveTo(1,1)
            .lineTo(1,99)
            .lineTo(99,99)
            .lineTo(99,1)
            .close();
        return(
           <View style={styles.container}>
                <Surface width={100} height={100}>
                  <Shape d={path} stroke="#000000" fill="#892265" strokeWidth={1} />
                </Surface>
            </View>
        )
    }

}

注意:close的意思是创建一个密闭的路径,首先通过linrTo绘制三条边,然后使用close链接第四条边。使用fill设置里面的填充色。

● 绘制圆形:

export default class  Note extends Component{
    render(){
         const path = new Path()
            .moveTo(50,1)
            .arc(0,99,25)
            .arc(0,-99,25)
            .close();

        return(
           <View style={styles.container}>
                <Surface width={100} height={100}>
                 <Shape d={path} stroke="#000000" strokeWidth={1}/>
                </Surface>
            </View>
        )
    }

}
  注意:acr(x,y,radius)终点坐标距离起始点的相对距离

● 绘制字体:

export default class  Note extends Component{
    render(){
        const   path=new Path()
        .moveTo(40,40)
        .lineTo(99,10);

        return(
           <View style={styles.container}>
                <Surface width={100} height={100}>
                   <Text strokeWidth={1} stroke="#000" font="bold 35px Heiti SC" path={path} >Swipe</Text>
                </Surface>
            </View>
        )
    }

}

注意:font的使用

● 绘制扇形:

const {Surface} = ART;
import Wedge from './Wedge'

export default class  Note extends Component{
    render(){
        const  path=new Path()
        .moveTo(40,40)
        .lineTo(99,10);

        return(
           <View style={styles.container}>
                 <Surface width={100} height={100}>
                    <Wedge
                     outerRadius={50}
                     startAngle={0}
                     endAngle={60}
                     originX={50}
                     originY={50}
                     fill="blue"/>

                </Surface>
            </View>
        )
    }

}
   注意:使用了一个React.art封装的一个组件Wedge;

● 图层叠加:

const {Surface, Shape,Text, Path,Group} = ART;
export default class  Note extends Component{
    render(){

        const pathRect = new Path()
            .moveTo(1,1)
            .lineTo(1,99)
            .lineTo(99,99)
            .lineTo(99,1)
            .close();

        const pathCircle = new Path()
            .moveTo(50,1)
            .arc(0,99,25)
            .arc(0,-99,25)
            .close();

        const pathText = new Path()
            .moveTo(40,5)
            .lineTo(40,99);


        return(
            <View style={styles.container}>
                <Surface width={100} height={100}>
                    <Group>
                        <Shape d={pathRect} stroke="#000000" fill="#000000" strokeWidth={1}/>
                        <Shape d={pathCircle} stroke="#FFFFFF" fill="#FFFFFF" strokeWidth={1}/>
                        <Text strokeWidth={1} strokeDash={[2,1,2,1]} stroke="#000" font="bold 30px Heiti SC" path={pathText} >Swipe</Text>
                    </Group>
                </Surface>
            </View>
        )
    }

}

注意:图层叠加,上一层的会覆盖下一层的,类似于安卓的帧布局!

三:高级例子:
效果图:

这里写图片描述

import React ,{
    Component
}from 'react';
import {
  ART as Art,
  StyleSheet,
  View,
  Dimensions,
  TouchableWithoutFeedback,
  Animated
} from 'react-native';

var HEART_SVG = "M130.4-0.8c25.4 0 46 20.6 46 46.1 0 13.1-5.5 24.9-14.2 33.3L88 153.6 12.5 77.3c-7.9-8.3-12.8-19.6-12.8-31.9 0-25.5 20.6-46.1 46-46.2 19.1 0 35.5 11.7 42.4 28.4C94.9 11 111.3-0.8 130.4-0.8"
var HEART_COLOR = 'rgb(226,38,77,1)';
var GRAY_HEART_COLOR = "rgb(204,204,204,1)";

var FILL_COLORS = [ 
  'rgba(221,70,136,1)',
  'rgba(212,106,191,1)',
  'rgba(204,142,245,1)',
  'rgba(204,142,245,1)',
  'rgba(204,142,245,1)',
  'rgba(0,0,0,0)'
];

var PARTICLE_COLORS = [
  'rgb(158, 202, 250)',
  'rgb(161, 235, 206)',
  'rgb(208, 148, 246)',
  'rgb(244, 141, 166)',
  'rgb(234, 171, 104)',
  'rgb(170, 163, 186)'
]

 getXYParticle=(total, i, radius)=> {
  var angle = ( (2*Math.PI) / total ) * i;

  var x = Math.round((radius*2) * Math.cos(angle - (Math.PI/2)));
  var y = Math.round((radius*2) * Math.sin(angle - (Math.PI/2)));
  return {
    x: x,
    y: y,
  }
}

 getRandomInt=(min, max)=> {
  return Math.floor(Math.random() * (max - min)) + min;
}

 shuffleArray=(array)=> {
    for (var i = array.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    return array;
}


var {
  Surface,
  Group,
  Shape,
  Path
} = Art;

//使用Animated.createAnimatedComponent对其他组件创建对话
//创建一个灰色的新型图片
var AnimatedShape = Animated.createAnimatedComponent(Shape);

var {
  width: deviceWidth,
  height: deviceHeight
} = Dimensions.get('window');

export default  class Key extends  Component{
  constructor(props) {
    super(props);

    this.state = {
       animation: new Animated.Value(0) 
    };
  }

  explode=()=> {
    Animated.timing(this.state.animation, {
      duration: 1500,
      toValue: 28
    }).start(() => {
      this.state.animation.setValue(0);
      this.forceUpdate();
    });
  }

  getSmallExplosions=(radius, offset)=> {
    return [0,1,2,3,4,5,6].map((v, i, t) => {

      var scaleOut = this.state.animation.interpolate({
        inputRange: [0, 5.99, 6, 13.99, 14, 21],
        outputRange: [0, 0, 1, 1, 1, 0],
        extrapolate: 'clamp'
      });

      var moveUp = this.state.animation.interpolate({
        inputRange: [0, 5.99, 14],
        outputRange: [0, 0, -15],
        extrapolate: 'clamp'
      });

      var moveDown = this.state.animation.interpolate({
        inputRange: [0, 5.99, 14],
        outputRange: [0, 0, 15],
        extrapolate: 'clamp'
      });

      var color_top_particle = this.state.animation.interpolate({
        inputRange: [6, 8, 10, 12, 17, 21],
        outputRange: shuffleArray(PARTICLE_COLORS)
      })

      var color_bottom_particle = this.state.animation.interpolate({
        inputRange: [6, 8, 10, 12, 17, 21],
        outputRange: shuffleArray(PARTICLE_COLORS)
      })

      var position = getXYParticle(7, i, radius)

      return (
        <Group 
          x={position.x + offset.x } 
          y={position.y + offset.y} 
          rotation={getRandomInt(0, 40) * i}
        >
          <AnimatedCircle 
            x={moveUp}
            y={moveUp}
            radius={15} 
            scale={scaleOut} 
            fill={color_top_particle} 
          />
          <AnimatedCircle 
            x={moveDown}
            y={moveDown}
            radius={8} 
            scale={scaleOut} 
            fill={color_bottom_particle} 
          />
        </Group>
      )
    }, this)
  }
  render() {
    var heart_scale = this.state.animation.interpolate({
      inputRange: [0, .01, 6, 10, 12, 18, 28],
      outputRange: [1, 0, .1, 1, 1.2, 1, 1],
      extrapolate: 'clamp'
    });

    var heart_fill = this.state.animation.interpolate({
      inputRange: [0, 2],
      outputRange: [GRAY_HEART_COLOR, HEART_COLOR],
      extrapolate: 'clamp'
    })

    var heart_x = heart_scale.interpolate({
      inputRange: [0, 1],
      outputRange: [90, 0],
    })

    var heart_y = heart_scale.interpolate({
      inputRange: [0, 1],
      outputRange: [75, 0],
    })

    var circle_scale = this.state.animation.interpolate({
      inputRange: [0, 1, 4],
      outputRange: [0, .3, 1],
      extrapolate: 'clamp'
    });

    var circle_stroke_width = this.state.animation.interpolate({
      inputRange: [0, 5.99, 6, 7, 10],
      outputRange: [0, 0, 15, 8, 0],
      extrapolate: 'clamp'
    });

    var circle_fill_colors = this.state.animation.interpolate({
      inputRange: [1, 2, 3, 4, 4.99, 5],
      outputRange: FILL_COLORS,
      extrapolate: 'clamp'
    })

    var circle_opacity = this.state.animation.interpolate({
      inputRange: [1,9.99, 10],
      outputRange: [1, 1, 0],
      extrapolate: 'clamp'
    })


    return (
      <View style={styles.container}>
        <TouchableWithoutFeedback onPress={this.explode} style={styles.container}> 
          <View style={{transform: [{scale: .8}]}}>
            <Surface width={deviceWidth} height={deviceHeight}>
              <Group x={75} y={200}>
             //是一个心形的图像
                <AnimatedShape
                  d={HEART_SVG}
                  x={heart_x}
                  y={heart_y}
                  scale={heart_scale}
                  fill={heart_fill}
                />
                <AnimatedCircle
                  x={89}
                  y={75}
                  radius={150}
                  scale={circle_scale}
                  strokeWidth={circle_stroke_width}
                  stroke={FILL_COLORS[2]}
                  fill={circle_fill_colors}
                  opacity={circle_opacity}
                />

                {this.getSmallExplosions(75, {x:89, y:75})}
              </Group>
            </Surface>
          </View>
        </TouchableWithoutFeedback>
      </View>
    );
  }
};

class  AnimatedCircle  extends  Component{
  render(){
     var radius = this.props.radius;
    var path = Path().moveTo(0, -radius)
        .arc(0, radius * 2, radius)
        .arc(0, radius * -2, radius)
        .close();
    return  React.createElement(AnimatedShape, React.__spread({},  this.props, {d: path}));
  }
}

var styles = StyleSheet.create({
  container: {
    flex: 1,
  }
});

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值