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

前端之家收集整理的这篇文章主要介绍了ReactNative 圆形进度条 ART Path arcTo 圆弧实现前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

因为现在简书发 如果图片不能用 点这里

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

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

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

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

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

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

0 0,1 第一个0是r轴的选择角度还是啥来着 默认是0不管他 具体我也不太清楚别人都是这么说的
第二个0是画大弧度还是小弧度 的意思 两个点可以画出弧度最小和最大 看图

0,1-></p>小弧度

1,1-></p>大弧度
再看0,1中的1 这个是镜像的意思 默认是顺时针方向 比如0->小弧度的这个图 是顺时针的情况 现在将1改成0 看图

0,0--></p>情况

1,0--></p>情况
还有一个渐变的使用 顺便也贴一个图吧

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


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

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

现在转移到圆弧的进度条的中心思想来 先思考圆弧进度条怎么画
@H_404_3@现在假设我们某个顶部的点是起始点(100,0)(top) 半径50
这样如果我们来画一个圆 四个最特殊的点的坐标如下
left–>(0,50)
bottom->(100,200)
right->(150,50)

现在我们知道了这四个外围点坐标 这是特殊点 我们和容易画出来 现在问题是怎么画出剩余部分的 比如下图的 我们想滑到A点

想画到A点我们首先要找到A点的坐标 这里就要用到sin cos来计算 因为角度一定的情况下 确定了radius
那么在这个点就确定了 比如假设红色部分的角度是30度
那么 A点的坐标 就是 x=100+sin(角度) y=半径-cos(角度)

因为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,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;
    }
}
@H_404_3@然后用到Art中 我们先看看 Path提供的API 发现他自己封装了一层

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

看到这里 push会先解析 说明传进来肯定是一个字符串
而且会带有m l s A M这些字母 然后这时候 是不是似曾相识 这东西不就是SVG path 里面 我们前面说的那一串字符串吗 “Mx,y Arx,ry 0 0,1 x1,y1”
这时候 我们看到A 他里面比较怪 顺序都是乱来的 我们比对前端的字符串 再来看看他的意思

"Arx,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+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); 
010--》大小弧度,镜像与否,x轴旋转啥的默认不管,
@H_404_3@然后这里我们发现其实push就已经能实现工作 只要我们在push里面传入想要的字符串就行
同理 我们直接用arcTo应该也是可以的
让我们来看看效果 先用push 看效果 画一个100,20起点 150,70,90度的圆弧

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

然后看效果 一脸懵逼 卧槽 不按套路出牌


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


@H_404_3@其实说了那么多 重点实现进度的核心就两个
一个是根据角度计算终点坐标
一个是push方法
下面先看看整个的效果
因为进度条是一个单独的组件 中间区域留了一个位置 可以插入你想插入的View
效果图中间的数字动画使用Animated.createAnimatedComponent实现
- 中间留空的区域 是根据传入的半径 获取到了圆的区域 在计算中间内切正方形的区域 在通过绝对布局left top实现 具体可以看代码


- 使用方法很简单

- 复杂配置


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

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

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

原文链接:https://www.f2er.com/react/305218.html

猜你在找的React相关文章