PropertyAnimation vs. NumberAnimation - qt

The QML code below animates two rectangles. One uses PropertyAnimation, while the other uses NumberAnimation. Both rectangles move similarly. I don't see anything different between the two animation types.
import QtQuick 2.0
import QtQuick.Window 2.0
Window {
visible: true
width: 640
height: 480
Rectangle {
id: r1
width: 100; height: 100
color: "red"
Behavior on x { PropertyAnimation {} }
}
Rectangle {
id: r2
y: 150
width: 100; height: 100
color: "blue"
Behavior on x { NumberAnimation {} }
}
// click anywhere to start animation
MouseArea { anchors.fill: parent; onClicked: r1.x = r2.x = 200 }
}
What is the difference between PropertyAnimation and NumberAnimation; and when should I use one over the other?

tl;dr.
NumberAnimation is derived from PropertyAnimation, and thus, it makes logical sense for them to exhibit similar behaviour.
NumberAnimation is a specialized PropertyAnimation that defines an animation to be applied when a numerical value changes.
(Source)
While NumberAnimation specifically animates numeric values (e.g. x, y, width, opacity), PropertyAnimation is generic and can animate non-numeric ones (e.g. color, size).
Lé longer answer:
1. PropertyAnimation can animate non-numeric types. NumberAnimation only animates numbers.
NumericAnimation can animate numeric properties such as x, y, width, height, opacity. But it can't animate color, size, or points.
Here's an example where the animation types differ in animating the color property. The first rectangle transitions from red to green while the second rectangle stays blue. In this case, PropertyAnimation should be used over NumberAnimation.
Rectangle {
id: r1
width: 100; height: 100
color: "red"
Behavior on color { PropertyAnimation {} } // works
}
Rectangle {
id: r2
y: 150
width: 100; height: 100
color: "blue"
Behavior on color { NumberAnimation {} } // fails
}
MouseArea { anchors.fill: parent; onClicked: r1.color = r2.color = "green" }
But then again, you can ColorAnimation instead...
2. PropertyAnimation is generic.
This is a build-off from #1. But this is another advantage on its own.
Since PropertyAnimation is more generic, it can be used if you decide to have a dynamic PropertyAnimation::property.
Here's an example where the animation property is user-provided:
Rectangle {
id: rect
width: 100; height: 100
color: "red"
PropertyAnimation { id: animation; target: rect }
}
MouseArea {
anchors.fill: parent
onClicked: {
animation.property = t1.text;
animation.to = t2.text;
animation.start();
}
}
Row {
width: parent.width; height: 50
anchors.bottom: parent.bottom
TextField { id: t1; width: parent.width/2; height: 50; placeholderText: "property" }
TextField { id: t2; width: parent.width/2; height: 50; placeholderText: "to" }
}
Using NumberAnimation also works, but restricts the viable properties to only numeric ones... users can't simulate supernovas or rainbows. :(
3. NumberAnimation is strict.
Let's compare the from and to properties.
NumberAnimation
from: real
to: real
PropertyAnimation
from: variant
to: variant
This makes NumberAnimation stricter. QML will prevent you from making silly mistakes:
NumberAnimation {
id: animation
to: "green" // Invalid property assignment: number expected
}
Use it when you're strictly limited animating numbers.
This also means that using NumberAnimation can improve readability and communication. It tells the people reading your code that you're only intending to animate numbers — not anchors, colours, unicorns or whatever.
4. NumberAnimation is more efficient at animating numbers.
– says Qt:
Specialized property animation types have more efficient implementations than the PropertyAnimation type.
(Source)
Here, the "specialized types" refers to NumberAnimation, along with other types such as AnchorAnimation and ColorAnimation.
I haven't tried profiling QML to benchmark the differences, but it seems like the rule of thumb for choosing animation types is:
If you're animating numbers, you should default to NumberAnimation.
PropertyAnimation should be a last resort (prefer the other types).

Related

Why my animations works in a strange way?

