• 圆环进度条 两种实现方式


    先看图效果图:

    这边UI的 设计图 长这样

     

     一个圆环的进度展示,这个圆环上开始位置 是齐口的,终点圆口,并且有一个圆;

    列举了两种实现方式:

    • 第一种 纯的CSS实现;原理是 叠加旋转 而成。缺点在某些机型上面应为遮罩没有对齐(uniapp 半个像素不显示的问题,其他平台没有这问题),会出现白边(没有遮挡好的情况)
    •  第二种 createCanvasContext 直接画弧线;动态计算原点位置 叠加 显示

    第一种实现方式 

    理论上:纯css  两个半圆在相应的取值范围内 旋转,旋转的时候被父对象 遮罩剩余的部分

    第一步: 两个半圆在旋转,旋转时候被父对象 clip 掉 剩余部分,两个红色底就是两个半圆的父元素,红色第里面的两个深色块就是 将要旋转的 元素;

    1. <view class="box0-parent">
    2. <view class="box0" :style="box0Style">
    3. </view>
    4. </view>
    5. <view class="box1-parent">
    6. <view class="box1" :style="box1Style">
    7. </view>
    8. </view>
    9. .box0-parent {
    10. position: absolute;
    11. top: 580rpx;
    12. width: 284rpx;
    13. height: 284rpx;
    14. background-color: #dd2124;
    15. clip: rect(0px, 142rpx, 284rpx, 0px);
    16. // border-radius: 50%;
    17. .box0 {
    18. position: absolute;
    19. top: 0;
    20. width: 284rpx;
    21. height: 284rpx;
    22. background-color: #2C405A;
    23. clip: rect(0px, 142rpx, 284rpx, 0px);
    24. border-radius: 50%;
    25. }
    26. }
    27. .box1-parent {
    28. position: absolute;
    29. top: 580rpx;
    30. width: 284rpx;
    31. height: 284rpx;
    32. background-color: #c34c24;
    33. clip: rect(0px, 284rpx, 284rpx, 142rpx);
    34. // border-radius: 50%;
    35. .box1 {
    36. position: absolute;
    37. top: 0;
    38. width: 284rpx;
    39. height: 284rpx;
    40. background-color: #5a4600;
    41. clip: rect(0px, 284rpx, 284rpx, 142rpx);
    42. border-radius: 50%;
    43. // transform: rotate(60deg);
    44. }
    45. }

     第二步: 调整下参数; 再调下颜色

    1. <template>
    2. <view class="process">
    3. <view class="box0-parent">
    4. <view class="box0" :style="box0Style">
    5. </view>
    6. </view>
    7. <view class="box1-parent">
    8. <view class="box1" :style="box1Style">
    9. </view>
    10. </view>
    11. <view class="input-range">
    12. <text> {{percent}}%</text> <text style="margin-left: 100rpx;">{{percent*3.6}}</text>
    13. <slider @changing="onChange" value="0" max="100" min="0" v-model="percent" activeColor="#FFCC33"
    14. backgroundColor="#000000" block-color="#8A6DE9"></slider>
    15. </view>
    16. </view>
    17. </template>
    18. <script>
    19. export default {
    20. data() {
    21. return {
    22. percent: 30,
    23. }
    24. },
    25. computed: {
    26. box0Style() {
    27. if (this.percent >= 50) {
    28. return `transform: rotate(${180 + this.percent*3.6}deg)`
    29. } else {
    30. return ``
    31. }
    32. },
    33. box1Style() {
    34. if (this.percent <= 50) {
    35. return `transform: rotate(${this.percent*3.6}deg)`
    36. } else {
    37. return `display: none;`
    38. }
    39. }
    40. },
    41. methods: {
    42. onChange(value) {
    43. // console.log(value.detail.value)
    44. this.percent = value.detail.value
    45. }
    46. }
    47. }
    48. </script>
    49. <style lang="scss" scoped>
    50. .process {
    51. width: 100%;
    52. display: flex;
    53. flex-direction: column;
    54. justify-content: center;
    55. align-items: center;
    56. .input-range {
    57. position: absolute;
    58. top: 980rpx;
    59. width: 300rpx;
    60. }
    61. .box0-parent {
    62. position: absolute;
    63. top: 580rpx;
    64. width: 284rpx;
    65. height: 284rpx;
    66. background-color: #dd2124;
    67. clip: rect(0px, 142rpx, 284rpx, 0px);
    68. // border-radius: 50%;
    69. .box0 {
    70. position: absolute;
    71. top: 0;
    72. width: 284rpx;
    73. height: 284rpx;
    74. //background-color: #2C405A;
    75. background-color: #2168F9;
    76. clip: rect(0px, 142rpx, 284rpx, 0px);
    77. border-radius: 50%;
    78. }
    79. }
    80. .box1-parent {
    81. position: absolute;
    82. top: 580rpx;
    83. width: 284rpx;
    84. height: 284rpx;
    85. //background-color: #c34c24;
    86. background-color: #dd2124;
    87. // background-color: #2168F9;
    88. clip: rect(0px, 284rpx, 284rpx, 142rpx);
    89. // border-radius: 50%;
    90. .box1 {
    91. position: absolute;
    92. top: 0;
    93. width: 284rpx;
    94. height: 284rpx;
    95. // background-color: #5a4600;
    96. background-color: #2168F9;
    97. clip: rect(0px, 284rpx, 284rpx, 142rpx);
    98. border-radius: 50%;
    99. // transform: rotate(60deg);
    100. }
    101. }
    102. }
    103. </style>

    然后加上蓝色底色,圆环换上白色;真理下就能得到这么的 圆环了;

    至于 白色圆点  直接绝对定位于半圆, 随着半圆移动即可;每个半圆都有一个

    第二种实现方式

    使用的是 canvas 中的 arc  (画弧线来实现的)

    uni.createCanvasContexthttps://uniapp.dcloud.io/api/canvas/CanvasContext.html

    1. <canvas class="canvas-content" :canvas-id="canvasId" :id="canvasId">
    2. </canvas>
    3. methods: {
    4. onChange(value) {
    5. // console.log(value.detail.value)
    6. this.percent = value.detail.value
    7. this.drawCircleByProgress()
    8. },
    9. drawCircleByProgress(){
    10. // 表示进度的两端为圆形 目前没有找到只设置一段的方式
    11. this.canvasContent.setLineCap('round'); //圆形
    12. this.canvasContent.setLineCap('square'); //方形
    13. // 设置线条的宽度和颜色
    14. this.canvasContent.setLineWidth(uni.upx2px(30));
    15. this.canvasContent.setStrokeStyle('#ff0000');
    16. let endAngle = ((2 * Math.PI) / 100) * this.percent + this.startAngle;
    17. this.canvasContent.beginPath();
    18. // 半径为整个canvas宽度的一半
    19. let radius = uni.upx2px(284) / 2;
    20. this.canvasContent.arc(radius, radius, radius - uni.upx2px(30), this.startAngle, endAngle, false);
    21. this.canvasContent.stroke();
    22. this.canvasContent.draw();
    23. }
    24. }
    25. .canvas-content{
    26. width: 284rpx;
    27. height: 284rpx;
    28. background-color: #059cdd;
    29. }

    这种方式对于圆环中的 画一个白色球需要通过 弧度计算圆上一点的位置

    1. drawCircleByProgress() {
    2. // 表示进度的两端为圆形 目前没有找到只设置一段的方式
    3. this.canvasContent.setLineCap('round'); //圆形
    4. this.canvasContent.setLineCap('square'); //方形
    5. let width = uni.upx2px(30)
    6. // 设置线条的宽度和颜色
    7. this.canvasContent.setLineWidth(width);
    8. this.canvasContent.setStrokeStyle('#ff0000');
    9. // 画圆环
    10. let endAngle = ((2 * Math.PI) / 100) * this.percent + this.startAngle;
    11. this.canvasContent.beginPath();
    12. // 半径为整个canvas宽度的一半
    13. let radius = uni.upx2px(284) / 2;
    14. this.canvasContent.arc(radius, radius, radius - width, this.startAngle, endAngle, false);
    15. this.canvasContent.stroke();
    16. //原点要在 圆弧前面一点点的位置 所有这个加了 0.1;
    17. let p0x = radius + Math.cos(endAngle + .1) * (radius - width)
    18. let p0y = radius + Math.sin(endAngle + .1) * (radius - width)
    19. // 画圆球
    20. this.canvasContent.beginPath()
    21. this.canvasContent.arc(p0x, p0y, width / 2, 0, 2 * Math.PI)
    22. this.canvasContent.setFillStyle('#F0AD4E');
    23. this.canvasContent.fill()
    24. // 画白色圆球
    25. this.canvasContent.beginPath()
    26. this.canvasContent.arc(p0x, p0y, width * 0.4, 0, 2 * Math.PI)
    27. this.canvasContent.setFillStyle('#FFFFFF');
    28. this.canvasContent.fill()
    29. this.canvasContent.draw();
    30. }

    真理下就能得到下面的例子了

    完整代码:

    1. <template>
    2. <view class="process">
    3. <canvas class="canvas-content" :canvas-id="canvasId" :id="canvasId">
    4. </canvas>
    5. <view class="box0-parent">
    6. <view class="box0" :style="box0Style">
    7. </view>
    8. </view>
    9. <view class="box1-parent">
    10. <view class="box1" :style="box1Style">
    11. </view>
    12. </view>
    13. <view class="input-range">
    14. <text> {{percent}}%</text> <text style="margin-left: 100rpx;">{{percent*3.6}}</text>
    15. <slider @changing="onChange" value="0" max="100" min="0" v-model="percent" activeColor="#FFCC33"
    16. backgroundColor="#000000" block-color="#8A6DE9"></slider>
    17. </view>
    18. </view>
    19. </template>
    20. <script>
    21. export default {
    22. data() {
    23. return {
    24. percent: 30,
    25. canvasId: 'canvasId',
    26. canvasContent: null,
    27. startAngle: -Math.PI / 2, //canvas画圆的起始角度,默认为3点钟方向即90度 方向,定位位到12位置 0度
    28. }
    29. },
    30. computed: {
    31. box0Style() {
    32. if (this.percent >= 50) {
    33. return `transform: rotate(${180 + this.percent*3.6}deg)`
    34. } else {
    35. return ``
    36. }
    37. },
    38. box1Style() {
    39. if (this.percent <= 50) {
    40. return `transform: rotate(${this.percent*3.6}deg)`
    41. } else {
    42. return `display: none;`
    43. }
    44. }
    45. },
    46. onShow() {
    47. this.canvasContent = uni.createCanvasContext(this.canvasId, this)
    48. this.drawCircleByProgress()
    49. },
    50. methods: {
    51. onChange(value) {
    52. // console.log(value.detail.value)
    53. this.percent = value.detail.value
    54. this.drawCircleByProgress()
    55. },
    56. drawCircleByProgress() {
    57. // 表示进度的两端为圆形 目前没有找到只设置一段的方式
    58. this.canvasContent.setLineCap('round'); //圆形
    59. this.canvasContent.setLineCap('square'); //方形
    60. let width = uni.upx2px(30)
    61. // 设置线条的宽度和颜色
    62. this.canvasContent.setLineWidth(width);
    63. this.canvasContent.setStrokeStyle('#ff0000');
    64. let endAngle = ((2 * Math.PI) / 100) * this.percent + this.startAngle;
    65. this.canvasContent.beginPath();
    66. // 半径为整个canvas宽度的一半
    67. let radius = uni.upx2px(284) / 2;
    68. this.canvasContent.arc(radius, radius, radius - width, this.startAngle, endAngle, false);
    69. this.canvasContent.stroke();
    70. //原点要在 圆弧前面一点点的位置 所有这个加了 0.1;
    71. let p0x = radius + Math.cos(endAngle + .1) * (radius - width)
    72. let p0y = radius + Math.sin(endAngle + .1) * (radius - width)
    73. this.canvasContent.beginPath()
    74. this.canvasContent.arc(p0x, p0y, width / 2, 0, 2 * Math.PI)
    75. this.canvasContent.setFillStyle('#F0AD4E');
    76. this.canvasContent.fill()
    77. this.canvasContent.beginPath()
    78. this.canvasContent.arc(p0x, p0y, width * 0.4, 0, 2 * Math.PI)
    79. this.canvasContent.setFillStyle('#FFFFFF');
    80. this.canvasContent.fill()
    81. this.canvasContent.draw();
    82. }
    83. }
    84. }
    85. </script>
    86. <style lang="scss" scoped>
    87. .process {
    88. width: 100%;
    89. display: flex;
    90. flex-direction: column;
    91. justify-content: center;
    92. align-items: center;
    93. .canvas-content {
    94. width: 284rpx;
    95. height: 284rpx;
    96. background-color: #059cdd;
    97. }
    98. .input-range {
    99. position: absolute;
    100. top: 750rpx;
    101. width: 300rpx;
    102. }
    103. .box0-parent {
    104. position: absolute;
    105. top: 380rpx;
    106. width: 284rpx;
    107. height: 284rpx;
    108. background-color: #dd2124;
    109. clip: rect(0px, 142rpx, 284rpx, 0px);
    110. // border-radius: 50%;
    111. .box0 {
    112. position: absolute;
    113. top: 0;
    114. width: 284rpx;
    115. height: 284rpx;
    116. //background-color: #2C405A;
    117. background-color: #2168F9;
    118. clip: rect(0px, 142rpx, 284rpx, 0px);
    119. border-radius: 50%;
    120. }
    121. }
    122. .box1-parent {
    123. position: absolute;
    124. top: 380rpx;
    125. width: 284rpx;
    126. height: 284rpx;
    127. //background-color: #c34c24;
    128. background-color: #dd2124;
    129. // background-color: #2168F9;
    130. clip: rect(0px, 284rpx, 284rpx, 142rpx);
    131. // border-radius: 50%;
    132. .box1 {
    133. position: absolute;
    134. top: 0;
    135. width: 284rpx;
    136. height: 284rpx;
    137. // background-color: #5a4600;
    138. background-color: #2168F9;
    139. clip: rect(0px, 284rpx, 284rpx, 142rpx);
    140. border-radius: 50%;
    141. // transform: rotate(60deg);
    142. }
    143. }
    144. }
    145. </style>

  • 相关阅读:
    web基础和http协议
    mysql的约束和表关系
    升降巡检机器人简介
    redis缓存击穿、穿透、雪崩
    【市场解读】掌握MT4外汇交易的核心技巧
    [C/C++]数据结构 链表OJ题:随机链表的复制
    Lesson 04 模板入门
    理论与实战:一篇看懂Python词云
    性能测试--线程的监控
    解析生成式人工智能 | 它真的有这么强大吗?
  • 原文地址:https://blog.csdn.net/nicepainkiller/article/details/125327485