Qt6 Qt Quick UI prototype learning QML seventh


Effect demo

insert image description here

insert image description here

QML syntaxClickableImageV2.qml

import QtQuick 2.0

// 用于创建一个可点击的项目(Item)
Item {
    
    
    id:root
    // 设置项目的宽度为column子元素的宽度。
    width: column.childrenRect.width
    height: column.childrenRect.height

    // 定义一个名为text的属性,该属性与label的text属性关联,允许在外部访问和修改该属性。
    property alias text: label.text
    property alias source: image.source

    // signal clicked - 声明一个clicked信号,表示项目被点击的事件。
    signal clicked

    Column {
    
    
        id:column
        spacing: 10
        Image {
    
    
            id: image
            sourceSize: Qt.size(90,90)
        }

        Text {
    
    
            id: label
           width: image.width
           // 设置文本的水平对齐方式为居中对齐。
            horizontalAlignment: Text.AlignHCenter
            wrapMode: Text.WordWrap
            color: "#000000"
        }
    }

    MouseArea {
    
    
        // 设置鼠标区域的大小与父元素(即Item)相同。
        anchors.fill: parent
        // 当鼠标区域被点击时,触发项目的clicked信号
        onClicked: root.clicked()
    }
}

QML syntax EasingCurves.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.3




Rectangle {
    
    
    id: root

        property int duration: 3000
        property Item ufo: ufo
        property Item ufo1: ufo1

        width: 600
        height: 400

        Image {
    
    
            anchors.fill: parent
            source: "pic//2.jpg"
        }

        ClickableImageV2 {
    
    
            id: ufo
            x: 20; y: root.height-height
            text: qsTr('ufo')
            clip: false
            visible: true
            source: "pic//3.jpg"
            onClicked: anim.restart()
        }

        ClickableImageV2 {
    
    
            id: ufo1
            x:120; y: root.height-height
            text: qsTr('ufo1')
            clip: false
            visible: true
            source: "pic//4.jpg"
            onClicked: anim1.restart()
        }


        // 并行动画
        ParallelAnimation {
    
    
            id: anim
            NumberAnimation {
    
    
                target: ufo
                properties: "y"
                to: 20
                duration: root.duration
            }
            NumberAnimation {
    
    
                target: ufo
                properties: "x"
                to: 160
                duration: root.duration
            }
        }

        // 连续动画 顺序动画按照声明的顺序运行每个子动画:从上到下。
        SequentialAnimation {
    
    
               id: anim1
               NumberAnimation {
    
    
                   target: ufo1
                   properties: "y"
                   to: 20
                   // 60% of time to travel up
                   duration: root.duration * 0.6
               }
               NumberAnimation {
    
    
                   target: ufo1
                   properties: "x"
                   to: 400
                   // 40% of time to travel sideways
                   duration: root.duration * 0.4
               }
           }

}

Clock ball rolling QML source code

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.3
import Qt.labs.calendar 1.0

Rectangle {
    
    
    id: root
    property int duration: 3000

       width: 600
       height: 400

    // 上面的蓝色矩形高度为200像素,下面的矩形固定在天空的底部和根元素的底部。
    Rectangle {
    
    
        id: sky
        width: parent.width
        height: 200
        gradient: Gradient {
    
    
            GradientStop {
    
     position: 0.0; color: "#0080FF" }
            GradientStop {
    
     position: 1.0; color: "#66CCFF" }
        }
    }
    Rectangle {
    
    
        id: ground
        anchors.top: sky.bottom
        anchors.bottom: root.bottom
        width: parent.width
        gradient: Gradient {
    
    
            GradientStop {
    
     position: 0.0; color: "#00FF00" }
            GradientStop {
    
     position: 1.0; color: "#00803F" }
        }
    }

    Image {
    
    
        id: ball
        x: 0; y: root.height-height
        source: "pic//clock.png"

        // 该图像附有一个鼠标区域。如果球被点击,球的位置将重置,动画将重新开始。
        MouseArea {
    
    
            anchors.fill: parent
            onClicked: {
    
    
                ball.x = 0
                ball.y = root.height-ball.height
                ball.rotation = 0
                anim.restart()
            }
        }
    }

    ParallelAnimation {
    
    
        id: anim
        SequentialAnimation {
    
    
            NumberAnimation {
    
    
                target: ball
                properties: "y"
                to: 20
                duration: root.duration * 0.4
                easing.type: Easing.OutCirc
            }
            NumberAnimation {
    
    
                target: ball
                properties: "y"
                to: root.height-ball.height
                duration: root.duration * 0.6
                easing.type: Easing.OutBounce
            }
        }
        NumberAnimation {
    
    
            target: ball
            properties: "x"
            to: root.width-ball.width
            duration: root.duration
        }
        RotationAnimation {
    
    
            target: ball
            properties: "rotation"
            to: 720
            duration: root.duration
        }
    }
}


