使用React-Native-ART实现声波、水波纹、波浪线动画效果(附源码)

背景

笔者最近有个RN项目,需要在与设备通话的时候,App侧展示声波纹UI效果,以笔者的尿性又去折腾整理了一番,同样也非常适用想了解react-native art绘图入门基础的同学。

在React Native中有个ART库,它可以绘制各种线(实线、虚线、曲线)、图形(矩形、圆、扇形)组合,让非常酷炫的绘图及动画变成了可能。

至于水波纹、波浪动画、声波音频这些常用的效果,一般都是贝塞尔曲线加持画出来的。

水波纹.jpg

一、UI效果展示

以下是我是整理和改进UI效果,基本能满足项目需要

水波纹波浪曲线

水波纹.gif
水波纹电量.gif

声音声波曲线

声波1.gif

声波2.gif

下载速率曲线

下载速率.gif

二、源码下载

源码有需要的就拿去吧,代码实现就不一一贴出来解析了。然后针对ART这个知识点做一下梳理,做了一个演示DEMO,这样会有一个大概的了解。

=====> React-Native使用ART实现水波纹动画、波浪线、声波音频波动效果(附源码)

三、知识点梳理

添加依赖

Android默认就包含ART库,IOS需要单独添加依赖库。

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

导入ART库

import {
    ART
} from 'react-native';
 
const {
   Surface, Shape, Path, Group, Text
} = ART;

基础组件

Surface:一个矩形可渲染的区域,是其他元素的容器
width:渲染区域的宽
height:定义渲染区域的高

Group:可容纳多个形状、文本和其他的分组

Shape:形状定义,可填充
d:定义绘制路径
stroke:描边颜色
strokeWidth:描边宽度
strokeDash:定义虚线
fill:填充颜色

Text:文本形状定义
font:字体样式,定义字体、大小、粗细等,如bold 35px Heiti SC

Path:Shape的属性值 表示绘制的路径
moveTo(x,y):移动到坐标(x,y)
lineTo(x,y):连线到坐标(x,y)
line(x,y): 相对于原来的偏移
arc():绘制弧线
close():封闭空间

Path().moveTo(20, 20).lineTo(10, 20) 得到的是一条(20, 20) 到(10, 20) 的线。
Path().moveTo(20, 20).line(10, 20) 得到的是一条(20, 20) 到(30, 40) 的线。
Path().moveTo(150,50).arc(50, 100,50) 绘制一半圆弧(150,50)起点,(50, 100)偏移量(终点) 50 半径。

四、DEMO示例

Demo图效

效果如下,代码不复杂的,聪明如你看看就明白,基本组件的操作下面也举例说明了

基础元素

1.jpg

圆形、圆环、扇形、椭圆

2.jpg

三角形、半圆

3.jpg

多边形

4.jpg

直线

了解Path的moveTo和LineTo的使用

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

export default class Line extends React.Component{

    render(){

        const path = ART.Path();
        path.moveTo(1,1); //将起始点移动到(1,1) 默认(0,0)
        path.lineTo(300,1); //连线到目标点(300,1)

        return(
            <View style={this.props.style}>
                <ART.Surface width={300} height={2}>
                    <ART.Shape d={path} stroke="#000000" strokeWidth={1} />
                </ART.Surface>
            </View>
        )
    }
}

虚线

了解strokeDash的参数,
[10,5] : 表示绘10像素实线在绘5像素空白,如此循环
[10,5,20,5] : 表示绘10像素实线在绘制5像素空白在绘20像素实线及5像素空白

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

export default class Line extends React.Component{

    render(){

        const path = ART.Path();
        path.moveTo(1,1); //将起始点移动到(1,1) 默认(0,0)
        path.lineTo(300,1); //连线到目标点(300,1)

        return(
            <View style={this.props.style}>
                <ART.Surface width={300} height={2}>
                    <ART.Shape d={path} stroke="#000000" strokeWidth={2} strokeDash={[10,10]} />
                </ART.Surface>
            </View>
        )
    }
}

折线

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

const {width,height} = Dimensions.get('window');

export default class Line extends React.Component{

    render(){

        // 构建折线路径
        const brokenLine = Path()
            .move(10,60)
            .line(80, 23)
            .line(60, -43)
            .line(70, 20);
            
        return(
            <View style={this.props.style}>
                  <Surface width={width} height={100}>
                        <Shape d={brokenLine} stroke="#000000" strokeWidth={2}  />
                   </Surface>
            </View>
        )
    }
}

曲线

了解curve的用法

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

const {width,height} = Dimensions.get('window');

export default class Line extends React.Component{

    render(){

        // 构建贝斯路径
        const curveLine = Path()
            .move(10,60)
            .curve(50, 23, 100, -23, 200, 0);
            
        return(
            <View style={this.props.style}>
                    <Surface width={width} height={100}>
                        <Shape d={curveLine} stroke="#000000" strokeWidth={2} />
                    </Surface>
            </View>
        )
    }
}

矩形

了解close()的使用,close的意思是创建一个密闭的路径。首先通过lineTo绘制三条边,在使用close链接第四条边。fill做颜色填充

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

const {Surface, Shape, Path} = ART;

export default class Rect extends React.Component{

    render(){

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

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

了解arc(x,y,radius)的使用, 终点坐标距离起点坐标的相对距离

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

const {Surface, Shape, Path} = ART;

export default class Circle extends React.Component{

    render(){

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


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

文本

了解font属性的使用,规则是“粗细 字号 字体”

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

const {Surface, Text, Path} = ART;

export default class ArtText extends  React.Component{


    render(){

        return(
            <View style={this.props.style}>
                <Surface width={200} height={100}>
                    <Text strokeWidth={1} stroke="#000" font="bold 35px Heiti SC" path={new Path().moveTo(40,40).lineTo(99,10)} >Hello World</Text>
                </Surface>
            </View>
        )
    }

}

扇形

注意这里封装了一个Wedge组件,内部还是使用arc做路径绘制,感兴趣的同学可以阅读一下代码

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

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

export default class Fan extends  React.Component{

    render(){

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

                </Surface>
            </View>
        )
    }
}

图层

了解Group的使用

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

const {Surface, Shape,Text, Path,Group} = ART;

export default class GroupTest extends React.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>
                <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>
        )
    }
}

以上整理,希望能帮助到有需要的同学,加油共勉!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,427评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,551评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,747评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,939评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,955评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,737评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,448评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,352评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,834评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,992评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,133评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,815评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,477评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,022评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,147评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,398评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,077评论 2 355

推荐阅读更多精彩内容