Playing a QML animation more than once without using States - qt

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.

Related

Stackview replace qml after button animation is completed

i am building an interface with QtQuick2 by using qmls. I also created a few buttons on home page and i am trying to change qmls by using loader after some animation is played. I have a stackview like this:
StackView {
id: stackViewTool
anchors {
left: parent.left
right: parent.right
top: parent.top
bottom: bottomBar.top
}
initialItem: initializePage
}
and i also added "initializePage" variable as property
property string initializePage : "HomePage.qml"
here is how i use my button to change qml on some other pages.
SimpleButton {
id:homeClicked
Image{
id: homeID
source:"/images/barHome.png"
}
onClicked: {
stackViewTool.replace(initializePage)
}
}
I want to add a animation to get the "pushing button" feeling. I want to change the button image first, and then i want to replace the qml. Here is the sequental animation i want to use. I want to have the animation like pushed and released, then change the qml.
SequentialAnimation {
id : homePressed
PropertyAnimation {
targets: [homeID]
property: "source"
to: "/images/pressedHome.png"
}
PauseAnimation {
duration: 100
}
PropertyAnimation {
targets: [homeID]
property: "source"
to: "/images/barHome.png"
}
PauseAnimation {
duration: 100
}
}
I tried to use "stackViewTool.replace(initializePage)" after the sequential animation but it did not work. I tried to add "Component.onCompleted: stackViewTool.replace(initializePage)" after 100ms pause snippet(last step of animation) but it did not work. What can i do for create something like i wanted? Answers are appreciated.
You can use the onFinished | onStarted signal handlers.
You can use ScriptAction at the end of the animation:
SequentialAnimation
{
id: homePressed
PropertyAnimation {
targets: [homeID]
property: "source"
to: "/images/pressedHome.png"
}
PauseAnimation {
duration: 100
}
PropertyAnimation {
targets: [homeID]
property: "source"
to: "/images/barHome.png"
}
PauseAnimation {
duration: 100
}
ScriptAction{
script: function(){stackViewTool.replace(initializePage)}
}
}

Switching between original condition and SequentialAnimation

Not sure how to express my question. My snippet code is just to illustrate what I want to achieve in a much bigger code base. I have an "originalCondition" that changes the opacity of an image which is independent of the SequentialAnimation. What I want to achieve after the SequentialAnimation has completed changing the opacity for the Image that the "originalCondition" binds back to the opacity. Not sure if bind is the appropriate way to describe it
For some reason, this does not occur and I am not sure why or how to do it.
Item {
id: root
property bool activatedLetter: false
Button {
text: "Click me"
onClicked: root.activatedLetter = true
}
Image {
id: headerBackgroundImage
visible: true
opacity: originalCondition
}
SequentialAnimation {
running: root.activatedLetter
onStopped: {
if(root.activatedLetter) {
headerBackgroundImage.visible = true
}
headerBackgroundImage.opacity = 1
root.activatedLetter = false
}
PauseAnimation {
duration: 750
}
NumberAnimation {
target: headerBackgroundImage
property: "opacity"
from: 1
to: 0
duration: 1000
}
NumberAnimation {
target: headerBackgroundImage
property: "visible"
from: 1
to:0
duration: 1000
}
}
}
In your onStopped, instead of this:
headerBackgroundImage.opacity = 1
try this:
headerBackgroundImage.opacity = Qt.binding(() => originalCondition);

QML: How to move an object from a previous set postion using states