## Clock ball rolling QML explanation

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.3
import Qt.labs.calendar 1.0

Rectangle { id: root property int duration: 3000

   宽度: 600
   高度: 400

// 上面的蓝色矩形高度为200像素,下面的矩形固定在天空的底部和根元素的底部。
矩形 {
    id: 天空
    宽度: 父宽度
    高度: 200
    渐变: 渐变 {
        渐变停止 { 位置: 0.0; 颜色: "#0080FF" }
        渐变停止 { 位置: 1.0; 颜色: "#66CCFF" }
    }
}
矩形 {
    id: 地面
    锚点.顶: 天空.底部
    锚点.底: root.底部
    宽度: 父宽度
    渐变: 渐变 {
        渐变停止 { 位置: 0.0; 颜色: "#00FF00" }
        渐变停止 { 位置: 1.0; 颜色: "#00803F" }
    }
}

图像 {
    id: 球
    x: 0; y: root.高度-高度
    源: "图片//clock.png"

    // 该图像附有一个鼠标区域。如果球被点击,球的位置将重置,动画将重新开始。
    鼠标区域 {
        锚点.填充: 父
        当被点击时: {
            球.x = 0
            球.y = root.高度-球.高度
            球.旋转 = 0
            动画.restart()
        }
    }
}

并行动画 {
    id: 动画
    顺序动画 {
        数字动画 {
            目标: 球
            属性: "y"
            到: 20
            持续时间: root.duration * 0.4
            缓动类型: Easing.OutCirc
        }
        数字动画 {
            目标: 球
            属性: "y"
            到: root.高度-球.高度
            持续时间: root.duration * 0.6
            缓动类型: Easing.OutBounce
        }
    }
    数字动画 {
        目标: 球
        属性: "x"
        到: root.宽度-球.宽度
        持续时间: root.duration
    }
    旋转动画 {
        目标: 球
        属性: "旋转"
        到: 720
        持续时间: root.duration
    }
}

}

grammar explanation

This code uses the QtQuick library to create a user interface. Among them, Rectangle is the root element of the interface.

  • id: root: Specifies the unique identifier root for the Rectangle element.

  • property int duration: 3000: Defines an integer attribute named duration with an initial value of 3000.

  • property Item ufo: ufo: Defines an Item type attribute named ufo, and the corresponding object is ufo.

  • property Item ufo1: ufo1: Defines an Item type attribute named ufo1, and the corresponding object is ufo1.

  • width: 600: Set the width of the Rectangle to 600.

  • height: 400: Set the height of the Rectangle to 400.

  • The Image element is nested inside the Rectangle and is used to display images. anchors.fill: parent indicates that the size of the image is the same as that of the parent element Rectangle, and source specifies that the source of the image is "pic//2.jpg".

  • The ClickableImageV2 element represents a clickable image object. The id attribute specifies a unique identifier for the ufo, and the other attributes set its position, text, visibility, and image source. The onClicked event specifies that when the image object is clicked, the restart() method of the anim animation object is executed.

  • Similarly, another ClickableImageV2 element is defined, which represents another clickable image object with a unique id, position, text, visibility, and image source. When the image object is clicked, the restart() method of the anim1 animation object is executed.

  • The ParallelAnimation element represents a parallel animation, which contains two NumberAnimation elements. The first NumberAnimation object sets the target as the ufo object, and moves it to the position of y=20 by changing the y property, and the duration is the time specified by root.duration. The second NumberAnimation object sets the target as the ufo object, and moves it to the position of x=160 by changing the x property, and the duration is also root.duration.

  • The SequentialAnimation element represents a continuous animation, which contains two NumberAnimation elements. These animations will be executed sequentially and sequentially. The first animation sets the target as the ufo1 object, and moves it to the position of y=20 by changing the y property, and the duration is root.duration * 0.6, which is 60% of the movement time. The second animation sets the target as the ufo1 object, and moves it to the position of x=400 by changing the x property, and the duration is root.duration * 0.4, which is 40% of the movement time.

