ReactNative圆形进度条 ART Path arcTo 圆弧实现

首先来吐槽一番
Facebook 对ReactNative添加了ART库后 竟然没有官方文档说明这个咋用 简直可怕.... 并不是每个来做RN开发都是懂得前端常常使用SVG Path 这些东西的啊 大哥

同时相比于Android 等开发 RN还比较新 导致的结果是遇到问题后 能用的资料少啊。。。这种情况下 连最应该有的文档都没有 吐血三升先。。。

ReactNative圆形进度条 ART Path arcTo 圆弧实现_第1张图片
。。心里苦。。。

所以我就查了一下RN开发的绘图库ART 发现不是canvas之类的(Android中用canvas习惯了) 最可怕的是网上只有一些简单的关于ART的说明 和一个大兄弟封装了一个SVG基于ART的库 就和在前端使用SVG那样使用来绘制 我不想这样使用 就只能自己摸索着开始

在开始画圆弧进度条之前 我们可能要先熟悉一下SVG Path(RN的path内部工作也是一样的) 是如何工作的 以及 里面的一些参数的具体作用 这里 因为是对SVG Path的介绍 采用React.js画出一些效果 来看看path是如何绘制出我们想要的圆弧的 我这里也就根据几个效果简单说一下 具体可以自己去查相关的只是 SVG Path 关键词搜索就行

Path 圆弧绘制

d="M100,0 A50,50 0 0,1 100,100"

看看这段字符串 寓意
M开头表示在坐标轴中的起始位置x,y
A表示即将绘制圆弧 后面是绘制圆弧半径的意思 一个是x轴的半径 一个是y轴的半径 其实就是在用弧度把这两个点连起来的时候 x比y大 x方向就长一些 如果x=y=radius 就是一个圆的弧度
这里应该涉及到椭圆的相关知识 具体我也不太懂 大概猜是这个意思
继续 A50,50 0 0,1 100,100 这是一个完整圆弧的全部参数
先说最后的100,100 这个是结束点的坐标

ReactNative圆形进度条 ART Path arcTo 圆弧实现_第2张图片
150,70 结束坐标

0 0,1 第一个0是r轴的选择角度还是啥来着 默认是0不管他 具体我也不太清楚别人都是这么说的
第二个0是画大弧度还是小弧度 的意思 两个点可以画出弧度最小和最大 看图
ReactNative圆形进度条 ART Path arcTo 圆弧实现_第3张图片
0,1->小弧度

ReactNative圆形进度条 ART Path arcTo 圆弧实现_第4张图片
1,1->大弧度

再看0,1中的1 这个是镜像的意思 默认是顺时针方向 比如0->小弧度的这个图 是顺时针的情况 现在将1改成0 看图
ReactNative圆形进度条 ART Path arcTo 圆弧实现_第5张图片
0,0-->情况

ReactNative圆形进度条 ART Path arcTo 圆弧实现_第6张图片
1,0-->情况

还有一个渐变的使用 顺便也贴一个图吧
ReactNative圆形进度条 ART Path arcTo 圆弧实现_第7张图片
渐变效果

好了 A后面的几个参数的意思 这几个图应该能看懂了 如果我这里没有解释很清楚 (我也是刚会 可能解释不太清楚 ) 可以自己再去查查SVG Path相关的知识点


现在理解了这个Path的相关参数的含义 后面我们看RN的art的时候也就很好理解了 我们现在来看RN的ART怎么使用
从 ‘react-native中引入 ART’ ART中有一些模块
直接进去ReatART源码

ReactNative圆形进度条 ART Path arcTo 圆弧实现_第8张图片
ART源码提供的功能模块

东西还挺多的 这里我们用到Surface (Group(Shape(Path)))
然后这里我看见他有一个类 LinearGradient 这个应该是用来实现刚刚React中那种渐变效果的 但是这里我很努力地去把他这个和Shape对接起来
对于LinearGradient 这个对象 需要一个Colors集合 这个Color对象也是ReatART提供的
这里我不知道怎么构造这个LinearGradient对象 求教哪位会的 麻烦告诉我一下
ReactNative圆形进度条 ART Path arcTo 圆弧实现_第9张图片
LinearGradient

