文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

通过ArkUI实现波纹进度条

2024-12-13 14:54

关注

效果呈现

本示例最终效果如下:


运行环境

本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发:

实现思路

本示例涉及4个主要特性及其实现方案如下:

开发步骤

针对上述所提到的内容,具体实现步骤如下:

先使用Cricle组件绘制外层的圆环.

具体代码块如下:

...
// 外框圆环
Circle({ width: BIG_DIAMETER, height: BIG_DIAMETER })
  .fill(COLOR_TRANSPARENT)  // 填充:透明
  .stroke('#007DFF')  //圆环颜色
  .strokeWidth(5)  //圆环环宽
...

通过setInterval()方法让outSetValue值一直增加到100,使进度在规定时间内完成,最后通过clearInterval结束自增。

具体代码块如下:

...
aboutToAppear() {
  this.test()
}
test() {
  let timer = setInterval(() => {  //开始定时
    if (this.outSetValue < 100) {
      //进度值每次+1
      this.outSetValue += 1  
      //进度显示
      if (this.outSetValue == 100) {  
        this.backGroundColor = COLOR_BACKGROUND_FILL
        this.pathCommands = '';  
      } else {
        this.backGroundColor = COLOR_TRANSPARENT
        this.pathCommands = this.calPathCommands(this.outSetValue);
      }
    } else {
    clearInterval(timer)  //取消定时
    }
  }, 100)
}
...

通过方程表达进度百分比和y的关系,通过Path组件的路径绘制命令(M、Q、T)去绘制路径生成封闭的自定义形状并对中间进行填充。

中间的填充有两个状态:

在使用Path组件绘制路径时的计算过程和相关函数的使用如下(坐标系以Path组件的左上角为坐标原点):

具体代码块如下:

...
onPageShow() {
  //校准的路径指令与进度值
  this.pathCommands = this.calPathCommands(this.outSetValue); 
}

calXSquare(y: number) {
  return RADIUS_IN_PX * RADIUS_IN_PX - (y - RADIUS_IN_PX) * (y - RADIUS_IN_PX);
}

calY(k: number) {
  return (1 - k) * RADIUS_IN_PX * 2;//返回值为百分比
}
formatPathCommands(x1: number, x2: number, y: number, radius: number) {
  //填充区域波浪线
  return `M${x1} ${y} A${radius} ${radius} 0 ${y > RADIUS_IN_PX ? 0 : 1} 0  ${x2} ${y} `
+ `Q${(x1 + 3 * x2) / 4} ${y + 12.5 * (x2 - x1) / radius}, ${(x1 + x2) / 2} ${y} T${x1} ${y}`
}   
calPathCommands(value: number) {
  let y = this.calY(value / 100.0) 
  let squareX = this.calXSquare(y)
  if (squareX >= 0) {
    let x = Math.sqrt(squareX);
    let x1 = RADIUS_IN_PX - x;
    let x2 = RADIUS_IN_PX + x;
    return this.formatPathCommands(x1, x2, y, RADIUS_IN_PX);
  }
  return "";
}
...

绘制下方滑动条组件.

具体代码块如下:

...
Row() {
  Slider({
    value: this.outSetValue,
    min: 0,
    max: 100,
    step: 1,
    style: SliderStyle.OutSet
  })
    .blockColor('#FFFFFF')
    .trackColor('#182431')
    .selectedColor('#007DFF')
    .showSteps(true)
    .showTips(true)
    .onChange((value: number, mode: SliderChangeMode) => {
      if(this.outSetValue == 0) {
        this.test()
      }
      this.outSetValue = value //初始状态
      if (this.outSetValue == 100) {
        this.backGroundColor = COLOR_BACKGROUND_FILL //进度为100时,滑动条拉满,背景全满
        this.pathCommands = '';
      } else {
        this.backGroundColor = COLOR_TRANSPARENT 、
        this.pathCommands = this.calPathCommands(this.outSetValue);
      }
      console.log(`value = ${value} ->` + this.pathCommands);
      //进度显示
    })
  Text(this.outSetValue.toFixed(0)).fontSize(16)
}
...