The entire code block implements a user interface that includes images, clickable image objects, and parallel and sequential animation effects.

reference

cartoon

Animations are applied to property changes. Animations define an interpolation curve from one value to another as the property value changes. These animation curves create smooth transitions from one value to another.

An animation is defined by a sequence of target properties to animate, an easing curve for the interpolation curve, and a duration. All animations in Qt Quick are controlled by the same timer and are therefore synchronous. This improves the performance and visual quality of animations.

Animations use value interpolation to control how properties change

This is a basic concept. QML is based on elements, attributes and scripts. Each element provides dozens of attributes, and each attribute is waiting for you to activate. In the books, you'll see it's a spectacular arena.

You'll find yourself looking at some animations and admiring their beauty, but also your creative genius. Remember: animations control property changes, and every element has dozens of properties at your disposal.

insert image description here

// AnimationExample.qml

import QtQuick

Image {
    
    
    id: root
    source: "assets/background.png"

    property int padding: 40
    property int duration: 4000
    property bool running: false

    Image {
    
    
        id: box
        x: root.padding;
        y: (root.height-height)/2
        source: "assets/box_green.png"

        NumberAnimation on x {
    
    
            to: root.width - box.width - root.padding
            duration: root.duration
            running: root.running
        }
        RotationAnimation on rotation {
    
    
            to: 360
            duration: root.duration
            running: root.running
        }
    }

    MouseArea {
    
    
        anchors.fill: parent
        onClicked: root.running = true
    }

}

The example above shows an attribute applied to the x and rotation properties. Each animation has a duration of 4000 milliseconds. Animation start x gradually moves the object's x coordinate to 240 pixels. The rotation animation runs 360 degrees from the current angle. These two animations run in parallel and are clicked on the MouseArea.

You can do this by changing the to and duration properties, or you can add another animation (for example, on opacity or even scale). Combine these and it looks like the object is disappearing into deep space. Try it!

animated elements

There are several types of animated elements, each optimized for a specific use case. Here is a list of the most famous animations:

  • PropertyAnimation - Shows changes in property values

  • NumberAnimation - Shows changes in real type values

  • ColorAnimation - animates changes in color values

  • RotationAnimation - Animates changes in rotation values

Besides these basic and widely used animation elements, Qt Quick also provides more specialized animations for specific use cases:

  1. PauseAnimation - Provides a pause for animations

  2. SequentialAnimation - allows animations to run sequentially

  3. ParallelAnimation - Allows animations to run in parallel

  4. AnchorAnimation - Animate changes in anchor values

  5. ParentAnimation - fires changes in parent values

  6. SmoothedAnimation - allows properties to track values ​​smoothly

  7. SpringAnimation - Allows properties to track values ​​in a spring-like motion

  8. PathAnimation - animates items along a path

  9. Vector3dAnimation - animation showing changes in QVector3d values

Later we will learn how to create an animation sequence. When working with more complex animations, it is sometimes necessary to change properties or run scripts during an ongoing animation. For this purpose, Qt Quick provides action elements, which can be used anywhere other animated elements can be used:

  • PropertyAction - Specifies an immediate property change during an animation

  • ScriptAction - Defines a script to run during the animation

The main animation types are discussed in this chapter using small, focused examples.

apply animation

Animations can be applied in various ways:

Property animation - runs automatically after the element is fully loaded

Property Behavior - run automatically when property value changes

Independent animation - run when using an explicit start animation with start() or running is set to true (e.g. via property binding)

Later we will also see how to use animations in state transitions.

