[Solved]Variable duration of animation



  • Hi,
    I'm just starting my journey with QML and already found something confusing. I want to have animation launched by clicking - it's easy, duration is 2s. Now I want to have possibility of reversing the animation (by clicking once again).

    It's quite simple to achieve, but it works a little bit different that I want it to.
    Code goes here:
    @
    import QtQuick 1.1

    Rectangle {
    width: 360
    height: 360

    property bool shown: true
    Rectangle {
    id: rect
    width: parent.width
    height: parent.height
    color: "red"

        /*Behavior on y {
                 NumberAnimation { duration: 2000 }
             }*/
    }
    
    states: [
    State {
            name: "show"
            when: shown == true
            PropertyChanges { target: rect; y: 0}
        },
    State {
            name: "hide"
            when: shown == false
            PropertyChanges { target: rect; y: rect.height }
        }
    
    ]
    transitions: [
        Transition {
            from: "*"
            to: "*"
            reversible: true
            PropertyAnimation {
                target: rect
                properties: "y"
                duration: 2000
            }
        }
    
    ]
    MouseArea {
        anchors.fill: parent
        onClicked: {
            shown = !shown
            print(shown)
        }
    }
    

    }

    @

    When I'm reversing the animation, duration is still 2s for this movement. As there is a less way to go, the animation is slower.
    "The solution" is to have dynamic duration based on Y.
    Duration is a property, y is a property, I cannot use Y in during calculation, because it does property binding(value of Y changes through time, any way of copying it?).
    Any idea how to deal with such problems?



  • Try putting this condition on duration (you can modify time to match desired, I just give as example 1000ms):
    duration: (shown ? 1000 : 2000)

    Also, small tip - you can put it this way:
    when: shown (instead: when: shown == true)

    and

    when: !shown (instead: when: shown == false)



  • Here is another idea:
    You could define PropertyChange on PropertyAnimation to change duration depending on state.
    Example:

    @import QtQuick 1.1

    Rectangle {

    width: 360
    
    height: 360
    

    property bool shown: true

    Rectangle {
    
        id: rect
    
        width: parent.width
    
        height: parent.height
    
        color: "red"
    
    
    
        /*Behavior on y {
    
                 NumberAnimation { duration: 2000 }
    
             }*/
    
    }
    
    
    
    states: [
    
    State {
    
            name: "show"
    
            when: shown == true
    
            PropertyChanges { target: rect; y: 0}
    
            PropertyChanges { target: animation; duration: 2000}
    
        },
    
    State {
    
            name: "hide"
    
            when: shown == false
    
            PropertyChanges { target: rect; y: rect.height }
    
            PropertyChanges { target: animation; duration: 1000}
    
        }
    
    
    
    ]
    
    transitions: [
    
        Transition {
    
            from: "*"
    
            to: "*"
    
            reversible: true
    
            PropertyAnimation {
    
                id: animation
    
                target: rect
    
                properties: "y"
    
                duration: 2000
    
            }
    
        }
    
    
    
    ]
    
    MouseArea {
    
        anchors.fill: parent
    
        onClicked: {
    
            shown = !shown
    
            print(shown)
    
        }
    
    }
    

    }@



  • You misunderstood me. Maybe I wrote it unclearly.

    duration: (shown ? 1000 : 2000) does not solve anything.
    The issue is that when you click once (animation starts now), and you click once again. Then the movement is short, but the duration is still 2000s. No matter how long the distance is.
    Please run and check how it works..

    Simply, I want to have constant speed no matter how many pixels are left to finish the animation.


  • Moderators

    [quote author="riddle" date="1355145150"]Simply, I want to have constant speed no matter how many pixels are left to finish the animation.
    [/quote]

    Use physics, then. time = distance/velocity. In your case, y should point to the current value when you invoke it in duration. Or you can temporarily stop the animation, get y and then use it to calculate duration.



  • bq. Use physics

    Sure, but I have problem with using property y in binding calulcations. I get binding loop.



  • I agree with sierdzio, you must use Y then.
    No need for bounding.
    You can do it on this way:

    1. when you click on button, grab current position (A) and position where it should go (B)
    2. subtract those two and take absolute value (abs(A-B))
      And you are ready to go.


  • Maths says
    When going from show to hide:
    @duration: (rect.height-rect.y)/rect.height2000@
    and when going from hide to show:
    @duration: rect.y/rect.height
    2000@

    But it doesn't work... we have QML PropertyAnimation: Binding loop detected for property "duration".
    What's going on?



  • Well, problem is that you are using binding.
    Don't use it!
    As I said above, when you click on button (rectangle) set formula (calculate, not bind).

    Like this:
    @
    MouseArea {
    anchors.fill: parent

        onClicked: {
            shown = !shown
            print(shown)
            animation.duration = (shown ? rect.y/rect.height*2000 : (rect.height-rect.y)/rect.height*2000)
        }
    }
    

    @



  • So there is no declarative way to do so?
    Maybe it's a good idea to add constVelocity boolean property to animations. It could ensure that when transition is reversible, no matter when you reverse the animation, it will play with constant speed.

    Oh, and one more thing. Could someone explain me why it does not work with properties (duration: (rect.height-rect.y)/rect.height*2000) ?



  • In declarative way, it is not possible, only via JavaScript.

    Duration cannot be bound to Y since it is one which changes Y.
    Code that you posted should work like this:

    1. animation started and changes Y
    2. animation duration depends on Y so it updates
    3. animation instance either resets or creates another one which changes Y (and from here you can see the loop)

    In other words:
    -change Y (animate)
    -Y is changed, update duration (bound to Y)
    -duration is changed, change Y (animate)
    -Y is changed, update duration
    -duration is changed, change Y
    -Y is changed, update duration
    -duration is changed, change Y
    -Y is changed, update duration
    ...



  • Thank you for explanation.



  • Anytime :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.