ReactNative圆形进度条 ART Path arcTo 圆弧实现_第10张图片
LinearGradient对象传入最后会走这个方法

现在转移到圆弧的进度条的中心思想来 先思考圆弧进度条怎么画

现在假设我们某个顶部的点是起始点(100,0)(top) 半径50
这样如果我们来画一个圆 四个最特殊的点的坐标如下
left-->(0,50)
bottom->(100,200)
right->(150,50)

ReactNative圆形进度条 ART Path arcTo 圆弧实现_第11张图片
圆的四个外围点

现在我们知道了这四个外围点坐标 这是特殊点 我们和容易画出来 现在问题是怎么画出剩余部分的 比如下图的 我们想滑到A点
ReactNative圆形进度条 ART Path arcTo 圆弧实现_第12张图片
A点的圆弧

想画到A点我们首先要找到A点的坐标 这里就要用到sin cos来计算 因为角度一定的情况下 确定了radius
那么在这个点就确定了 比如假设红色部分的角度是30度
那么 A点的坐标 就是 x=100+sin(角度) y=半径-cos(角度)
ReactNative圆形进度条 ART Path arcTo 圆弧实现_第13张图片
角度对于的值

因为sin cos涉及到正负 所以这里我们分层四部分处理
0-90 90-180 180-270 270-360
这里还要提醒一点 因为是圆弧 两点一个弧度 所以一整整圆不可能一个弧度完成(我是这么理解的 要是可以的话可以告诉我下 这样我代码部分也能简单点) 我们这里就转个弯 用两个半圆 左边半圆180-360 右边圆0-180 下面是计算公式 也是核心代码

/**
 * 计算目的坐标位置 右边 <180度的计算
 * @param progress
 * @param total
 * @param startX
 * @param startY
 */
function calTargetXY(progress, total, startX, startY, radius) {
    let degress = progress / total * 360;
    if (degress > 180) {
        //log(Tag, '强制 degress -> 180');
        degress = 180;
    }
    //log(Tag, "开始位置 " + startX + " " + startY + "  r: " + radius + " degress  " + degress);
    let target = [];
    if (degress <= 90) {
        degress = degress * 2 * Math.PI / 360;
        // log(Tag, "sin " + Math.sin(degress));
        let endx = startX + radius * Math.sin(degress);
        let endy = startY + radius - radius * Math.cos(degress);
        target.push(endx);
        target.push(endy);
        return target;
    }
    else if (degress <= 180) {
        degress = degress - 90;
        degress = degress * 2 * Math.PI / 360;
        //  log(Tag, "sin " + Math.sin(degress));
        let endx = startX + radius * Math.cos(degress);
        let endy = startY + radius + radius * Math.sin(degress);
        target.push(endx);
        target.push(endy);
        return target;
    }
}

/**
 * 左边圆的计算 >180度的计算
 * @param degress
 * @param startX
 * @param startY
 * @param radius
 */
function calTargetXY1(degress, startX, startY, radius) {
    let target = [];
    //log(Tag, "开始位置1 " + startX + " " + startY + "  r: " + radius + " degress  " + degress);
    if (degress > 360) {
        degress = 360;
    }
    if (degress <= 270) {
        degress = degress - 180;
        degress = degress * 2 * Math.PI / 360;
        //  log(Tag, Math.sin(degress));
        let endx = startX - radius * Math.sin(degress);
        let endy = startY - ( radius - +radius * Math.cos(degress));
        target.push(endx);
        target.push(endy);
        return target;
    } else if (degress <= 360) {
        degress = degress - 270;
        degress = degress * 2 * Math.PI / 360;
        let endx = startX - radius * Math.cos(degress);
        let endy = startY - radius - radius * Math.sin(degress);
        target.push(endx);
        target.push(endy);
        return target;
    }
}

