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

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

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

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

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

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

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

看看这段字符串 寓意
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相关的知识点

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

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

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

现在假设我们某个顶部的点是起始点(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;
    }
}

然后用到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轴旋转啥的默认不管,

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

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

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


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

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


- 使用方法很简单

- 复杂配置

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

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom