Qt Quick - 在组件状态更改时动画图像转换的最佳方法是啥?
Posted
技术标签:
【中文标题】Qt Quick - 在组件状态更改时动画图像转换的最佳方法是啥?【英文标题】:Qt Quick - What is the best way to animate an image transition while component state changes?Qt Quick - 在组件状态更改时动画图像转换的最佳方法是什么? 【发布时间】:2020-01-09 15:22:47 【问题描述】:使用 Qt Quick,我创建了一个如下所示的自定义按钮:
这个按钮还包含几个状态(默认、悬停、按下),并且每个状态之间的转换是动画的。我找到了一种使用 Qt Quick 引擎轻松为每个属性设置动画的方法,图像除外。事实上,我想通过在状态之间执行交叉淡入淡出来为图像过渡设置动画。
但是我找不到这样的图像动画师。我发现的唯一方法是向我的按钮添加 3 个图像,每个状态一个,并为它们各自的不透明度设置动画。
下面是我的按钮代码:
Button
property bool hoveredBtn: false
property bool pressedBtn: false
id: btAnimStateDemo
height: 40
anchors.right: parent.right
anchors.rightMargin: 5
anchors.left: parent.left
anchors.leftMargin: 5
anchors.top: parent.top
anchors.topMargin: 290
state: "DEFAULT"
// the button background
background: Rectangle
id: btAnimStateDemoBg
anchors.fill: parent
// the button text
Text
id: btAnimStateDemoText
text: qsTr("A button showing animated states (default, hovered, pressed)")
renderType: Text.NativeRendering
font.bold: true
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.fill: parent
Image
id: btAnimStateDemoDefaultImage
width: 30
height: 30
anchors.left: parent.left
anchors.leftMargin: 5
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
opacity: 1.0
source: "Resources/Palette.svg"
Image
id: btAnimStateDemoHoverImage
width: 30
height: 30
anchors.left: parent.left
anchors.leftMargin: 5
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
opacity: 0.0
source: "Resources/Smile.svg"
Image
id: btAnimStateDemoPressedImage
width: 30
height: 30
anchors.left: parent.left
anchors.leftMargin: 5
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
opacity: 0.0
source: "Resources/Woman.svg"
// the component state array
states:
[
State
name: "DEFAULT"
PropertyChanges target: btAnimStateDemoBg; color: "green"
PropertyChanges target: btAnimStateDemoBg; radius: 4
PropertyChanges target: btAnimStateDemoDefaultImage; opacity: 1.0
PropertyChanges target: btAnimStateDemoHoverImage; opacity: 0.0
PropertyChanges target: btAnimStateDemoPressedImage; opacity: 0.0
,
State
name: "HOVERED"
PropertyChanges target: btAnimStateDemoBg; color: "red"
PropertyChanges target: btAnimStateDemoBg; radius: 10
PropertyChanges target: btAnimStateDemoDefaultImage; opacity: 0.0
PropertyChanges target: btAnimStateDemoHoverImage; opacity: 1.0
PropertyChanges target: btAnimStateDemoPressedImage; opacity: 0.0
,
State
name: "PRESSED"
PropertyChanges target: btAnimStateDemoBg; color: "blue"
PropertyChanges target: btAnimStateDemoBg; radius: 15
PropertyChanges target: btAnimStateDemoDefaultImage; opacity: 0.0
PropertyChanges target: btAnimStateDemoHoverImage; opacity: 0.0
PropertyChanges target: btAnimStateDemoPressedImage; opacity: 1.0
]
// the matching transitions between states
transitions:
[
Transition
from: "*"; to: "DEFAULT"
ColorAnimation property: "color"; easing.type: Easing.Linear; duration: 1000
NumberAnimation properties: "radius, opacity"; easing.type: Easing.Linear; duration: 1000
,
Transition
from: "*"; to: "HOVERED"
ColorAnimation property: "color"; easing.type: Easing.Linear; duration: 1000
NumberAnimation properties: "radius, opacity"; easing.type: Easing.Linear; duration: 1000
,
Transition
from: "*"; to: "PRESSED"
ColorAnimation property: "color"; easing.type: Easing.Linear; duration: 1000
NumberAnimation properties: "radius, opacity"; easing.type: Easing.Linear; duration: 1000
]
// the mouse area which will apply the correct state in relation to the current mouse status
MouseArea
anchors.fill: parent
hoverEnabled: true
onEntered: btAnimStateDemo.state = "HOVERED"; btAnimStateDemo.hoveredBtn = true;
onExited: btAnimStateDemo.state = btAnimStateDemo.pressedBtn ? "PRESSED" : "DEFAULT"; btAnimStateDemo.hoveredBtn = false;
onPressed: btAnimStateDemo.state = "PRESSED"; btAnimStateDemo.pressedBtn = true;
onReleased: btAnimStateDemo.state = btAnimStateDemo.hoveredBtn ? "HOVERED" : "DEFAULT"; btAnimStateDemo.pressedBtn = false;
上面的代码运行良好,达到了我计划的目的,但在我看来有点复杂。如果图像中存在像NumberAnimation
或ColorAnimation
这样的动画师,那就太好了,但我没有找到。
所以我的问题是:有没有比我上面提出的解决方案更简单的方法来动画组件状态之间的图像转换? Qt Quick 是否会提议一个动画师来达到这样的目的?
【问题讨论】:
我认为这不存在,所以也许您应该向 Qt 提交功能请求? (也许先等待一些答案;-)) 所以按照您的建议,我在 Qt 错误跟踪器上打开了一个线程:bugreports.qt.io/browse/QTBUG-81292 【参考方案1】:创建一个 SpriteSheet,为三个帧中的每一个分配状态,然后将 interpolate 属性设置为 true 以使其在图像之间转换。
使用 SpriteSequence 的 Sprite 动画 SpriteSequence 演示了使用精灵序列来绘制动画和交互式熊。 SpriteSequence 对象定义了五个不同的精灵。熊最初处于静止状态:
Sprite
name: "still"
source: "content/BearSheet.png"
frameCount: 1
frameWidth: 256
frameHeight: 256
frameDuration: 100
to: "still":1, "blink":0.1, "floating":0
当点击场景时,动画将精灵序列设置为下降状态并为熊的 y 属性设置动画。
SequentialAnimation
id: anim
ScriptAction script: image.goalSprite = "falling";
NumberAnimation target: image; property: "y"; to: 480; duration: 12000;
ScriptAction script: image.goalSprite = ""; image.jumpTo("still");
PropertyAction target: image; property: "y"; value: 0
在动画结束时,熊被设置回初始状态。
【讨论】:
以上是关于Qt Quick - 在组件状态更改时动画图像转换的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章