Clickable Image V2

To demonstrate the use of animations, we reused the ClickableImage component from the previous chapter and extended it with a text element.

// ClickableImageV2.qml
// Simple image which can be clicked

import QtQuick

Item {
    
    
    id: root
    width: container.childrenRect.width
    height: container.childrenRect.height
    property alias text: label.text
    property alias source: image.source
    signal clicked

    Column {
    
    
        id: container
        Image {
    
    
            id: image
        }
        Text {
    
    
            id: label
            width: image.width
            horizontalAlignment: Text.AlignHCenter
            wrapMode: Text.WordWrap
            color: "#ececec"
        }
    }

    MouseArea {
    
    
        anchors.fill: parent
        onClicked: root.clicked()
    }
}

To organize the elements below the image, we used a column locator and calculated the width and height from the childrenRect property of the column. We expose text and image source properties, and a click signal. We also want the text to be as wide as the image and to wrap. We do this by using the wrapMode property of the text element.

Parent/Child Geometry Dependencies

Due to the inversion of geometry dependencies (parent geometry depends on child geometry), we cannot set width/height on ClickableImageV2 as this would break our width/height binding.

If the item is more like a container for other items and should adapt to the parent's geometry, you should prefer the child's geometry to be dependent on the parent's geometry.

rising object

insert image description here

All three objects are at the same y position (y=200). They all need to go to y=40 and each uses a different method, with different side effects and characteristics.

first object

The first object uses the Animation on strategy. Animation will start immediately.

ClickableImageV2 {
    
    
    id: greenBox
    x: 40; y: root.height-height
    source: "assets/box_green.png"
    text: qsTr("animation on property")
    NumberAnimation on y {
    
    
        to: 40; duration: 4000
    }
}

When an object is clicked, its y position is reset to the starting position, and this applies to all objects. On the first object, the reset has no effect as long as the animation is running.

This can be visually disruptive because the y-position is set to a new value for a fraction of a second before the animation starts. Such competing property changes should be avoided.

second object

The second object is animated using Behavior on. This behavior tells the property that it should animate every change in value. This behavior can be disabled by setting enabled: false on the Behavior element.

ClickableImageV2 {
    
    
    id: blueBox
    x: (root.width-width)/2; y: root.height-height
    source: "assets/box_blue.png"
    text: qsTr("behavior on property")
    Behavior on y {
    
    
        NumberAnimation {
    
     duration: 4000 }
    }

    onClicked: y = 40
    // random y on each click
    // onClicked: y = 40 + Math.random() * (205-40)
}

When you click on the object it will start moving (its y position will be set to 40). Another click has no effect because the position is already set.

You can try using a random value like 40 + (Math.random() * (205-40)) for the y position. You will see that the object will always animate to the new position and adjust its speed to match the animation duration defined by 4 seconds to the destination.

third object

The third object uses independent animation. Animation is defined as its own element and can appear almost anywhere in the document.

ClickableImageV2 {
    
    
    id: redBox
    x: root.width-width-40; y: root.height-height
    source: "assets/box_red.png"
    onClicked: anim.start()
    // onClicked: anim.restart()

    text: qsTr("standalone animation")

    NumberAnimation {
    
    
        id: anim
        target: redBox
        properties: "y"
        to: 40
        duration: 4000
    }
}

Clicking will use the animation's start animation start() function. Every animation has start(), stop(), resume() and restart() functions. Animation itself contains much more information than other earlier animation types.

We need to define target, which is the element to animate, and the name of the property we want to animate. We also need to define a to value, in this case a from value, which allows the animation to start over.

insert image description here

Clicking on the background will reset all objects to their initial positions. The first object cannot be restarted unless a reload of the element is triggered by restarting the program.

Other ways to control animation

Another way to start/stop the animation is to bind a property to the running animation's property. This is especially useful when user input controls properties:

NumberAnimation {
    
    
    // [...]
    // animation runs when mouse is pressed
    running: area.pressed
}
MouseArea {
    
    
    id: area
}

Spiral curve

A property's value change can be controlled by animation. Easing properties allow interpolation curves that affect property changes.
insert image description here

