Qt Quick 动画入门篇

简介

在使用 QML 进行界面开发时,我们的目标是创建一套流体界面,所谓流体界面指的是UI组件是动态变化的。举个例子,当界面上的组件需要变化时,如果视觉画布突然变化会导致用户的体验感比较差。而如果在状态的变化过程中,我们添加一些引导,把状态从初始慢慢变化到目标状态,让用户可以感受到这个变化的过程,那么用户的感官体验这一块就会大大提升了,而这也就是所谓的动态变化

这里需要引出几个重要的概念:State(状态)、Transition(过度)、Animation(动画)

State(状态):所有项目都有一个默认状态,用于定义对象和特性值的默认配置。可以通过向 states 属性添加状态项来定义新状态,以允许项在不同配置之间切换

Transition(过度):发生状态更改时要应用的动画

Animation(动画):随着时间的推移逐渐改变属性

具体请参考官方文档:Important Concepts in Qt Quick - States, Transitions and Animations

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

缓和曲线

通常动画中的变化是匀速的,如果开发者觉得太单调了,可以调节动画的变化速度曲线,即缓和曲线。我们通过动画的 easing 属性组来改变缓和曲线

type - 缓和曲线类型

amplitude - 幅度

period - 周期

overshoot - 过冲

bezierCurve - 贝塞尔

 

缓和曲线的类型如下所示:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

动画类型

AnchorAnimation - 为锚定值的更改设置动画

 

Rectangle {
    id: myRect
    width: 100; height: 100
    color: "red"
    
    property int type: 1
    
    states: [
        State {
            name: "right"
            AnchorChanges { target: myRect; anchors.right: parent.right }
        },
        State {
            name: "bottom"
            AnchorChanges { target: myRect; anchors.bottom: parent.bottom }
        },
        State {
            name: "left"
            AnchorChanges { target: myRect; anchors.left: parent.left }
        },
        State {
            name: "top"
            AnchorChanges { target: myRect; anchors.top: parent.top }
        }
    ]
    
    transitions: Transition {
        AnchorAnimation { duration: 500 }
    }
    
    MouseArea {
        anchors.fill: parent
        onClicked: {
            let state = {
                1: "right",
                2: "bottom",
                3: "left",
                4: "top"
            }
            myRect.state = state[myRect.type]
            
            myRect.type++
            if ( myRect.type > 4 ) {
                myRect.type = 1
            }
        }
    }
}

ColorAnimation - 为颜色值的更改设置动画

 

Rectangle {
    id: myRect
    width: 100; height: 100
    color: "black"
    
    property int type: 1
    
    states: [
        State {
            name: "red"
            PropertyChanges { target: myRect; color: "red" }
        },
        State {
            name: "yellow"
            PropertyChanges { target: myRect; color: "yellow" }
        },
        State {
            name: "pink"
            PropertyChanges { target: myRect; color: "pink" }
        },
        State {
            name: "blue"
            PropertyChanges { target: myRect; color: "blue" }
        },
        State {
            name: "black"
            PropertyChanges { target: myRect; color: "black" }
        }
    ]
    
    transitions: Transition {
        ColorAnimation { duration: 500 }
    }
    
    MouseArea {
        anchors.fill: parent
        onClicked: {
            let state = {
                1: "red",
                2: "yellow",
                3: "pink",
                4: "blue",
                5: "black",
            }
            myRect.state = state[myRect.type]
            
            myRect.type++
            if ( myRect.type > 5 ) {
                myRect.type = 1
            }
        }
    }
}

NumberAnimation - 为 qreal 类型值的更改设置动画

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

 

Rectangle {
    id: myRect
    width: 100; height: 100
    color: "red"

    property int type: 1

    states: [
        State {
            name: "step1"
            PropertyChanges { target: myRect; x: 60; y: 60; width: 120; height: 120; rotation: 30 }
        },
        State {
            name: "step2"
            PropertyChanges { target: myRect; x: 60; y: 60; width: 120; height: 120; rotation: 60 }
        },
        State {
            name: "step3"
            PropertyChanges { target: myRect; x: 40; y: 40; width: 180; height: 180; rotation: 90 }
        },
        State {
            name: "step4"
            PropertyChanges { target: myRect; x: 100; y: 100; width: 50; height: 50; rotation: 45 }
        }
    ]

    transitions: Transition {
        NumberAnimation { duration: 500 }
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            let state = {
                1: "step1",
                2: "step2",
                3: "step3",
                4: "step4"
            }
            myRect.state = state[myRect.type]

            myRect.type++
            if ( myRect.type > 4 ) {
                myRect.type = 1
            }
        }
    }
}

ParentAnimation - 为父类的更改设置动画

 