I have write a simple animation demo,but the animation work in a strange way.
The Code
import QtQuick 2.5
import QtQuick.Controls 2.12
ApplicationWindow {
visible: true
width: 480
height: 680
id: root
Rectangle {
id: rect
width: 200
height: 200
color: "blue"
anchors.centerIn: parent
states: State {
name: "A"
when: mouseArea.pressed
PropertyChanges {target: rect; color:"red"; }
PropertyChanges {target: rect; width: rect.width + 100}
PropertyChanges {target: rect; rotation: 720}
}
transitions: Transition {
ColorAnimation {duration: 1000}
NumberAnimation {duration: 1000}
RotationAnimation {duration: 1000}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
}
}
Q1: When mouse press and hold, I want the rectange width increase 100 every time,but my code seems not work?
Q2: If the width assign a const value(eg 100), the NumberAnimation seems not work, the width change immediately?
Q3:The RotationAnimation not rotate 720, it rotate exceed 720?
Currently, I am not familiar with js&qml, Hope Good Man(Woman) can help me.
Q1: You shouldn't bind rect.width to itself. That causes a binding loop. Either use a constant value or come up with some way outside of rect to keep track of what size you want the rect to be.
Q2: You need to tell the NumberAnimation which property to animate on. In this case it's "width".
Q3: 720 degrees means twice all the way around. That's exactly what I'm seeing when I test it, so I think it's working correctly.
The code below works for me.
Rectangle {
id: rect
width: 200
height: 200
color: "blue"
anchors.centerIn: parent
states: State {
name: "A"
when: mouseArea.pressed
PropertyChanges {target: rect; color:"red"; }
PropertyChanges {target: rect; width: 300} // Fixed value
PropertyChanges {target: rect; rotation: 720}
}
transitions: Transition {
ColorAnimation {duration: 1000}
NumberAnimation {property: "width"; duration: 1000} // Specify property
RotationAnimation {duration: 1000}
}
}
In addition to the answer from JarMan, I think you want to define a onPressed handler in the MouseArea, where you assign a new value to the width of the rect (note the difference between "binding" and "assigning"):
MouseArea {
id: mouseArea
anchors.fill: parent
onPressed: rect.width += 100
}
To clarify why that PropertyChange on width didn't work: as long as State "A" is active (thus during the mouse press), the PropertyChange overwrites the binding in the original Rectangle code, and you are defining it as a binding, meaning during the "A" state, the width is bound to itself (the binding loop that JarMan writes about). When state "A" is not active anymore, it will return to width: 300 (which is basically also a binding, albeit being constant).
When you use the above onPressed handler, the width property will loose it's binding and become fixed to the value assigned to it. Note: you can make it bound again by using Qt.binding or temporarily by using another PropertyChanges from a State

How to Blend overlapping SVG in QML

I have two SVG files that I am animating, one is a fixed figure that is centered in the screen, while the other is a second shape coming from the bottom of the screen and ending up overlapping a bit on the first shape:
Image {
id: progressIconFix
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
source: "../../images/Progress2-01.svg"
}
Image {
id: progressIcon
y: screenHeight
anchors.horizontalCenter: parent.horizontalCenter
source: "../../images/Progress1-01.svg"
states: State {
name: "visible";
when: progressIcon.visible;
PropertyChanges {
target: progressIcon;
y: progressIconFix.height + 180;
}
}
transitions: Transition {
from: "";
to: "visible";
reversible: true;
ParallelAnimation {
NumberAnimation {
properties: "y";
duration: 1050;
easing.type: Easing.InOutQuad;
}
}
}
}
I would like to make it so that when the second shape overlaps with the fixed one, the overlapped area (and only the overlap) between the two gets blended with a "multiply" effect. However, if I use:
Blend {
anchors.fill: progressIconFix
source: progressIconFix
foregroundSource: progressIcon
mode: "multiply"
}
The moving shape gets blended since the beginning in its entirety, but I would really like this effect to happen only when it overlaps the fixed shapes and only on the intersection area of the two.
Something like this should be happening:

Attribute parent dynamically to a QML component based in a condition

How to attribute a parent dynamically when the QML component is being created based in a condition?
Example:
//FirstFile.qml
SecondFile{
Rectangle {
id: bodyRect
}
}
//SecondFile.qml
Rectangle{
id: rectangleId
Flickable{
id: flickableId
}
}
In this example the parent of bodyRect is rectangleId.
How to attribute the flickableId as a parent of bodyRectif a condition is true ?
Well, it really depends on what you actually want to achieve, which is totally unclear from the question as it stands right now.
If you use dynamic object instantiation, you can simply pass the desired parent to the function:
someComponent.createObject(condition ? parent1 : parent2)
Additionally, you can change the visual parent of an object based on a condition:
property bool cond: false
property Rectangle rect: Rectangle {
Rectangle {
parent: cond ? redrect : bluerect
anchors.centerIn: parent
width: 50
height: 50
color: "blue"
}
}
MouseArea {
anchors.fill: parent
onClicked: cond = !cond
}
Row {
Rectangle {
id: redrect
width: 200
height: 200
color: "red"
}
Rectangle {
id: bluerect
width: 200
height: 200
color: "green"
}
}
The blue rectangle will be dynamically reparented to either the red or the green rectangle as cond changes.
Keep in mind that you cannot really do stuff across different files, unless the objects happen to represent actual instances that have visibility in the object tree.

Array of animations for `SequentialAnimation`

Is it possible to have an array of animations which allow a large number of animations to be run together?
Consider the following code:
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
id: mywindow
visible: true
Rectangle {
id: rect
width: 100; height: 100
color: "red"
SequentialAnimation {
running: true
NumberAnimation { target: rect; property: "x"; to: 150; duration: 1000 }
NumberAnimation { target: rect; property: "y"; to: 150; duration: 1000 }
NumberAnimation { target: rect; property: "x"; to: 250; duration: 1000 }
}
}
}
The above code runs three animations one after another. A rectangle moves right, down and then right again. However, is it possible to create a large array of such animations under SequentialAnimation, and then play them one after another? This will allow me to design more complex motions for that rectangle.
Could someone give an rewrite the example above where the three number animations above are lumped/zipped into an "arrayAnimation" (assuming there is such a thing)

