Qt Quick中的动画和过渡简介

1,407 阅读8分钟

本文已参加【新人创作礼】活动,一起开启掘金创作之路。


📒博客首页:何名取 的个人主页 - 文章 - 掘金 (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。 donghua1.gif

专门化的属性动画类型比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。

donghua2.gif

这也可以用于分组动画,以确保组内的所有动画都应用于相同的属性。例如,前面的例子可以使用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对象也自动应用于此属性,不需要指定目标或属性值。

donghua3.gif

状态变化期间的过渡

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}
            }
        ]
    }

按钮可能有两个状态,当用户单击按钮时为按下状态,当用户释放按钮时为释放状态。我们可以为每个状态分配不同的属性配置。转换将使从按下状态到释放状态的变化具有动画效果。同样,在从释放状态到按下状态的变化期间,也会有一个动画。 donghua4.gif 将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和颜色属性。行为动画可以设置为模拟弹性效果。实际上,每当球移动时,这个行为动画就会将弹性效果应用到属性中。

donghua5.gif 有几种方法可以将行为动画分配给属性。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类型将同时播放动画。

donghua6.gif 一旦单个动画被放置到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 {} }
 }

donghua7.gif