Qt-for-鸿蒙PC-水波纹进度条组件开发实战 - 详解

目录

  1. 项目概述
  2. 技术栈选择
  3. 组件设计
  4. 核心功能实现
  5. 数学原理
  6. 开发要点与技巧
  7. 总结与展望

项目概述

在这里插入图片描述

在这里插入图片描述

项目背景

水波纹进度条是一种视觉效果独特的进度展示组件,通过模拟水波纹的波动效果来展示进度信息。本项目基于Qt/QML框架,实现了矩形和圆形两种形状的水波纹进度条,为HarmonyOS应用提供生动、直观的进度展示方案。

组件特性

本项目实现了以下两种水波纹进度条:

  • 矩形水波纹进度条:适用于方形容器,展示矩形区域的水波纹效果
  • 圆形水波纹进度条:适用于圆形容器,展示圆形区域的水波纹效果

所有组件均支持:

  • 自定义进度值(value、minimum、maximum)
  • 自定义颜色(水波纹颜色、背景颜色)
  • 动态水波纹动画效果
  • 双波纹叠加效果
  • 垂直渐变填充
  • 百分比文字显示

技术栈选择

前端框架:Qt/QML

选择理由:

  1. Canvas API:QML的Canvas组件提供了强大的2D绘制能力,可以精确控制水波纹的绘制
  2. Timer机制:使用Timer实现水波纹的周期性动画更新
  3. 数学函数支持:JavaScript的Math.sin函数可以方便地生成正弦波形
  4. 性能优化:Canvas的裁剪机制可以优化绘制性能

核心技术点

  • QtQuick 2.15:UI框架
  • Canvas API:2D绘制
  • Timer:动画更新机制
  • Math.sin:正弦波生成
  • LinearGradient:垂直渐变

组件设计

整体架构

水波纹进度条组件的架构设计:

Item (root)
├── Canvas
    ├── 背景绘制(矩形/圆形)
    ├── 裁剪区域设置
    ├── 渐变创建(垂直方向)
    ├── 第一层水波纹绘制
    └── 第二层水波纹绘制(相位差)
└── 文字显示(百分比)

核心属性

property real value: 0              // 当前值
property real minimum: 0            // 最小值
property real maximum: 100          // 最大值
property real progress: ...         // 计算得出的进度比例(反向:1 - (value-min)/(max-min))
property bool isCircle: true        // 是否为圆形
property color waterColor           // 水波纹颜色
property color backgroundColor      // 背景颜色
property real backgroundOpacity     // 背景透明度
// 水波纹参数
property real waveOffset: 0         // 波纹偏移量(动画)
property real waveAmplitude: 0     // 波纹振幅
property real waveFrequency: 0.038 // 波纹频率

核心功能实现

1. 进度值计算(反向)

水波纹进度条使用反向进度计算,值越大,水位越高:

property real progress: Math.max(0, Math.min(1, 1 - (value - minimum) / (maximum - minimum)))

说明:

  • value = minimum时,progress = 1,水位在底部(满)
  • value = maximum时,progress = 0,水位在顶部(空)
  • 这与常规进度条相反,符合"水位上升"的视觉效果

2. 水波纹动画

使用Timer实现水波纹的周期性动画:

Timer {
    id: waveTimer
    interval: 80                    // 每80ms更新一次
    running: true
    repeat: true
    onTriggered: {
        waveOffset += 0.6           // 增加偏移量
        if (waveOffset > width / 2) {
            waveOffset = 0         // 重置偏移量
        }
    }
}

关键技术点:

  • interval: 80:控制动画帧率,80ms约等于12.5fps
  • waveOffset += 0.6:每次增加的偏移量,控制波纹移动速度
  • 重置机制:当偏移量超过容器宽度的一半时重置,避免数值过大

3. 波纹振幅计算

波纹振幅根据容器高度动态计算:

onHeightChanged: {
    waveAmplitude = height * 0.05  // 振幅为高度的5%
}
Component.onCompleted: {
    waveAmplitude = height * 0.05
}

说明:

  • 振幅设置为高度的5%,确保波纹效果明显但不过于夸张
  • onHeightChangedComponent.onCompleted中都设置,确保初始化正确

4. Canvas绘制实现

4.1 背景绘制
// 绘制背景
ctx.fillStyle = Qt.rgba(1, 1, 1, backgroundOpacity)
ctx.beginPath()
if (isCircle) {
    // 圆形背景
    var side = Math.min(width, height)
    var centerX = width / 2
    var centerY = height / 2
    ctx.arc(centerX, centerY, side / 2, 0, 2 * Math.PI)
} else {
    // 矩形背景
    ctx.rect(0, 0, width, height)
}
ctx.fill()
4.2 裁剪区域设置

使用 clip()方法限制绘制区域:

