I am trying to animate the margin value change with animation in QML, but i cant. The animation is not working
This is my state
State {
name: "up"
PropertyChanges {
target: drag_line
anchors.topMargin: 50
}
And in the transition i tried
transitions: [
Transition {
to: "up"
NumberAnimation { properties: "margin" ;easing.type: Easing.InOutQuad;duration: 300 }
}
]
I also tried the number animation but it also didn't work. Is there any way, am i doing something wrong
The property is not margin but anchors.topMargin
This is my working example:
ApplicationWindow {
visible: true
width: 500
height: 500
Rectangle {
width: 100
height: 100
anchors.centerIn: parent
color: "red"
Rectangle {
id: iRect
color: "blue"
width: 40
height: 40
anchors.top: parent.top
states: [State {
name: "up"
when: iMouseArea.pressed
PropertyChanges {
target: iRect
anchors.topMargin: 50
}
}]
transitions: [
Transition {
to: "up"
NumberAnimation { properties:"anchors.topMargin"; easing.type: Easing.InOutQuad;duration: 300 }
}
]
}
MouseArea{
id: iMouseArea
anchors.fill: parent
}
}
}
Related
I am trying to call a reset function once after the animation is completed. But in the below given code , the animation starts after resetting the values
On Long press of the button I need to start an animation which basically acts as a progress bar, and once the animation is completed I need to call the reset() function.
I have tried the below given code , But here the animation starts once after the resetting of values are done.
Button {
id: button1
onPressAndHold: {
rectangle.visible = true
timer.restart()
}
}
Item {
id: rectangle
Behavior on width {
NumberAnimation {
duration: 1000
easing.type: Easing.InOutCubic
}
}
Image {
id: img
source: "somesource"
fillMode: Image.PreserveAspectCrop
}
}
Timer {
id: timer
repeat: true
interval: 50
onTriggered: {
rectangle.width = img.sourceSize.width * img.progress
if (rectangle.width <= img.sourceSize.width) {
timer.stop()
reset(values)
}
}
}
can you please let me know on how modify it such that the animation completes first and then the reset is done. Thank you in advance!
Ok, that really works for standalone Animation only that sounds a bit strange for me since the common usecase is using animations inside Behavior or State.
So you can use NumberAnimation.onRunningChanged or ScriptAction as #iam_peter said or use Transition.onRunningChanged as well:
Window {
height: 200
width: 600
visible: true
title: qsTr("Animation test")
RowLayout {
width: parent.width
height: 100
anchors.centerIn: parent
Button {
text: "start"
onClicked: {
testRect.state = "state2"
}
}
Rectangle {
id: testContainer
Layout.fillWidth: true
Layout.fillHeight: true
Rectangle {
id: testRect
height: 100
width: 0
color: "orange"
states: [
State {
name: "state1"
PropertyChanges {
target: testRect
width: 0
}
},
State {
name: "state2"
PropertyChanges {
target: testRect
width: testContainer.width
}
}
]
transitions: Transition {
NumberAnimation {
property: "width"
duration: 2000
easing.type: Easing.InQuad
}
onRunningChanged: {
if(running == false)
{
finishRect.color = "red";
}
}
}
}
}
Rectangle {
id: finishRect
Layout.preferredWidth: 100
color: "yellow"
width: 100
height: width
radius: width / 2
}
}
}
According to this post you have two options.
You can us the onRunningChanged handler and check if the animation is still running. If not call anything you want at that point.
Rectangle {
id: rect
width: 100; height: 100
color: "red"
Behavior on width {
NumberAnimation {
duration: 1000
onRunningChanged: {
if (!running)
console.log("Animation finished")
}
}
}
MouseArea {
anchors.fill: parent
onClicked: rect.width = 50
}
}
The other option would be to create a SequentialAnimation and add a SrcriptAction that runs after the NumberAnimation is completed.
Rectangle {
id: rect
width: 100; height: 100
color: "red"
Behavior on width {
SequentialAnimation {
NumberAnimation { duration: 1000 }
ScriptAction {
script: console.log("Animation finished")
}
}
}
MouseArea {
anchors.fill: parent
onClicked: rect.width = 50
}
}
With Qt Quick, I created a custom button which looks like that:
This button also contains several states (default, hover, pressed), and the transition between each states is animated. I found a way to animate each properties easily with the Qt Quick engine, except for the image one. Indeed, I want to animate the image transition, by performing a crossfade between states.
However I couldn't found a such animator for images. The only way I found was to add 3 images to my button, one for each states, and to animate their respective opacity.
Below is the code for my buttons:
Button
{
property bool hoveredBtn: false
property bool pressedBtn: false
id: btAnimStateDemo
height: 40
anchors.right: parent.right
anchors.rightMargin: 5
anchors.left: parent.left
anchors.leftMargin: 5
anchors.top: parent.top
anchors.topMargin: 290
state: "DEFAULT"
// the button background
background: Rectangle
{
id: btAnimStateDemoBg
anchors.fill: parent
}
// the button text
Text
{
id: btAnimStateDemoText
text: qsTr("A button showing animated states (default, hovered, pressed)")
renderType: Text.NativeRendering
font.bold: true
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.fill: parent
}
Image
{
id: btAnimStateDemoDefaultImage
width: 30
height: 30
anchors.left: parent.left
anchors.leftMargin: 5
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
opacity: 1.0
source: "Resources/Palette.svg"
}
Image
{
id: btAnimStateDemoHoverImage
width: 30
height: 30
anchors.left: parent.left
anchors.leftMargin: 5
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
opacity: 0.0
source: "Resources/Smile.svg"
}
Image
{
id: btAnimStateDemoPressedImage
width: 30
height: 30
anchors.left: parent.left
anchors.leftMargin: 5
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
opacity: 0.0
source: "Resources/Woman.svg"
}
// the component state array
states:
[
State
{
name: "DEFAULT"
PropertyChanges { target: btAnimStateDemoBg; color: "green"}
PropertyChanges { target: btAnimStateDemoBg; radius: 4}
PropertyChanges { target: btAnimStateDemoDefaultImage; opacity: 1.0}
PropertyChanges { target: btAnimStateDemoHoverImage; opacity: 0.0}
PropertyChanges { target: btAnimStateDemoPressedImage; opacity: 0.0}
},
State
{
name: "HOVERED"
PropertyChanges { target: btAnimStateDemoBg; color: "red"}
PropertyChanges { target: btAnimStateDemoBg; radius: 10}
PropertyChanges { target: btAnimStateDemoDefaultImage; opacity: 0.0}
PropertyChanges { target: btAnimStateDemoHoverImage; opacity: 1.0}
PropertyChanges { target: btAnimStateDemoPressedImage; opacity: 0.0}
},
State
{
name: "PRESSED"
PropertyChanges { target: btAnimStateDemoBg; color: "blue"}
PropertyChanges { target: btAnimStateDemoBg; radius: 15}
PropertyChanges { target: btAnimStateDemoDefaultImage; opacity: 0.0}
PropertyChanges { target: btAnimStateDemoHoverImage; opacity: 0.0}
PropertyChanges { target: btAnimStateDemoPressedImage; opacity: 1.0}
}
]
// the matching transitions between states
transitions:
[
Transition
{
from: "*"; to: "DEFAULT"
ColorAnimation { property: "color"; easing.type: Easing.Linear; duration: 1000 }
NumberAnimation { properties: "radius, opacity"; easing.type: Easing.Linear; duration: 1000 }
},
Transition
{
from: "*"; to: "HOVERED"
ColorAnimation { property: "color"; easing.type: Easing.Linear; duration: 1000 }
NumberAnimation { properties: "radius, opacity"; easing.type: Easing.Linear; duration: 1000 }
},
Transition
{
from: "*"; to: "PRESSED"
ColorAnimation { property: "color"; easing.type: Easing.Linear; duration: 1000 }
NumberAnimation { properties: "radius, opacity"; easing.type: Easing.Linear; duration: 1000 }
}
]
// the mouse area which will apply the correct state in relation to the current mouse status
MouseArea
{
anchors.fill: parent
hoverEnabled: true
onEntered: {btAnimStateDemo.state = "HOVERED"; btAnimStateDemo.hoveredBtn = true;}
onExited: {btAnimStateDemo.state = btAnimStateDemo.pressedBtn ? "PRESSED" : "DEFAULT"; btAnimStateDemo.hoveredBtn = false;}
onPressed: {btAnimStateDemo.state = "PRESSED"; btAnimStateDemo.pressedBtn = true;}
onReleased: {btAnimStateDemo.state = btAnimStateDemo.hoveredBtn ? "HOVERED" : "DEFAULT"; btAnimStateDemo.pressedBtn = false;}
}
}
The above code works well, and reaches the purpose I planned, but is a little complicated from my point of view. It would be wonderful if an animator like NumberAnimation or ColorAnimation would exist for the images, but I found none.
So my question is: Is there a simpler way to animate an image transition between component states than my above proposed solution? Do Qt Quick propose an animator to reach a such purpose?
Create a SpriteSheet that assigns states to each of the three frames then set the interpolate property to true to have it transition between the images.
Sprite Animations with SpriteSequence
SpriteSequence demonstrates using a sprite sequence to draw an animated and interactive bear. The SpriteSequence object defines five different sprites. The bear is initially in a still state:
Sprite{
name: "still"
source: "content/BearSheet.png"
frameCount: 1
frameWidth: 256
frameHeight: 256
frameDuration: 100
to: {"still":1, "blink":0.1, "floating":0}
}
When the scene is clicked, an animation sets the sprite sequence to the falling states and animates the bear's y property.
SequentialAnimation {
id: anim
ScriptAction { script: image.goalSprite = "falling"; }
NumberAnimation { target: image; property: "y"; to: 480; duration: 12000; }
ScriptAction { script: {image.goalSprite = ""; image.jumpTo("still");} }
PropertyAction { target: image; property: "y"; value: 0 }
}
At the end of the animation the bear is set back to its initial state.
I am currently working on a Video/Stream Management program for my university. The body of my application is a GridView. I implemented a playbar for each video so I can use my playback functions specifically for each member of the GridView. The Problem now is FullScreen. I couldn't find a showFullScreen() function like the one from Window. Now I came across this question and tried the first solution (States/Transitions) and it works the way it is intended except that I would need it to be able to go out of the parents scope.
Code:
GridView {
id: mainGrid
width: parent.width - (parent.width % cellWidth)
height: parent.height
anchors.centerIn: parent
Layout.fillHeight: true
Layout.fillWidth: true
cellWidth: 300
cellHeight: 300
focus: true
property bool newPlayStatus: true
model: VideoModel {
list: videoList
}
delegate: Component {
id: videoDelegate
Frame {
id: videoContainer
width: mainGrid.cellWidth
height: mainGrid.cellHeight
background: Rectangle {
anchors.centerIn: parent
width: parent.width
height: parent.height
color: "black"
}
VideoDummy {
id: video
list: model.video
videoUrl: model.url
anchors.centerIn: parent
focus: true
playStatus: mainGrid.newPlayStatus
}
onChildrenChanged: {
console.log("url: " + model.url)
}
Playbar {
id: localPlaybar
x: -12
y: mainGrid.cellHeight - 42
width: mainGrid.cellWidth
height: 30
}
Connections{
target:localPlaybar
onToggleFullscreen: {
videoContainer.state = videoContainer.state === "EXPANDED" ? "" : "EXPANDED"
}
}
states: [
State {
name: "EXPANDED"
PropertyChanges {
target: videoContainer
x: application.x
}
PropertyChanges {
target: videoContainer
y: application.y
}
PropertyChanges {
target: videoContainer
width: application.width
}
PropertyChanges {
target: videoContainer
height: application.height
}
}
]
transitions: [
Transition {
ParallelAnimation {
NumberAnimation {
target: videoContainer
property: "x"
duration: 350
}
NumberAnimation {
target: videoContainer
property: "y"
duration: 350
}
NumberAnimation {
target: videoContainer
property: "width"
duration: 350
}
NumberAnimation {
target: videoContainer
property: "height"
duration: 350
}
}
}
]
}
}
}
I excluded some parts of my code because it would only made it harder to see the important parts. application is the id for the ApplicationWindow.
Currently this code isn't scaling everything to the size/position it needs to be but that is something I would do if the general idea would work.
The problem is that the videoContainer isn't able to go out of it's parents space. Is there any way to do it? I could open up a new Window with the needed qml parts and make it showFullScreen() but I do not believe that this is a nice solution is it?
Thanks in advance!
I found a solution:
onToggleFullscreen: {
var i = videoContainer.mapFromGlobal(0,0)
videoContainer.x = i.x
videoContainer.y = i.y
videoContainer.width = application.width
videoContainer.height = application.height
}
With this I can resize and position it outside of its parent.
I would like to make an animation when mouse comes over the image, but NOT when mouse leaves the image.
Item{
width: 800
height:800
Rectangle{
id: blueRec
width: 100; height: 100; color: "blue"
MouseArea{
anchors.fill: parent
onClicked: {
im1.visible = true
im1.source = "1.png"
}
}
}
Image {
id: im1
scale: im1MouseArea.containsMouse ? 0.8 : 1.0
Behavior on scale {
NumberAnimation{
id: anim
from: 0.95
to: 1
duration: 400
easing.type: Easing.OutBounce
}
}
MouseArea{
id: im1MouseArea
hoverEnabled: true
anchors.fill: parent
}
}
}
The code above makes also animation, when mouse is leaving image.
Can someone help?
Setting the scale and then triggering an animation that alters the scale seems like an odd approach. If I were you, I'd break this out into states and set the animation to trigger on the appropriate transition.
Here's an example of how this could be done:
Image {
id: im1
states: [ "mouseIn", "mouseOut" ]
state: "mouseOut"
transitions: [
Transition {
from: "*"
to: "mouseIn"
NumberAnimation {
target: im1
properties: "scale"
from: 0.95
to: 1
duration: 400
easing.type: Easing.OutBounce
}
}
]
MouseArea{
id: im1MouseArea
hoverEnabled: true
anchors.fill: parent
onContainsMouseChanged: {
im1.state = containsMouse ? "mouseIn" : "mouseOut"
}
}
}
I wonder how to make smooth transitions betwen image sources in QML, I try
import QtQuick 1.1
Image {
id: rect
source: "quit.png"
smooth: true
MouseArea {
id: mouseArea
anchors.fill: parent
anchors.margins: -10
hoverEnabled: true //this line will enable mouseArea.containsMouse
onClicked: Qt.quit()
}
states: State {
name: "mouse-over"; when: mouseArea.containsMouse
PropertyChanges { target: rect; scale: 0.8; source :"quit2.png" }
}
transitions: Transition {
NumberAnimation { properties: "scale, source"; easing.type: Easing.InOutQuad; duration: 1000 }
}
}
But It does not work on source as a transition just as final state change.. so I wonder how to make one image source fade into andothe and back?
You want the first image to fade out into the other? How about if you place two Image objects on top of each other, then animate the opacity property?
EDIT: This worked for me (I'm using QtQuick 1.0 because my Qt Creator installation is a bit outdated):
import QtQuick 1.0
Rectangle {
Image {
id: rect
source: "quit.png"
smooth: true
opacity: 1
MouseArea {
id: mouseArea
anchors.fill: parent
anchors.margins: -10
hoverEnabled: true //this line will enable mouseArea.containsMouse
onClicked: Qt.quit()
}
states: State {
name: "mouse-over"; when: mouseArea.containsMouse
PropertyChanges { target: rect; scale: 0.8; opacity: 0}
PropertyChanges { target: rect2; scale: 0.8; opacity: 1}
}
transitions: Transition {
NumberAnimation { properties: "scale, opacity"; easing.type: Easing.InOutQuad; duration: 1000 }
}
}
Image {
id: rect2
source: "quit2.png"
smooth: true
opacity: 0
anchors.fill: rect
}
}
To the question in your comment: you can place the image exactly on top of the other by copying the anchors thru anchors.fill: rect
Here is also a simple scroll transition between images:
import QtQuick 2.6
import QtQuick.Controls 1.4
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle {
id: imageRect
anchors.centerIn: parent
width: 240
height: 320
clip: true
property int currentIndex: 0
property var imageSources: [ "imageLeft.jpg", "imageCenter.jpg" ]
Repeater {
model: imageRect.imageSources
Image {
id: image
width: parent.width
height: parent.height
x: index * parent.width - imageRect.currentIndex * parent.width
fillMode: Image.PreserveAspectFit
source: imageRect.imageSources[index]
Behavior on x { SpringAnimation { spring: 2; damping: 0.2 } }
}
}
}
Button {
id: leftButton
anchors.bottom: parent.bottom
text: "left"
onClicked: if(imageRect.currentIndex > 0) imageRect.currentIndex--
}
Button {
id: rightButton
anchors.bottom: parent.bottom
anchors.left: leftButton.right
text: "right"
onClicked: if(imageRect.currentIndex < imageRect.imageSources.length - 1) imageRect.currentIndex++
}
Button {
id: addButton
anchors.bottom: parent.bottom
anchors.left: rightButton.right
text: "+"
onClicked: imageRect.imageSources = [ "imageLeft.jpg", "imageCenter.jpg" , "imageRight.jpg" ]
}
}