All the animations we define now use linear interpolation because the animation's initial easing type is Easing.Linear. This is best visualized with a small graph, where the y-axis is the property being animated and the x-axis is time (duration). Linear interpolation adds the value from when the from animation begins to the value at the end of the to animation. So the easing type defines the transition curve.

The type of easing should be chosen carefully to support the natural fit of moving objects. For example, when a page slides out, the page should initially slide out slowly, then gain momentum to eventually slide out at high speed, similar to turning a page.

Animations should not be overused.

Like other aspects of UI design, animation should be carefully designed to support the UI flow, not dominate it. Eyes are very sensitive to moving objects, and animations can easily distract users.

In the next example we'll try out some spirals. Each easing curve is represented by a clickable image that, when clicked, animates in the square, then triggers a restart() to run the animation with the new curve.

The code for this example gets a little more complicated. We first create a Mesh with EasingTypes and a Box which is controlled by the easing type. The easing type only shows the curves that the box uses for animation. When the user clicks on the spiral, the box moves in one direction according to the spiral. The animation itself is a standalone animation with the target set to a box and configured as an x-property animation with a duration of 2 seconds.

The interior of EasingType presents curves in real time, and interested readers can take an example in EasingCurves.

// EasingCurves.qml

import QtQuick
import QtQuick.Layouts

Rectangle {
    
    
    id: root
    width: childrenRect.width
    height: childrenRect.height

    color: '#4a4a4a'
    gradient: Gradient {
    
    
        GradientStop {
    
     position: 0.0; color: root.color }
        GradientStop {
    
     position: 1.0; color: Qt.lighter(root.color, 1.2) }
    }

    ColumnLayout {
    
    
        Grid {
    
    
            spacing: 8
            columns: 5
            EasingType {
    
    
                easingType: Easing.Linear
                title: 'Linear'
                onClicked: {
    
    
                    animation.easing.type = easingType
                    box.toggle = !box.toggle
                }
            }
            EasingType {
    
    
                easingType: Easing.InExpo
                title: "InExpo"
                onClicked: {
    
    
                    animation.easing.type = easingType
                    box.toggle = !box.toggle
                }
            }
            EasingType {
    
    
                easingType: Easing.OutExpo
                title: "OutExpo"
                onClicked: {
    
    
                    animation.easing.type = easingType
                    box.toggle = !box.toggle
                }
            }
            EasingType {
    
    
                easingType: Easing.InOutExpo
                title: "InOutExpo"
                onClicked: {
    
    
                    animation.easing.type = easingType
                    box.toggle = !box.toggle
                }
            }
            EasingType {
    
    
                easingType: Easing.InOutCubic
                title: "InOutCubic"
                onClicked: {
    
    
                    animation.easing.type = easingType
                    box.toggle = !box.toggle
                }
            }
            EasingType {
    
    
                easingType: Easing.SineCurve
                title: "SineCurve"
                onClicked: {
    
    
                    animation.easing.type = easingType
                    box.toggle = !box.toggle
                }
            }
            EasingType {
    
    
                easingType: Easing.InOutCirc
                title: "InOutCirc"
                onClicked: {
    
    
                    animation.easing.type = easingType
                    box.toggle = !box.toggle
                }
            }
            EasingType {
    
    
                easingType: Easing.InOutElastic
                title: "InOutElastic"
                onClicked: {
    
    
                    animation.easing.type = easingType
                    box.toggle = !box.toggle
                }
            }
            EasingType {
    
    
                easingType: Easing.InOutBack
                title: "InOutBack"
                onClicked: {
    
    
                    animation.easing.type = easingType
                    box.toggle = !box.toggle
                }
            }
            EasingType {
    
    
                easingType: Easing.InOutBounce
                title: "InOutBounce"
                onClicked: {
    
    
                    animation.easing.type = easingType
                    box.toggle = !box.toggle
                }
            }
        }
        Item {
    
    
            height: 80
            Layout.fillWidth: true
            Box {
    
    
                id: box
                property bool toggle
                x: toggle ? 20 : root.width - width - 20
                anchors.verticalCenter: parent.verticalCenter
                gradient: Gradient {
    
    
                    GradientStop {
    
     position: 0.0; color: "#2ed5fa" }
                    GradientStop {
    
     position: 1.0; color: "#2467ec" }
                }
                Behavior on x {
    
    
                    NumberAnimation {
    
    
                        id: animation
                        duration: 500
                    }
                }
            }
        }
    }
}

