本文已参加【新人创作礼】活动,一起开启掘金创作之路。
📒博客首页:何名取 的个人主页 - 文章 - 掘金 (juejin.cn)
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
❤️期待一起交流!
🙏作者水平很有限,如果发现错误,求告知,多谢!
🌺有问题可私信交流!!!
Qt Quick中的动画和过渡
前言
本节对Qt Quick中的动画和过渡从总体角度上进行了介绍,并对其中的子类型简单做了示例。
动画和过渡类型
- Transition - 在状态变化期间用动画来转换
- SequentialAnimation - 按顺序运行动画
- ParallelAnimation - 并行运行动画
- Behavior - 为属性更改指定默认动画
- PropertyAction - 在动画期间立即更改属性
- PauseAnimation - 在动画中引入暂停
- SmoothedAnimation - 使属性值平滑地改变
- SpringAnimation - 使属性值弹性地变动
- ScriptAction - 在动画中运行脚本
基于数据类型对属性进行动画处理的类型:
类型 | 描述 |
---|---|
AnchorAnimationAnimates | 当锚点变化时产生动画效果。 |
ColorAnimationAnimates | 当颜色变化时产生动画效果。 |
NumberAnimationAnimates | 当数值改变时产生动画效果。 |
ParentAnimationAnimates | 当Item的父级更改时产生动画效果。 |
PathAnimationAnimates | 当item沿路径运动时产生动画。 |
PropertyAnimationAnimates | 当属性时产生动画效果。 |
RotationAnimationAnimates | 控制旋转方向。 |
Vector3dAnimationAnimates | 当Vector3d值改变时产生动画效果。 |
通过将动画类型应用到属性值来创建动画。动画类型将插值属性值来创建平滑的过渡。同样,状态转换也可以为状态变化分配动画。例如,将动画应用到属性x坐标值的变化上,当x从0到100时,在0到100中间插入50个数来形成动画效果,而不是直接从0变化到100。
触发动画
有几种方法可以将动画设置为对象。
直接指定属性的动画
动画是通过将动画对象应用到属性值来创建的,以便随着时间的推移逐渐改变属性。这些属性动画通过在属性值变化之间插入值来应用平滑的移动。属性动画提供了计时控制,并允许通过缓动曲线进行不同的插值。
Rectangle {
id: flashingblob
width: 75; height: 75
color: "blue"
opacity: 0.1
MouseArea {
anchors.fill: parent
onClicked: {
animateColor.start()
animateOpacity.start()
}
}
PropertyAnimation {id: animateColor; target: flashingblob; properties: "color"; to: "green"; duration: 100}
NumberAnimation {
id: animateOpacity
target: flashingblob
properties: "opacity"
from: 0.1
to: 1.0
loops: Animation.Infinite
easing {type: Easing.OutBack; overshoot: 500}
}
}
最开始将矩形块的颜色设置为蓝色,透明度设置为0.1。当鼠标点击时改变这两个属性。其中颜色属性使用PropertyAnimation,透明度属性使用NumberAnimation。
专门化的属性动画类型比PropertyAnimation类型有更有效的实现。它们用于将动画设置为不同的QML类型,如int, color和rotations,对应的是NumberAnimationAnimates,ColorAnimationAnimates和RotationAnimationAnimates。类似地,ParentAnimation可以对父元素的更改进行动画处理。
使用预定义的目标和属性
在前面的示例中,PropertyAnimation和NumberAnimation对象需要指定特定的目标和属性值,以指定应该被动画化的对象和属性。这可以通过使用<Animation> on <Property>语法来避免,该语法指定将动画应用为属性值源。
下面是两个使用此语法指定的PropertyAnimation对象:
import QtQuick 2.0
Rectangle {
id: rect
width: 100; height: 100
color: "red"
MouseArea {
anchors.fill: parent
onClicked: {
xp.running = true
yp.running = true
}
}
PropertyAnimation on x { id:xp; running: false; to: 100 }
PropertyAnimation on y { id:yp; running: false; to: 100 }
}
动画在鼠标点击后立即开始,并自动应用于它的x和y值。由于已经使用了<Animation> on <Property>语法,因此不需要设置要纠正的PropertyAnimation对象的目标值,也不需要将属性值设置为x和y。
这也可以用于分组动画,以确保组内的所有动画都应用于相同的属性。例如,前面的例子可以使用SequentialAnimation来使矩形的颜色先变为黄色,然后变为蓝色:
import QtQuick 2.0
Rectangle {
width: 100; height: 100
color: "red"
SequentialAnimation on color {
ColorAnimation { to: "yellow"; duration: 1000 }
ColorAnimation { to: "blue"; duration: 1000 }
}
}
由于SequentialAnimation对象已在color属性上使用<Animation> on <Property>语法指定,它的子ColorAnimation对象也自动应用于此属性,不需要指定目标或属性值。
状态变化期间的过渡
Qt Quick States是属性配置,其中一个属性可以有不同的值来反映不同的状态。太过剧烈的状态变化会带来突然的属性变化,使用动画平滑过渡会产生视觉上更吸引人的状态变化。
过渡类型可以包含动画类型来插值由状态变化引起的属性变化。若要将过渡分配给对象,请将其绑定到transitions属性。
Rectangle {
width: 75; height: 75
id: button
state: "RELEASED"
MouseArea {
anchors.fill: parent
onPressed: button.state = "PRESSED"
onReleased: button.state = "RELEASED"
}
states: [
State {
name: "PRESSED"
PropertyChanges { target: button; color: "DarkBlue"}
},
State {
name: "RELEASED"
PropertyChanges { target: button; color: "SkyBlue"}
}
]
transitions: [
Transition {
from: "PRESSED"
to: "RELEASED"
ColorAnimation { target: button; duration: 100}
},
Transition {
from: "RELEASED"
to: "PRESSED"
ColorAnimation { target: button; duration: 100}
}
]
}
按钮可能有两个状态,当用户单击按钮时为按下状态,当用户释放按钮时为释放状态。我们可以为每个状态分配不同的属性配置。转换将使从按下状态到释放状态的变化具有动画效果。同样,在从释放状态到按下状态的变化期间,也会有一个动画。
将to和from属性绑定到状态名称将把特定的过渡分配给状态更改。对于简单或对称过渡,将to属性值设置为通配符“*”表示该转换适用于任何状态更改。
transitions:
Transition {
to: "*"
ColorAnimation { target: button; duration: 100}
}
为行为的指定默认动画
默认的属性动画是使用行为动画设置的。在行为类型中声明的动画应用于属性,并且动画任何属性值的变化。然而,行为类型有一个enabled属性来有意地启用或禁用行为动画。
Rectangle {
width: 75; height: 75; radius: width
id: ball
color: "lightsteelblue"
Behavior on x {
NumberAnimation {
id: bouncebehavior
easing {
type: Easing.OutElastic
amplitude: 1.0
period: 0.5
}
}
}
Behavior on y {
animation: bouncebehavior
}
Behavior {
ColorAnimation { target: ball; duration: 300 }
}
}
小球组件将行为动画分配给它的x, y和颜色属性。行为动画可以设置为模拟弹性效果。实际上,每当球移动时,这个行为动画就会将弹性效果应用到属性中。
有几种方法可以将行为动画分配给属性。Behavior on <property>声明是将行为动画分配到属性上的一种简便方式。
并行或顺序播放动画
动画可以并行运行,也可以顺序运行。并行动画会同时播放一组动画,而顺序动画会依次播放一组动画。在SequentialAnimation和ParallelAnimation中分组动画将按顺序或并行播放动画。
Rectangle {
id: banner
width: 150; height: 100; border.color: "black"
Column {
anchors.centerIn: parent
Text {
id: code
text: "Code less."
opacity: 0.01
}
Text {
id: create
text: "Create more."
opacity: 0.01
}
Text {
id: deploy
text: "Deploy everywhere."
opacity: 0.01
}
}
MouseArea {
anchors.fill: parent
onPressed: playbanner.start()
}
SequentialAnimation {
id: playbanner
running: false
NumberAnimation { target: code; property: "opacity"; to: 1.0; duration: 200}
NumberAnimation { target: create; property: "opacity"; to: 1.0; duration: 200}
NumberAnimation { target: deploy; property: "opacity"; to: 1.0; duration: 200}
}
}
横幅组件可以一个接一个地显示多个图标或口号。不透明属性可以转换为1.0,表示不透明对象。使用SequentialAnimation类型,不透明度动画将在前面的动画完成后播放。ParallelAnimation类型将同时播放动画。
一旦单个动画被放置到SequentialAnimation或ParallelAnimation中,它们就不能再独立地启动和停止了。顺序或并行动画必须作为一个组启动和停止。
SequentialAnimation类型对于播放转场动画也很有用,因为动画是在转场内部并行播放的。
控制动画
下面有几种控制动画的方法。
动画播放
所有动画类型都继承自动画类型。该类型提供了动画类型的基本属性和方法。动画类型有start()、stop()、resume()、pause()、restart()和complete()——所有这些方法都控制动画的执行。
缓动
缓动曲线定义了动画如何在开始值和结束值之间插值。不同的缓动曲线可能会超出内插的限定范围。缓动曲线简化了动画效果的创建,如反弹效果、加速、减速和循环动画。
一个QML对象对于每个属性动画可能有不同的缓动曲线。也有不同的参数来控制曲线,其中一些是特定曲线独有的。
其他类型的动画
此外,QML还提供了其他一些对动画有用的类型:
- PauseAnimation: 在动画期间启用暂停
- ScriptAction: 允许JavaScript在动画过程中执行,并可以与StateChangeScript一起使用来重用现有的脚本
- PropertyAction: 在动画期间立即更改属性,而不对属性更改进行动画化
这些是特殊的动画类型,用于动画不同的属性类型:
- SmoothedAnimation: 一种专门的数字动画,当目标值发生变化时,它提供动画中的平滑变化
- SpringAnimation: 提供具有特殊属性(如质量和阻尼)的类似弹簧的动画
- ParentAnimation: 用于动画父级的改变
- AnchorAnimation: 用于动画锚的变化
动画实例的共享
不支持在Transitions过渡或behavior行为之间共享动画实例,这可能导致未定义的行为。在下面的例子中,矩形位置的改变很可能不会被正确的动画化。
Rectangle {
// NOT SUPPORTED: this will not work correctly as both Behaviors
// try to control a single animation instance
NumberAnimation { id: anim; duration: 300; easing.type: Easing.InBack }
Behavior on x { animation: anim }
Behavior on y { animation: anim }
}
最简单的解决方法是为两个行为重复NumberAnimation。如果重复的动画相当复杂,你也可以考虑创建一个自定义动画组件,并为每个行为分配一个实例,例如:
Rectangle {
component MyNumberAnimation : NumberAnimation {
duration: 300; easing.type: Easing.InBack
}
Behavior on x { MyNumberAnimation {} }
Behavior on y { MyNumberAnimation {} }
}