ctx.save()
ctx.beginPath()
if (isCircle) {
    var side = Math.min(width, height)
    var centerX = width / 2
    var centerY = height / 2
    ctx.arc(centerX, centerY, side / 2, 0, 2 * Math.PI)
} else {
    ctx.rect(0, 0, width, height)
}
ctx.clip()  // 设置裁剪区域

说明:

  • ctx.save():保存当前绘图状态
  • ctx.clip():设置裁剪区域,后续绘制只在此区域内可见
  • ctx.restore():恢复绘图状态(在绘制完成后调用)
4.3 垂直渐变创建

创建两个不同透明度的垂直渐变:

// 第一个渐变(透明度较低)
var gradient1 = ctx.createLinearGradient(0, 0, 0, height)
gradient1.addColorStop(0.0, Qt.rgba(255/255, 66/255, 213/255, 0.4))  // 粉色,透明度0.4
gradient1.addColorStop(1.0, Qt.rgba(43/255, 74/255, 255/255, 0.4))   // 蓝色,透明度0.4
// 第二个渐变(透明度较高)
var gradient2 = ctx.createLinearGradient(0, 0, 0, height)
gradient2.addColorStop(0.0, Qt.rgba(255/255, 66/255, 213/255, 0.7))  // 粉色,透明度0.7
gradient2.addColorStop(1.0, Qt.rgba(43/255, 74/255, 255/255, 0.7))   // 蓝色,透明度0.7

说明:

  • 渐变方向:从上到下(0, 0)到(0, height)
  • 颜色:粉色到蓝色,与项目整体配色方案一致
  • 透明度:两个渐变使用不同透明度,叠加后产生层次感
4.4 第一层水波纹绘制

使用正弦函数生成波纹路径:

ctx.fillStyle = gradient1
ctx.beginPath()
ctx.moveTo(0, height)
for (var x = 0; x <= width; x += 1) {
    var y1 = waveAmplitude * Math.sin(waveFrequency * x + waveOffset) + waterLevel
    // 边界处理
    if (value === minimum) {
        y1 = height  // 最小值时,水位在底部
    }
    if (value === maximum) {
        y1 = 0       // 最大值时,水位在顶部
    }
    ctx.lineTo(x, y1)
}
ctx.lineTo(width, height)
ctx.closePath()
ctx.fill()

关键技术点:

  • Math.sin(waveFrequency * x + waveOffset):生成正弦波形
  • waveFrequency * x:控制波纹的密度(频率)
  • waveOffset:控制波纹的相位(动画效果)
  • waterLevel:水位基准线,根据progress计算
  • 边界处理:确保在极值时水位位置正确
4.5 第二层水波纹绘制(相位差)

第二层波纹使用相位差,产生叠加效果:

ctx.fillStyle = gradient2
ctx.beginPath()
ctx.moveTo(0, height)
for (var x2 = 0; x2 <= width; x2 += 1) {
    var phaseOffset = waveOffset + (width / 2 * waveFrequency)  // 相位差
    var y2 = waveAmplitude * Math.sin(waveFrequency * x2 + phaseOffset) + waterLevel
    // 边界处理(与第一层相同)
    if (value === minimum) {
        y2 = height
    }
    if (value === maximum) {
        y2 = 0
    }
    ctx.lineTo(x2, y2)
}
ctx.lineTo(width, height)
ctx.closePath()
ctx.fill()

关键技术点:

  • phaseOffset = waveOffset + (width / 2 * waveFrequency):相位差为容器宽度的一半乘以频率
  • 两层波纹叠加产生更丰富的视觉效果
  • 使用不同透明度的渐变,增强层次感

5. 文字显示

在Canvas上绘制百分比文字:

// 绘制文字
ctx.fillStyle = "white"
var fontSize = Math.max(12, width / 8)  // 字体大小自适应
ctx.font = fontSize + "px Arial"
ctx.textAlign = "center"
ctx.textBaseline = "middle"
ctx.fillText(Math.round(value) + "%", width / 2, height / 2)

说明:

  • 字体大小根据容器尺寸自适应
  • 文字居中显示
  • 使用 Math.round()四舍五入显示整数百分比

数学原理

正弦波函数

水波纹使用正弦函数生成:

y = A * sin(ω * x + φ) + y₀

其中:

  • A:振幅(amplitude),控制波纹的高度
  • ω:角频率(angular frequency),控制波纹的密度
  • x:水平位置
  • φ:相位(phase),控制波纹的偏移
  • y₀:基准线(waterLevel),根据进度值计算

相位差计算

第二层波纹的相位差:

phaseOffset = waveOffset + (width / 2 * waveFrequency)

这确保了两层波纹在视觉上形成良好的叠加效果。

水位计算

水位基准线根据进度值计算:

var waterLevel = height * progress