Rectangle {
    id: myRect
    width: 300; height: 100
    color: "black"

    property int type: 1

    Rectangle {
        id: redRect
        width: 100; height: 100
        color: "red"
    }

    Rectangle {
        id: blueRect
        x: 110
        width: 100; height: 100
        color: "blue"
    }

    Rectangle {
        id: yellowRect
        x: 220; y: 10
        width: 50; height: 50
        color: "yellow"

        states: [
            State {
                name: "red"
                ParentChange { target: yellowRect; parent: redRect; x: 10; y: 10 }
            },
            State {
                name: "blue"
                ParentChange { target: yellowRect; parent: blueRect; x: 10; y: 10 }
            },
            State {
                name: "black"
                ParentChange { target: yellowRect; parent: myRect; x: 220; y: 10 }
            }
        ]

        transitions: Transition {
            ParentAnimation {
                NumberAnimation { properties: "x,y"; duration: 500 }
            }
        }

        MouseArea {
            anchors.fill: parent
            onClicked: {
                let state = {
                    1: "red",
                    2: "blue",
                    3: "black"
                }
                yellowRect.state = state[myRect.type]

                myRect.type++
                if ( myRect.type > 3 ) {
                    myRect.type = 1
                }
            }
        }
    }
}

PathAnimation - 沿路径设置项目的动画

 

Rectangle {
    width: 400; height: 400

    PathInterpolator {
        id: motionPath

        path: Path {
            startX: 0; startY: 0

            PathCubic {
                x: 350; y: 350

                control1X: 350; control1Y: 0
                control2X: 0; control2Y: 350
            }
        }

        NumberAnimation on progress { id: animation; from: 0; to: 1; duration: 2000 }
    }

    Rectangle {
        x: motionPath.x; y: motionPath.y
        width: 50; height: 50
        rotation: motionPath.angle
        color: "green"
    }

    MouseArea {
        anchors.fill: parent
        onClicked: animation.start()
    }
}

PropertyAnimation - 为特性值的更改设置动画

 

Rectangle {
    width: 100; height: 100
    color: "red"

    property bool location: true

    Behavior on x { PropertyAnimation {} }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            var x = location ? 50 : 0
            parent.x = x
            location = !location
        }
    }
}

RotationAnimation - 为旋转的更改设置动画

 

Item {
    width: 300; height: 300

    Rectangle {
        id: myRect
        width: 150; height: 100
        anchors.centerIn: parent
        color: "red"
        antialiasing: true

        property int type: 1

        states: [
            State {
                name: "state1"
                PropertyChanges { target: myRect; rotation: 45 }
            },
            State {
                name: "state2"
                PropertyChanges { target: myRect; rotation: 90 }
            },
            State {
                name: "state3"
                PropertyChanges { target: myRect; rotation: 180 }
            }
        ]

        transitions: Transition {
            RotationAnimation { duration: 1000; direction: RotationAnimation.Counterclockwise }
        }
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            let state = {
                1: "state1",
                2: "state2",
                3: "state3"
            }
            myRect.state = state[myRect.type]

            myRect.type++
            if ( myRect.type > 3 ) {
                myRect.type = 1
            }
        }
    }
}

Vector3dAnimation - 为 QVector3d 值的更改设置动画

 

Rectangle {
    id: myRect
    x: 50; y: 50
    width: 100; height: 100
    color: "red"

    transform: Rotation {
        angle: 45
        origin.x: 50; origin.y: 50
        axis: Qt.vector3d(0, 1, 0)

        SequentialAnimation on axis {
            id: animation
            running: false
            Vector3dAnimation { from: "1, 0, 0"; to: "0, 1, 0"; duration: 1000 }
            Vector3dAnimation { from: "0, 1, 0"; to: "0, 0, 1"; duration: 1000 }
            Vector3dAnimation { from: "0, 0, 1"; to: "1, 0, 1"; duration: 1000 }
            Vector3dAnimation { from: "1, 0, 1"; to: "1, 1, 0"; duration: 1000 }
            Vector3dAnimation { from: "1, 1, 0"; to: "1, 1, 1"; duration: 1000 }
            Vector3dAnimation { from: "1, 1, 1"; to: "1, 0, 1"; duration: 1000 }
            Vector3dAnimation { from: "1, 0, 1"; to: "0, 0, 1"; duration: 1000 }
            Vector3dAnimation { from: "0, 0, 1"; to: "0, 1, 0"; duration: 1000 }
            Vector3dAnimation { from: "0, 1, 0"; to: "1, 0, 0"; duration: 1000 }
        }
    }

    MouseArea {
        anchors.fill: parent
        onClicked: animation.start()
    }
}

组合动画

  • SequentialAnimation - 按顺序运行动画

 