Qt Quick move box with random movements

I'm trying to create a box that has some kind of Brownian motion (i.e. it keeps moving in random fashion) while the user can interact with it.
The interaction part works and is shortened below to resizing the height below.
The browian part doesn't work - I get two warnings at runtime:
[W] unknown:29 - file:.../EvasiveButton.qml:29:76: Unable to assign int to QEasingCurve
[W] unknown:29 - file:.../EvasiveButton.qml:29: ReferenceError: randomNumber is not defined
[W] unknown:24 - file:.../EvasiveButton.qml:24:54: Unable to assign int to QEasingCurve
So it appears i have at least the issue that my function randomNumber is not recognized. But moving it elsewhere doesn't seem to help.
Secondly, where do those warnings for ints to QEasingCurve come from?
The code:
import QtQuick 2.0
import QtQuick.Window 2.0
Rectangle {
width: Screen.width
height: Screen.height
color: "black"
focus: true
Rectangle {
x: 60
y: 60
width: 100
height: 100
color: "red"
MouseArea {
anchors.fill: parent
onClicked: parent.height += 50
}
Behavior on height {
NumberAnimation { duration: 200; easing: Easing.OutInQuint}
}
SequentialAnimation on x {
id: brownianMotionX
loops: Animation.Infinite
NumberAnimation {to: 40+randomNumber(); duration: 200; easing: Easing.OutInQuint}
}
function randomNumber() {
return Math.random() * 10 - 5;
}
}
}
Thanks for your suggestions!
randomNumber() is not available where you are calling it. Either move it up so it's declared before it's used, or give an id to your inner Rectangle to call it explicitly.
The easing errors are because you are trying to assign an easing curve style to a complete QEasingCurve - that's not going to work. So set the curve style specifically:
easing.type: Easing.OutInQuint

Resources