其中 progress是反向计算的进度值(1 - (value-min)/(max-min))。


开发要点与技巧

1. 性能优化

裁剪机制:

ctx.save()
ctx.beginPath()
// ... 设置裁剪路径
ctx.clip()
// ... 绘制内容
ctx.restore()

使用裁剪机制可以避免绘制超出边界的内容,提升性能。

重绘触发:

onWidthChanged: {
    if (width > 0 && height > 0) {
        requestPaint()
    }
}
onHeightChanged: {
    if (width > 0 && height > 0) {
        requestPaint()
    }
}
onProgressChanged: {
    if (canvas.width > 0 && canvas.height > 0) {
        canvas.requestPaint()
    }
}
onWaveOffsetChanged: {
    if (canvas.width > 0 && canvas.height > 0) {
        canvas.requestPaint()
    }
}

只在尺寸有效时触发重绘,避免无效绘制。

2. 边界处理

在极值情况下确保水位位置正确:

if (value === minimum) {
    y1 = height  // 最小值时,水位在底部(满)
}
if (value === maximum) {
    y1 = 0       // 最大值时,水位在顶部(空)
}

3. 动画参数调优

波纹频率:

property real waveFrequency: 0.038

频率值影响波纹的密度,值越大波纹越密集。

动画速度:

waveOffset += 0.6

每次增加的偏移量控制波纹移动速度,值越大移动越快。

更新间隔:

interval: 80  // 80ms,约12.5fps

更新间隔影响动画流畅度,需要在流畅度和性能之间平衡。

4. 渐变透明度控制

使用不同透明度的渐变叠加:

// 第一层:透明度0.4
gradient1.addColorStop(0.0, Qt.rgba(255/255, 66/255, 213/255, 0.4))
gradient1.addColorStop(1.0, Qt.rgba(43/255, 74/255, 255/255, 0.4))
// 第二层:透明度0.7
gradient2.addColorStop(0.0, Qt.rgba(255/255, 66/255, 213/255, 0.7))
gradient2.addColorStop(1.0, Qt.rgba(43/255, 74/255, 255/255, 0.7))

两层叠加后产生更丰富的视觉效果。


使用示例

基本使用

import QtQuick 2.15
Column {
    spacing: 20
    // 矩形水波纹进度条
    WaterProgressBar {
        width: 200
        height: 200
        value: 50
        isCircle: false
        waterColor: "#2B4AFF"
    }
    // 圆形水波纹进度条
    WaterProgressBar {
        width: 200
        height: 200
        value: 75
        isCircle: true
        waterColor: "#2B4AFF"
    }
}

动态更新进度

Item {
    property real progressValue: 0
    Timer {
        interval: 100
        running: true
        repeat: true
        onTriggered: {
            progressValue += 1
            if (progressValue > 100) progressValue = 0
        }
    }
    WaterProgressBar {
        width: 200
        height: 200
        value: progressValue
        isCircle: true
    }
}

自定义颜色

WaterProgressBar {
    width: 200
    height: 200
    value: 60
    isCircle: true
    waterColor: "#FF6B6B"        // 自定义水波纹颜色
    backgroundColor: "#FFFFFF"   // 自定义背景颜色
    backgroundOpacity: 0.3      // 自定义背景透明度
}

总结与展望

技术总结

本项目成功实现了矩形和圆形两种形状的水波纹进度条,展示了Qt/QML Canvas API的强大能力:

  1. 数学建模:使用正弦函数精确模拟水波纹效果
  2. 动画机制:通过Timer实现流畅的动画更新
  3. 视觉效果:双波纹叠加和渐变填充产生丰富的视觉层次
  4. 性能优化:裁剪机制和合理的重绘策略保证流畅运行

扩展方向

  1. 更多波纹层:可以添加更多波纹层,产生更复杂的效果
  2. 不同波形:可以使用其他数学函数(如余弦、复合波形)生成不同效果
  3. 交互效果:可以添加点击涟漪效果
  4. 3D效果:可以添加阴影和高光,模拟3D水面效果

最佳实践

  1. 参数调优:波纹频率、振幅、动画速度需要根据实际需求调优
  2. 性能考虑:合理设置Timer间隔,避免过度绘制
  3. 边界处理:确保在极值情况下正确显示
  4. 代码复用:矩形和圆形使用统一的绘制逻辑,通过 isCircle参数区分

相关资源

  • 项目地址:https://gitcode.com/szkygc/HarmonyOs_PC-PGC/tree/main/progress
  • Qt官方文档:https://doc.qt.io/qt-5/qtquick-index.html
  • QML Canvas文档:https://doc.qt.io/qt-5/qml-qtquick-canvas.html
  • 正弦函数参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math/sin
posted @ 2025-12-17 13:20  clnchanpin  阅读(37)  评论(0)    收藏  举报