Array of animations for `SequentialAnimation` - qt

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)

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

PropertyAnimation vs. NumberAnimation

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).

Behavior on scale often is not working

I would like to have an application, where always when new image is loaded, it is appeared by scaling from 0 size to default size. This behavior is often not working. In this image I am also using animation for bouncing when mouse enters to image. Is it possible, that this two animations are not loving themselves and that is, why scaling up is often not working?
I am using Linux Mint 13, Qt 5.3
Here is my Image element:
Image {
id: pic1
width: appWindow.height*0.4
height: appWindow.height*0.4
smooth: { enabled = true
pic1MouseArea.containsMouse
}
states: [ "mouseIn", "mouseOut" ]
state: "mouseOut"
transitions: [
Transition {
from: "*"
to: "mouseIn"
NumberAnimation {
target: pic1
properties: "scale"
from: 0.95
to: 1
duration: 400
easing.type: Easing.OutBounce
}
}
]
scale: {
status === Image.Ready ? 1 : 0
}
Behavior on scale {
NumberAnimation{
from: 0
to: 1
duration: 1000
easing.type: Easing.OutBounce
}
}
MouseArea{
id: pic1MouseArea
hoverEnabled: true
anchors.fill: parent
onContainsMouseChanged: {
pic1.state = containsMouse ? "mouseIn" : "mouseOut"
}
onClicked: {
MyScript.getRandomFile()
}
}
}
First of all, read this doc. The states property must be defined as list<State>, not as an array of strings. Also, the State element defines some state when a property or set of properties changes from default configuration. In your example states define nothing. Read more about State type.
Finally, here is a small example to help you getting on:
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Window 2.2
Window {
width: 600
height: 400
visible: true
Image {
id: img
source: "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"
anchors.centerIn: parent
opacity: 1
state: "mouseOut"
states: [
State {
name: "mouseIn"
PropertyChanges { target: img; opacity: 0 }
},
State {
name: "mouseOut"
PropertyChanges { target: img; opacity: 1 }
}
]
transitions: Transition {
PropertyAnimation {
target: img
property: "opacity"
easing.type: Easing.InCirc
duration: 1000
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: img.state = "mouseIn"
onExited: img.state = "mouseOut"
}
}
}
Sure, you can replace transitions with Behavior, if you need exactly this functionality, as shown below:
Behavior on opacity {
PropertyAnimation {
duration: 1000
easing.type: Easing.InCirc
}
}

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

Playing a QML animation more than once without using States

I'm trying to get an QML animation to Start every time it's clicked, without using States. It Starts the first time it's clicked, but then won't Start when it's clicked a second time.
Is there a reason why? Here's the code I'm working it.
Image {
id: head;
source: "vlad.png";
height: 80;
width: 90;
MouseArea {
anchors.fill: parent
onClicked: animateHead.start();
ParallelAnimation {
id: animateHead;
NumberAnimation {
property int randomValueX: 0;
function randomize(randomValueX) {
randomValueX = (Math.floor(Math.random()*210));
return randomValueX;
}
target: head;
properties: "x";
to: randomize(randomValueX);
duration: 1000;
easing {
type: Easing.OutBack;
overshoot: 5
}
}
NumberAnimation {
property int randomValueY: 0;
function randomize(randomValueY) {
randomValueY = (Math.floor(Math.random()*210));
return randomValueY;
}
target: head;
properties: "y";
to: randomize(randomValueY);
duration: 700;
easing {
type: Easing.OutBack;
overshoot: 5
}
}
}
}
}
The problem is that the values of the to properties of the two NumberAnimation instances are bound only once during initialization of the QML component. They are not recalculated when you call animateHead.start() and animations are only executed if the value of the to property differs from the actual value of the animated property. That's why it works only the first time.
A working solution would be:
import QtQuick 1.0
Image {
id: head;
source: "vlad.png";
height: 80;
width: 90;
MouseArea {
anchors.fill: parent
onClicked: {
xAnimation.to = Math.floor(Math.random()*210)
yAnimation.to = Math.floor(Math.random()*210)
animateHead.start();
}
ParallelAnimation {
id: animateHead;
NumberAnimation {
id: xAnimation
target: head;
properties: "x";
duration: 1000;
easing {
type: Easing.OutBack;
overshoot: 5
}
}
NumberAnimation {
id: yAnimation
target: head;
properties: "y";
duration: 1000;
easing {
type: Easing.OutBack;
overshoot: 5
}
}
}
}
}
Here the values of the to properties are set explicitly in the onClicked handler of the MouseArea.
Just as a note, because I was trying to solve similar problem, googled this question and decided that there must be another way of dealing with animated property initialization. In Qt 5 you can use the PropertyAction to instantly initialize some properties.
Example from PropertyAction type documentation:
SequentialAnimation {
PropertyAction { target: img; property: "opacity"; value: .5 }
NumberAnimation { target: img; property: "width"; to: 300; duration: 1000 }
PropertyAction { target: img; property: "opacity"; value: 1 }
}
I don't know how would it interact with ParallelAnimation but it works very good with SequentialAnimation.

Resources