I have an object that I want to move from it's previously set position every time that particular state is set. I've tried making a separate property called xPos to get around the binding loop error which is set by the object's new position of x after the state is set, then entering a default state just to be able to switch back to that specific state again since calling the same state does nothing but it doesn't seem to work.
Here is a snippet of my code:
property int xPos: 0
states: [
State {
name: "nextStep"
PropertyChanges {
target: progressBar_Id
x: -1*(progressBar_Id.step.width) + xPos
}
},
State {
name: "previousStep"
PropertyChanges {
target: progressBar_Id
x: progressBar_Id.step.width + xPos
}
},
State {
name: "default"
PropertyChanges {
target: progressBar_Id
x: xPos
}
}
]
transitions: [
Transition {
from: "*"
to: "nextStep"
NumberAnimation {properties: "x"; easing.type: Easing.Linear; duration: 1000}
onRunningChanged: {
if(!running) {
xPos = progressBar_Id.x;
console.info("xPos = " + xPos);
state = "default";
}
}
},
Transition {
from: "*"
to: "previousStep"
NumberAnimation {properties: "x"; easing.type: Easing.Linear; duration: 1000}
onRunningChanged: {
if(!running) {
xPos = progressBar_Id.x;
console.info("xPos = " + xPos);
state = "default";
}
}
}
]
xPos seems to get set the first time from the console output but never applies the new xCoord to the object.
Explicitly specify the id of the item on which you wish to set the state, e.g:
idOfComponent.state = "default"
All QML Items and derivatives have a property called state, so the code needs to be more specific.
Actually came up with a much better alternative using a ListView.
ListView {
id: listView_Id
width: contentWidth
height: bubbleSize
anchors.centerIn: parent
layoutDirection: Qt.RightToLeft
orientation: ListView.Horizontal
spacing: 0
delegate: Item {
width: bubbleSize
height: width
ProgressBubble {
stateText: stateNumber
currentState: state
}
}
model: ListModel { id: progressModel_Id }
}
Another qml file:
progressModel.insert(0, {stateNumber: number++, state: "current"});
But I ran into another problem, is there anyway to change a state within a delegate after it's been added to the ListView?
I've already tried progressModel.set and progressModel.setProperty but doesn't seem to work.
state is a property for qml types, so when you are assigning "state" to "currentState" for "ProgressBubble", its taking the value of state in which " ProgressBubble" is currently present.
Rename "state" to something else like "presentState" and then try.
Moreover id of ListView model(progressModel_Id) and the one used to insert model elements(progressModel) in different file are different, both of them must refer to same id.
After these changes, you can try set property of model. Sample code snippet:
import QtQuick 2.0
Rectangle {
id: root
width: 360
height: 360
property int number: 1
ListView {
id: listView_Id
width: 100 //contentWidth // this creates property binding issue
height: 100 // bubbleSize // I was not sure about this value
anchors.centerIn: parent
layoutDirection: Qt.RightToLeft
orientation: ListView.Horizontal
spacing: 0
delegate: Item {
width: 100 // bubbleSize // I was not sure about this value
height: width
ProgressBubble {
state: "default"
stateText: stateNumber
currentState: presentState
MouseArea {
anchors.fill: parent
onClicked: {
progressModel_Id.set(index,{stateNumber: stateNumber, presentState: "not current"})
}
}
}
}
model: ListModel { id: progressModel_Id }
}
Component.onCompleted:
{
progressModel_Id.insert(0, {stateNumber: number++, presentState: "current"});
}
}

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

does qtquick have a function such as wait()?

Is there something like a wait() function for qtquick? I have as mousearea that calls an animation and a different state. When you click the mousearea they are both fired at the same time I need the state change to fire after the animation is completed.
MouseArea {
id: movie_mouse_mm
x: 392
y: 364
width: 104
height: 100
onClicked:{
image6.state = "rotated"
page.state = 'State1'
Logic.get_db(5,0);
}
}
So I need to get
page.state ='state'
to run after
image6.state= "rotated"
You have to use transitions & animations like that:
Item {
//...
MouseArea {
//...
onClicked:{
parent.state = "rotate"
//...
}
}
transitions: [
Transition {
to: "rotate"
SequentialAnimation {
RotationAnimation { target: image6; duration: 1000; direction: RotationAnimation.Clockwise }
PropertyAction { target: page; property: "state"; value: "state" }
}
}
]
}
You can adjust duration
More information here.

Resources