Rectangle {
    id: rect
    width: 100; height: 100
    color: "red"

    SequentialAnimation {
        id: animation
        running: false
        NumberAnimation { target: rect; property: "x"; to: 100; duration: 500 }
        NumberAnimation { target: rect; property: "y"; to: 100; duration: 500 }
        NumberAnimation { target: rect; property: "x"; to: 0; duration: 500 }
        NumberAnimation { target: rect; property: "y"; to: 0; duration: 500 }
    }

    MouseArea {
        anchors.fill: parent
        onClicked: animation.start()
    }
}

ParallelAnimation - 并行运行动画

 

Rectangle {
    id: rect
    width: 100; height: 100
    color: "red"

    ParallelAnimation {
        id: animation
        running: false
        NumberAnimation { target: rect; property: "x"; to: 100; duration: 1000 }
        NumberAnimation { target: rect; property: "y"; to: 100; duration: 1000 }
        NumberAnimation { target: rect; property: "width"; to: 200; duration: 1000 }
        NumberAnimation { target: rect; property: "height"; to: 200; duration: 1000 }
        NumberAnimation { target: rect; property: "rotation"; to: 90; duration: 1000 }
    }

    MouseArea {
        anchors.fill: parent
        onClicked: animation.start()
    }
}

行为动画

  • Behavior - 为特性更改指定默认动画

 

Rectangle {
    id: coloredRect
    width: 100; height: 100
    anchors.centerIn: parent
    color: "red"

    states: State {
        name: "GreenState"
        when: mouser.containsMouse

        PropertyChanges {
            target: coloredRect
            color: "green"
        }
    }

    Behavior on color {  ColorAnimation {} }

    MouseArea {
        id: mouser
        anchors.fill: parent
        hoverEnabled: true
    }
}

动画暂停

  • PauseAnimation - 在动画中引入暂停

 

Rectangle {
    id: rect
    width: 100; height: 100
    color: "red"

    SequentialAnimation {
        id: animation
        running: false
        NumberAnimation { target: rect; property: "x"; to: 100; duration: 500 }
        NumberAnimation { target: rect; property: "y"; to: 100; duration: 500 }
        PauseAnimation { duration: 1000 }
        NumberAnimation { target: rect; property: "x"; to: 0; duration: 500 }
        NumberAnimation { target: rect; property: "y"; to: 0; duration: 500 }
    }

    MouseArea {
        anchors.fill: parent
        onClicked: animation.start()
    }
}

弹簧动画

  • SpringAnimation - 模拟弹簧的振荡行为,使用适当的弹簧常数来控制加速度和阻尼,以控制效果消失的速度

 

Rectangle {
    id: rect
    width: 50; height: 50
    color: "red"

    Behavior on x { SpringAnimation { spring: 2; damping: 0.2 } }
    Behavior on y { SpringAnimation { spring: 2; damping: 0.2 } }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            rect.x = mouse.x - rect.width/2
            rect.y = mouse.y - rect.height/2
        }
    }
}

属性跟踪动画

  • SmoothedAnimation - 允许特性平滑跟踪值

 

Item {
    Rectangle {
        width: 60; height: 60
        x: rect1.x - 5; y: rect1.y - 5
        color: "green"

        Behavior on x { SmoothedAnimation { velocity: 200; duration: 500 } }
        Behavior on y { SmoothedAnimation { velocity: 200; duration: 500 } }
    }

    Rectangle {
        id: rect1
        x: 5; y: 5
        width: 50; height: 50
        color: "red"
    }

    focus: true
    Keys.onRightPressed: rect1.x = rect1.x + 100
    Keys.onLeftPressed: rect1.x = rect1.x - 100
    Keys.onUpPressed: rect1.y = rect1.y - 100
    Keys.onDownPressed: rect1.y = rect1.y + 100
}

动画中运行脚本

  • ScriptAction - 在动画中运行脚本

 

Rectangle {
    id: rect
    width: 100; height: 100
    color: "red"

    SequentialAnimation {
        id: animation
        running: false
        NumberAnimation { target: rect; property: "x"; to: 100; duration: 500 }
        NumberAnimation { target: rect; property: "y"; to: 100; duration: 500 }
        ScriptAction { script: doSomething() }
        NumberAnimation { target: rect; property: "x"; to: 0; duration: 500 }
        NumberAnimation { target: rect; property: "y"; to: 0; duration: 500 }
        ScriptAction { script: doStateStuff() }
    }

    MouseArea {
        anchors.fill: parent
        onClicked: animation.start()
    }

    function doSomething() {
        rect.color = "blue"
        rect.width = 120
        rect.height = 120
    }

    function doStateStuff() {
        rect.color = "red"
        rect.width = 100
        rect.height = 100
    }
}

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值