完整代码

具体代码如下:

const COLOR_TRANSPARENT = '#00000000'
const COLOR_BACKGROUND_FILL = '#7ebede'

const DIAMETER = 200;
const RADIUS_IN_PX = vp2px(DIAMETER / 2.0);
const BIG_DIAMETER = 220;


@Entry
@Component
struct Page3 {
  @State outSetValue: number = 0
  @State pathCommands: string = ''
  @State backGroundColor: string = '#00000000'

  onPageShow() {
    this.pathCommands = this.calPathCommands(this.outSetValue);
  }

  calXSquare(y: number) {
    return RADIUS_IN_PX * RADIUS_IN_PX - (y - RADIUS_IN_PX) * (y - RADIUS_IN_PX);
  }

  calY(k: number) {
    return (1 - k) * RADIUS_IN_PX * 2;
  }

  formatPathCommands(x1: number, x2: number, y: number, radius: number) {
    return `M${x1} ${y} A${radius} ${radius} 0 ${y > RADIUS_IN_PX ? 0 : 1} 0  ${x2} ${y} `
    + `Q${(x1 + 3 * x2) / 4} ${y + 12.5 * (x2 - x1) / radius}, ${(x1 + x2) / 2} ${y} T${x1} ${y}`
  }

  calPathCommands(value: number) {
    let y = this.calY(value / 100.0)
    let squareX = this.calXSquare(y)
    if (squareX >= 0) {
      let x = Math.sqrt(squareX);
      let x1 = RADIUS_IN_PX - x;
      let x2 = RADIUS_IN_PX + x;
      return this.formatPathCommands(x1, x2, y, RADIUS_IN_PX);
    }
    return "";
  }

  aboutToAppear() {
    this.test()
  }
  test() {
    let timer = setInterval(() => {
      if (this.outSetValue < 100) {
        this.outSetValue += 1
        if (this.outSetValue == 100) {
          this.backGroundColor = COLOR_BACKGROUND_FILL
          this.pathCommands = '';
        } else {
          this.backGroundColor = COLOR_TRANSPARENT
          this.pathCommands = this.calPathCommands(this.outSetValue);
        }
      } else {
        clearInterval(timer)
      }
    }, 100)
  }
  build() {

    Column() {
      Column() {
        Stack() {
          // 外框圆环
          Circle({ width: BIG_DIAMETER, height: BIG_DIAMETER })
            .fill(COLOR_TRANSPARENT)
            .stroke('#007DFF')
            .strokeWidth(5)
          // 进度显示

          Circle({ width: DIAMETER, height: DIAMETER })
            .fill(this.backGroundColor)
          Path()
            .width(DIAMETER)
            .height(DIAMETER)
            .commands(this.pathCommands)
            .fill(COLOR_BACKGROUND_FILL)

          // 进度
          Text(this.outSetValue.toFixed(0) + "%")
            .fontSize(60)


        }.width(BIG_DIAMETER)
        .height(BIG_DIAMETER)


        Row() {
          Slider({
            value: this.outSetValue,
            min: 0,
            max: 100,
            step: 1,
            style: SliderStyle.OutSet
          })
            .blockColor('#FFFFFF')
            .trackColor('#182431')
            .selectedColor('#007DFF')
            .showSteps(true)
            .showTips(true)
            .onChange((value: number, mode: SliderChangeMode) => {
              if(this.outSetValue == 0) {
                this.test()
              }
              this.outSetValue = value
              if (this.outSetValue == 100) {
                this.backGroundColor = COLOR_BACKGROUND_FILL
                this.pathCommands = '';
              } else {
                this.backGroundColor = COLOR_TRANSPARENT
                this.pathCommands = this.calPathCommands(this.outSetValue);
              }
              console.log(`value = ${value} ->` + this.pathCommands);
            })
          Text(this.outSetValue.toFixed(0)).fontSize(16)
        }
        .padding({ top: 50 })
        .width('80%')

      }.width('100%')
    }
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}
来源:鸿蒙开发者社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