要做波纹效果,用径向渐变是最简单的。QML中有两个RadialGradient径向渐变,一个是QtGraphicalEffects模块中的,另一个是QtQuick.Shapes模块中的(Shapes是Qt5.10开始引入的模块)。
Effects的径向渐变默认效果就没有锯齿感,Shapes的径向渐变抗锯齿设置更麻烦(暂时还没实现和Effects一样的效果,或许可以配合Shader来实现)。所以实际应用中,这种简单的波纹我准备用QtGraphicalEffects模块的径向渐变。
下面的Demo代码我实现了两个波纹以及一个点击效果(GIF不流畅):
代码有四个文件,使用Qt5.12版本编写及测试
//ClickWave.qml
import QtQuick 2.12
import QtGraphicalEffects 1.0
Item {
id: control
implicitWidth: 100
implicitHeight: 100
visible: false
property double wave_offset: 0.0
property color wave_color: "red"
RadialGradient{
id: gradient
anchors.fill: parent
//horizontalRadius: 0
//verticalRadius: 0
//horizontalOffset: 0
//verticalOffset: 0
gradient: Gradient{
GradientStop{
position: (control.wave_offset>0.1)?(control.wave_offset-0.1):0
color: "transparent"
}
GradientStop{ position: control.wave_offset+0.09; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.11; color: "transparent" }
}
}
PropertyAnimation{
id: animation
target: control
property: "wave_offset"
from:0
to:0.4
duration: 400
running: false
onStarted: control.visible=true
onFinished: control.visible=false
}
function click(ptx,pty){
animation.stop()
control.x=ptx-control.width/2
control.y=pty-control.height/2
animation.start()
}
}
//EffectsWave.qml
import QtQuick 2.12
import QtGraphicalEffects 1.0
Item {
id: control
implicitWidth: 150
implicitHeight: 150
property double wave_offset: 0.0
property color wave_color: "red"
property alias running: animation.running
RadialGradient{
id: gradient
anchors.fill: parent
//horizontalRadius: 0
//verticalRadius: 0
//horizontalOffset: 0
//verticalOffset: 0
//待改进,根据参数来设置波纹数量
gradient: Gradient{
//很遗憾,不能用Repeater
GradientStop{ position: 0; color: "transparent" }
GradientStop{ position: control.wave_offset+0.001; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.01; color: "transparent" }
GradientStop{ position: control.wave_offset+0.07; color: "transparent" }
GradientStop{ position: control.wave_offset+0.1; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.11; color: "transparent" }
GradientStop{ position: control.wave_offset+0.17; color: "transparent" }
GradientStop{ position: control.wave_offset+0.2; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.21; color: "transparent" }
GradientStop{ position: control.wave_offset+0.27; color: "transparent" }
GradientStop{ position: control.wave_offset+0.3; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.31; color: "transparent" }
GradientStop{ position: control.wave_offset+0.37; color: "transparent" }
GradientStop{ position: control.wave_offset+0.4; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.41; color: "transparent" }
}
}
PropertyAnimation{
id: animation
target: control
property: "wave_offset"
from:0
to:0.1
duration: 1000
running: control.visible
loops: Animation.Infinite
}
}
Shape用起来没Effects简单,但功能也更多。还要注意的是,ShapePath要围起来他才会填充,这里我用一个透明边框围了一个矩形框。有一点不同的是,Effects径向范围到0.5就到矩形边上了,Shapes径向范围为1才到矩形边上。
//ShapesWave.qml
import QtQuick 2.12
import QtQuick.Shapes 1.12
Item {
id: control
implicitWidth: 150
implicitHeight: 150
property double wave_offset: 0.0
property color wave_color: "red"
property alias running: animation.running
Shape {
anchors.fill: parent
//这些设置感觉没效果
//多重采样抗锯齿
//layer.enabled: true
//layer.smooth: true
//layer.samples: 8
//平滑处理
//smooth: true
//反走样抗锯齿
//antialiasing: true
ShapePath{
startX:0
startY: 0
strokeColor: "transparent"
//需要圈起来他才会填充渐变色
PathLine {x: control.width;y: 0}
PathLine {x: control.width;y: control.height}
PathLine {x: 0;y: control.height}
PathLine {x: 0;y: 0}
fillGradient: RadialGradient {
//ShapeGradient.PadSpread 该区域将填充最接近的停止色。
//ShapeGradient.RepeatSpread 在渐变区域外重复渐变。
//ShapeGradient.ReflectSpread 渐变会反射到渐变区域之外。
//spread: ShapeGradient.PadSpread
centerRadius: control.width/2
//对于简单的径向渐变,应该将focusRadius设置为0(默认值)
centerX: control.width/2 //中心
centerY: control.height/2
focalX: centerX //焦点
focalY: centerY
//待改进,根据参数来设置波纹数量, 很遗憾,不能用Repeater
GradientStop{ position: 0; color: "transparent" }
GradientStop{ position: control.wave_offset+0.001; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.01; color: "transparent" }
GradientStop{ position: control.wave_offset+0.15; color: "transparent" }
GradientStop{ position: control.wave_offset+0.2; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.21; color: "transparent" }
GradientStop{ position: control.wave_offset+0.35; color: "transparent" }
GradientStop{ position: control.wave_offset+0.4; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.41; color: "transparent" }
GradientStop{ position: control.wave_offset+0.55; color: "transparent" }
GradientStop{ position: control.wave_offset+0.6; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.61; color: "transparent" }
GradientStop{ position: control.wave_offset+0.75; color: "transparent" }
GradientStop{ position: control.wave_offset+0.8; color: control.wave_color }
GradientStop{ position: control.wave_offset+0.81; color: "transparent" }
}
}
}
PropertyAnimation{
id: animation
target: control
property: "wave_offset"
from:0
to:0.2
duration: 1000
running: control.visible
loops: Animation.Infinite
}
}
//main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
visible: true
width: 720
height: 520
title: qsTr("Hello World")
color: "black"
EffectsWave{
width: 200
height: 200
x:100
y:100
}
ShapesWave{
width: 200
height: 200
x:300
y:100
}
ClickWave{
id: click_wave
width: 100
height: 100
x:100
y: 300
}
MouseArea{
anchors.fill: parent
onClicked: {
click_wave.click(mouse.x,mouse.y)
}
}
}
(完结~~)