Play the example to see how the speed changes in the animation. Some animations feel more natural to objects, while others are off-putting.

In addition to duration and easing.type, you can fine-tune the animation. For example, the General PropertyAnimation type (from which most animations inherit) also supports easing.amplitude , easing.overshoot , and easing.period properties, which allow you to fine-tune the behavior of specific easing curves.

Not all easing curves support these parameters. Please refer to the relax table (opens new window) documentation from PropertyAnimation to check if the easing parameters have an effect on the easing curve.

Choose the right animation

Choosing the right animation for elements in the context of the user interface is critical to the result. Remember that animations should support the UI flow; not irritate the user.

group animation

Often the animation will be more complex than just animating a single property. You may wish to run several animations simultaneously or one after the other, or even execute a script between two animations.

For this, grouped animations can be used. As the name suggests, animations can be grouped. Grouping can be done in two ways: parallel or sequential. You can use SequentialAnimation or ParallelAnimation elements, which act as animation containers for other animated elements. These grouped animations are themselves animations and can be used exactly as-is.
insert image description here

parallel animation

All immediate child animations of a parallel animation run in parallel on startup. This allows you to animate different properties simultaneously.

// ParallelAnimationExample.qml
import QtQuick

BrightSquare {
    
    
    id: root

    property int duration: 3000
    property Item ufo: ufo

    width: 600
    height: 400

    Image {
    
    
        anchors.fill: parent
        source: "assets/ufo_background.png"
    }

    ClickableImageV3 {
    
    
        id: ufo
        x: 20; y: root.height-height
        text: qsTr('ufo')
        source: "assets/ufo.png"
        onClicked: anim.restart()
    }

    ParallelAnimation {
    
    
        id: anim
        NumberAnimation {
    
    
            target: ufo
            properties: "y"
            to: 20
            duration: root.duration
        }
        NumberAnimation {
    
    
            target: ufo
            properties: "x"
            to: 160
            duration: root.duration
        }
    }
}

insert image description here

continuous animation

Sequential animations run each sub-animation in the order declared: top to bottom.

// SequentialAnimationExample.qml
import QtQuick

BrightSquare {
    
    
    id: root

    property int duration: 3000
    property Item ufo: ufo

    width: 600
    height: 400

    Image {
    
    
        anchors.fill: parent
        source: "assets/ufo_background.png"
    }

    ClickableImageV3 {
    
    
        id: ufo
        x: 20; y: root.height-height
        text: qsTr('rocket')
        source: "assets/ufo.png"
        onClicked: anim.restart()
    }

    SequentialAnimation {
    
    
        id: anim
        NumberAnimation {
    
    
            target: ufo
            properties: "y"
            to: 20
            // 60% of time to travel up
            duration: root.duration * 0.6
        }
        NumberAnimation {
    
    
            target: ufo
            properties: "x"
            to: 400
            // 40% of time to travel sideways
            duration: root.duration * 0.4
        }
    }
}

insert image description here

nested animation

Grouped animations can also be nested. For example, a continuous animation can have two parallel animations as sub-animations, and so on. We can visualize this with a football example. The idea is to throw a ball from left to right and animate its behavior.

insert image description here

To understand animation, we need to break it down into the overall transformation of an object. We need to remember that an animation is an animation of a property change. The following are the different conversions:

x translation from left to right (X1)

y translation from bottom to top (Y1) followed by translation from top to bottom (Y2) with some bouncing

Rotate 360 ​​degrees (ROT1) for the entire duration of the animation

The entire duration of the animation should be three seconds.

insert image description here

We start with an empty item as the root element with a width of 480 and a height of 300.

import QtQuick

Item {
    
    
    id: root

    property int duration: 3000

    width: 480
    height: 300

    // [...]
}

We have defined our total animation duration as a reference to better synchronize animation parts.

