From a301a560ef32c995f8d9a40a6df36bae27e515da Mon Sep 17 00:00:00 2001 From: zhangkun Date: Fri, 26 Dec 2025 15:16:22 +0800 Subject: [PATCH] fix: refactor progress bar animation and visual effects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Replaced manual timer-based animation with a reusable lightSweepAnimation component 2. Fixed BoxShadow positioning to use anchors instead of manual calculations 3. Added OpacityMask layers to handle corner radius clipping properly 4. Restructured gradient animation to use ColorAnimation for smoother transitions 5. Fixed indeterminate mode animation to respect animationStop control 6. Improved visual consistency between determinate and indeterminate modes Log: Improved progress bar visual effects with smoother animations and better corner handling Influence: 1. Test progress bar in both determinate and indeterminate modes 2. Verify smooth gradient animation without visual glitches 3. Check corner radius rendering at different progress values 4. Test animation stop/start functionality in indeterminate mode 5. Verify BoxShadow positioning and visibility at progress boundaries 6. Test performance with multiple progress bars simultaneously fix: 重构进度条动画和视觉效果 1. 将基于定时器的手动动画替换为可复用的 lightSweepAnimation 组件 2. 修复 BoxShadow 定位,使用锚点替代手动计算 3. 添加 OpacityMask 层以正确处理圆角裁剪 4. 重构渐变动画,使用 ColorAnimation 实现更平滑的过渡 5. 修复不确定模式动画以遵守 animationStop 控制 6. 改进确定模式和不确定模式之间的视觉一致性 Log: 改进了进度条的视觉效果,动画更平滑,圆角处理更好 Influence: 1. 测试确定模式和不确定模式下的进度条 2. 验证平滑的渐变动画,无视觉故障 3. 检查不同进度值下的圆角渲染 4. 测试不确定模式下的动画停止/开始功能 5. 验证进度边界处的 BoxShadow 定位和可见性 6. 测试同时显示多个进度条时的性能表现 pms: BUG-341547 --- qt6/src/qml/private/ProgressBarImpl.qml | 133 ++++++++++++++++-------- 1 file changed, 87 insertions(+), 46 deletions(-) diff --git a/qt6/src/qml/private/ProgressBarImpl.qml b/qt6/src/qml/private/ProgressBarImpl.qml index 22b1a8f6..8fad1269 100644 --- a/qt6/src/qml/private/ProgressBarImpl.qml +++ b/qt6/src/qml/private/ProgressBarImpl.qml @@ -27,43 +27,59 @@ Item { Item { BoxShadow { - y: (parent.height - height) / 2 - x: -y - width: progressBar.height - height: progressBar.visualPosition * progressBar.width - shadowOffsetX: -4 + anchors.fill: parent + anchors.rightMargin: (1 - progressBar.visualPosition) * progressBar.width + shadowOffsetY: 4 shadowBlur: 6 - rotation: -90 cornerRadius: DS.Style.control.radius shadowColor: control.D.ColorSelector.shadowPaletteColor visible: progressBar.visualPosition > 0 + } + Item { + id: item + // 向左偏移height显示,避免宽度过窄时产生的圆角显示问题 + x: - height + width: progressBar.width + height + height: progressBar.height Rectangle { id: rect - anchors.fill: parent - radius: parent.cornerRadius - property int count - property real lightPosition - gradient: Gradient { + property color gradientColor: progressBar.palette.highlight + property real lightPosition: 0 + width: progressBar.width * progressBar.visualPosition + height + height: progressBar.height + gradient: Gradient { + orientation: Gradient.Horizontal GradientStop { position: 0; color: progressBar.palette.highlight } - GradientStop { position: rect.lightPosition; color: control.D.ColorSelector.handleGradientColor } + GradientStop { position: rect.lightPosition; color: rect.gradientColor } GradientStop { position: 1; color: progressBar.palette.highlight } } - Timer { - id: moveTimer - interval: 10 - repeat: true - running: rect.visible - onTriggered: { - moveTimer.interval = 10 - if (rect.count === 100) { - rect.count = 0 - rect.lightPosition = 0.0 - moveTimer.interval = 2000 - return; + + LightSweepAnimation { + targetItem: rect + running: !control.animationStop && rect.visible + } + + radius: DS.Style.control.radius + layer.enabled: true + clip: true + layer.effect: OpacityMask { + maskSource: Rectangle { + width: rect.width + height: rect.height + radius: DS.Style.control.radius } - rect.count += 1 - rect.lightPosition = rect.count * 0.01 + } + } + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Item { + width: item.width + height: item.height + Rectangle { + anchors.fill: parent + anchors.leftMargin: -item.x + radius: DS.Style.control.radius } } } @@ -121,28 +137,16 @@ Item { id: indeterminateRect anchors.fill: parent radius: indeterminateProgressContent.cornerRadius - property int count - property real lightPosition + property real lightPosition: 0 + property color gradientColor: control.D.ColorSelector.handleGradientColor gradient: Gradient { - GradientStop { position: 0.0; color: progressBar.palette.highlight } - GradientStop { position: indeterminateRect.lightPosition; color: control.D.ColorSelector.handleGradientColor } - GradientStop { position: 1.0; color: progressBar.palette.highlight } + GradientStop { position: 0; color: progressBar.palette.highlight } + GradientStop { position: indeterminateRect.lightPosition; color: indeterminateRect.gradientColor } + GradientStop { position: 1; color: progressBar.palette.highlight } } - Timer { - id: indeterminateMoveTimer - interval: 50 - repeat: true - running: indeterminateRect.visible - onTriggered: { - indeterminateMoveTimer.interval = 50 - if (indeterminateRect.count === 100) { - indeterminateRect.count = 0 - indeterminateMoveTimer.interval = 2000 - return; - } - indeterminateRect.count += 5 - indeterminateRect.lightPosition = indeterminateRect.count * 0.01 - } + LightSweepAnimation { + targetItem: indeterminateRect + running: progressBar.indeterminate && !control.animationStop && indeterminateRect.visible } } @@ -224,4 +228,41 @@ Item { } } } + + component LightSweepAnimation: SequentialAnimation{ + id: anim + property Item targetItem: null + loops: Animation.Infinite + + ParallelAnimation { + SequentialAnimation { + ColorAnimation { + target: anim.targetItem + property: "gradientColor" + from: progressBar.palette.highlight + to: control.D.ColorSelector.handleGradientColor + duration: 500 + } + PauseAnimation { duration: 2000 } + ColorAnimation { + target: anim.targetItem + property: "gradientColor" + from: control.D.ColorSelector.handleGradientColor + to: progressBar.palette.highlight + duration: 500 + } + } + + NumberAnimation { + target: anim.targetItem + property: "lightPosition" + from: 0 + to: 1 + duration: 3000 + easing.type: Easing.InOutSine + } + } + + PauseAnimation { duration: 2000 } + } }