然后用到Art中 我们先看看 Path提供的API 发现他自己封装了一层


ReactNative圆形进度条 ART Path arcTo 圆弧实现_第14张图片
Path源码

然后我们发现 他是继承了Path 然后自己实现了一些对外方法 我们看真实Path类 发现一个push方法


ReactNative圆形进度条 ART Path arcTo 圆弧实现_第15张图片
Path push方法

看到这里 push会先解析 说明传进来肯定是一个字符串
而且会带有m l s A M这些字母 然后这时候 是不是似曾相识 这东西不就是SVG path 里面 我们前面说的那一串字符串吗 "Mx,y Arx,ry 0 0,1 x1,y1"

这时候 我们看到A 他里面比较怪 顺序都是乱来的 我们比对前端的字符串 再来看看他的意思

"Arx,ry 0 0,1 x1,y1"
i=1;
case 'A': 
this.arcTo(p[i+5], p[i+6], p[i], p[i+1], p[i+3], !+p[i+4], p[i+2]); 
break;

>this.arcTo(p[i+5], p[i+6], p[i], p[i+1], p[i+3], !+p[i+4], p[i+2]); 
其实就是
this.arcTo(p[6], p[7], p[1], p[2], p[4], !+p[5], p[3]); 
也就是
this.arcTo(x1 ,y1, rx, ry, 0, 1, 0); 
0,1,0--》大小弧度,镜像与否,x轴旋转啥的默认不管,

然后这里我们发现其实push就已经能实现工作 只要我们在push里面传入想要的字符串就行
同理 我们直接用arcTo应该也是可以的
让我们来看看效果 先用push 看效果 画一个100,20起点 150,70,90度的圆弧


直接使用push

好 push 没问题 那我们在使用arcTo 刚刚上面已经分析过了


ReactNative圆形进度条 ART Path arcTo 圆弧实现_第16张图片
使用arcTo

然后看效果 一脸懵逼 卧槽 不按套路出牌
ReactNative圆形进度条 ART Path arcTo 圆弧实现_第17张图片
可怕。。。

artTo异常效果效果

是不是感觉要炸了 我也要炸了 不知道为什么他画出这个来 理论上来讲 两个点的圆弧 应该不会画出一个圆来 很奇怪 我也看了很久么看错有什么不对 希望有会的人告知一下 我们这里用push实现就行 也合理

其实说了那么多 重点实现进度的核心就两个
一个是根据角度计算终点坐标
一个是push方法
下面先看看整个的效果吧
因为进度条是一个单独的组件 中间区域留了一个位置 可以插入你想插入的View
效果图中间的数字动画使用Animated.createAnimatedComponent实现

  • 中间留空的区域 是根据传入的半径 获取到了圆的区域 在计算中间内切正方形的区域 在通过绝对布局left top实现 具体可以看代码


    ReactNative圆形进度条 ART Path arcTo 圆弧实现_第18张图片
    效果图

    ReactNative圆形进度条 ART Path arcTo 圆弧实现_第19张图片
    内容说明
  • 使用方法很简单


    ReactNative圆形进度条 ART Path arcTo 圆弧实现_第20张图片
    一个无动画 一个有动画
  • 复杂配置


    ReactNative圆形进度条 ART Path arcTo 圆弧实现_第21张图片
    很多的配置

代码就不贴了 github有
如果对RN的ART arcTo 圆弧 不太熟悉的 可以看看Demo 希望有帮助

github地址 点我点我 可以的话 给个star

star star star

当你在穿山越岭的另一边
我在孤独的路上没有尽头
一辈子有多少的来不及
发现已经失去
最重要的东西
恍然大悟早已远去
为何总是在犯错之后
开始相信错的是自己

你可能感兴趣的:(ReactNative圆形进度条 ART Path arcTo 圆弧实现)