The next step is to add a background, in our case two rectangles with a green and blue gradient.

Rectangle {
    
    
    id: sky
    width: parent.width
    height: 200
    gradient: Gradient {
    
    
        GradientStop {
    
     position: 0.0; color: "#0080FF" }
        GradientStop {
    
     position: 1.0; color: "#66CCFF" }
    }
}
Rectangle {
    
    
    id: ground
    anchors.top: sky.bottom
    anchors.bottom: root.bottom
    width: parent.width
    gradient: Gradient {
    
    
        GradientStop {
    
     position: 0.0; color: "#00FF00" }
        GradientStop {
    
     position: 1.0; color: "#00803F" }
    }
}

insert image description here

The upper blue rectangle has a height of 200px, and the lower rectangle is anchored to the bottom of the sky and the bottom of the root element.

Let's bring football to grass. The ball is an image, stored under "assets/soccer_ball.png". First, we want to place it in the bottom left corner, near the edge.

Image {
    
    
    id: ball
    x: 0; y: root.height-height
    source: "assets/soccer_ball.png"

    MouseArea {
    
    
        anchors.fill: parent
        onClicked: {
    
    
            ball.x = 0
            ball.y = root.height-ball.height
            ball.rotation = 0
            anim.restart()
        }
    }
}

insert image description here

The image has a mouse area attached to it. If the ball is clicked, the position of the ball will reset and the animation will start over.

Let's start with a continuous animation of two y-translations.

SequentialAnimation {
    
    
    id: anim
    NumberAnimation {
    
    
        target: ball
        properties: "y"
        to: 20
        duration: root.duration * 0.4
    }
    NumberAnimation {
    
    
        target: ball
        properties: "y"
        to: 240
        duration: root.duration * 0.6
    }
}

insert image description here

This specifies that 40% of the total animation duration should be animated up and 60% should be animated down, with each animation running in sequence. The transform animates on a linear path, but currently has no curves. Curves will be added later using easing curves, and at this point we're focusing on animating the transform.

Next, we need to add the x translation. The x translation should run in parallel with the y translation, so we need to wrap the y translation sequence together with the x translation into a parallel animation.

ParallelAnimation {
    
    
    id: anim
    SequentialAnimation {
    
    
        // ... our Y1, Y2 animation
    }
    NumberAnimation {
    
     // X1 animation
        target: ball
        properties: "x"
        to: 400
        duration: root.duration
    }
}

insert image description here

Finally, we want the ball to spin. To do this, we need to add another animation inside the parallel animation. We choose RotationAnimation because it is dedicated to rotation.

ParallelAnimation {
    
    
    id: anim
    SequentialAnimation {
    
    
        // ... our Y1, Y2 animation
    }
    NumberAnimation {
    
     // X1 animation
        // X1 animation
    }
    RotationAnimation {
    
    
        target: ball
        properties: "rotation"
        to: 720
        duration: root.duration
    }
}

That's the whole animation sequence. The only thing left is to provide the correct easing curve for the ball's movement. For the Y1 animation we use an Easing.OutCirc curve since this should look more like a circular motion. Y2 is using Easing.OutBounce to make the ball bounce, the bounce should happen at the end (try it with Easing.InBounce and you will see the bounce start immediately).

The X1 and ROT1 animations remain as they are, with a linear curve.

Here is the final animation code for your reference:

ParallelAnimation {
    
    
    id: anim
    SequentialAnimation {
    
    
        NumberAnimation {
    
    
            target: ball
            properties: "y"
            to: 20
            duration: root.duration * 0.4
            easing.type: Easing.OutCirc
        }
        NumberAnimation {
    
    
            target: ball
            properties: "y"
            to: root.height-ball.height
            duration: root.duration * 0.6
            easing.type: Easing.OutBounce
        }
    }
    NumberAnimation {
    
    
        target: ball
        properties: "x"
        to: root.width-ball.width
        duration: root.duration
    }
    RotationAnimation {
    
    
        target: ball
        properties: "rotation"
        to: 720
        duration: root.duration
    }
}

Guess you like

Origin blog.csdn.net/m0_45463480/article/details/131926028