Complex group animation in QtQuick 2.0

2019-09-19 08:18发布

问题:

Im trying to animate the top level "cont" rectangle to the right, downscale it, and move it over the right a little bit and the back to left on left swipe. At the same time it will down scale the back rectangle also, It will set the scale size to that of the screen and will place the rectangle flush to the right of the screen.

Would anyone be ale to give me some pointers on how I need to do it?

Check pictures for reference to what I'm trying to achieve

And I forgot to mention how would I apply easing to the animation as well?


(source: paisei.com)


(source: paisei.com)

import QtQuick 2.0
import QtQuick.Controls 1.1

Item {
    id: root

    // default size, but scalable by user
    height: 450
    width: 300

    signal clickInit();

    MouseArea{

        anchors.fill: parent
        signal swipeRight;
        signal swipeLeft;
        signal swipeUp;
        signal swipeDown;

        property int startX;
        property int startY;

        onPressed: {
            startX = mouse.x;
            startY = mouse.y;
        }

        onReleased: {
            var deltax = mouse.x - startX;
            var deltay = mouse.y - startY;

            if (Math.abs(deltax) > 50 || Math.abs(deltay) > 50) {
                if (deltax > 30 && Math.abs(deltay) < 30) {
                    // swipe right
                    console.log("swiped right");
                    downSizeToRight.start()
                    swipeRight();
                } else if (deltax < -30 && Math.abs(deltay) < 30) {
                    console.log("swiped left")
                    // swipe left
                    upSizeFromRight.start()
                    swipeLeft()
                } else if (Math.abs(deltax) < 30 && deltay > 30) {
                    console.log("swiped down")
                    // swipe down
                    swipeDown()
                } else if (Math.abs(deltax) < 30 && deltay < 30) {
                    console.log("swiped up")
                    // swipe up
                    swipeUp()
                }
            }
        }

        Rectangle{
            id: bg
            gradient: Gradient {
                    GradientStop { position: 0.0; color: "#000000" }
                    GradientStop { position: 1.0; color: "#fff" }
                }
            height : cont.height + 80
            width : cont.width + 80
            y:cont.y - 40
            x: cont.x - 80

        }

        Rectangle{
            id: cont
            width:parent.width
            height:parent.height
            transform: Scale {
                        id: scaleTransform
                        property real scale: 1
                        xScale: scale
                        yScale: scale
                    }

            SequentialAnimation {
                id: downSizeToRight
                loops: 1
                PropertyAnimation {
                    target: scaleTransform
                    properties: "scale"
                    from: 1.0
                    to: 0.5
                    duration: 300
                }
            }

            SequentialAnimation {
                id: upSizeFromRight
                loops: 1
                PropertyAnimation {
                    target: scaleTransform
                    properties: "scale"
                    from: 0.5
                    to: 1.0
                    duration: 300
                }
            }

            Label {
                id: label1
                y: 226
                text: qsTr("Hi this is just a load of text that i cant write in that makes no sence for testing")
                horizontalAlignment: Text.AlignHCenter
                wrapMode: Text.WordWrap
                anchors.right: parent.right
                anchors.rightMargin: 5
                anchors.left: parent.left
                anchors.leftMargin: 5
            }
        }


    }
}

回答1:

For the people who would be interested in doing something like this, this was my solution but I still have one error which I'm still currently trying to find a fix which is on the scale front back to the left animation the right back rectangle flies back over to the left covering the left back rectangle. Its a little hard to describe but if you compile and swipe left and right you'll see the error.

And also I'm a total beginner at qt quick so if you feel there is a better way to do anything in this code then any changes would be appreciated.

Thank you

import QtQuick 2.0

MouseArea {
    id:screen
    width: 320
    height: 460

    property int startX;property int startY
    signal swipeRight;signal swipeLeft;signal swipeUp;signal swipeDown

    property int size_addition:100
    property bool swiped: false
    property int swiped_direction:1
    property int aniSpeed: 200;

    states: [
        State {
            name: "frontToRight"
            PropertyChanges {target: front;x:(screen.width - (screen.width/3) + (screen.width/24) - 25)}
            PropertyChanges {target: front;scale:0.5}
            PropertyChanges {target: right;x:screen.width}
            PropertyChanges {target: left;scale:1}
        },
        State {
            name: "frontToLeft"
            PropertyChanges {target: front;x:-(screen.width - (screen.width/3) + (screen.width/24) - 25)}
            PropertyChanges {target: front;scale:0.5}
            PropertyChanges {target: right;scale:1}
        }
    ]

    onPressed: {startX=mouse.x;startY=mouse.y;}
    onReleased: {
        var swipe_a = 115; var deltax = mouse.x - startX; var deltay = mouse.y - startY
        if (Math.abs(deltax) > 100 || Math.abs(deltay) > 100) {
            if (deltax > swipe_a && Math.abs(deltay) < swipe_a) {swipeRight()}
            else if (deltax < -swipe_a && Math.abs(deltay) < swipe_a){swipeLeft()}
            else if (Math.abs(deltax) < swipe_a && deltay > swipe_a) {swipeDown()}
            else if (Math.abs(deltax) < swipe_a && deltay < swipe_a) {swipeUp()}
        }
    }

    onSwipeRight: {
        //scale to right
        if(front.height == screen.height && swiped_direction!=0 && swiped_direction!=2)
        {screen.state = "frontToRight";swiped = true;swiped_direction = 0;}
        //back to center from left
        else if(swiped && swiped_direction!=0)
        {screen.state = "";swiped = false;swiped_direction = 1;}
    }

    onSwipeLeft: {
        //scale to left // here is where my swipe problem lies 
        if(front.height == screen.height && swiped_direction!=2 && swiped_direction!=0)
        {screen.state = "frontToLeft";swiped = true;swiped_direction = 2;}
        //back to center from right
        else if(swiped && swiped_direction!=2)
        {screen.state = "";screen.swiped = false;screen.swiped_direction = 1;}
    }

    Rectangle{
        id:left
        color:"#0500ff"
        height:screen.height
        width:screen.width
        transformOrigin: Item.Right
        scale:1.2
        Behavior on scale{NumberAnimation{duration:aniSpeed}}
        Text{
            text:"Left"
            anchors.fill: parent
            font.pixelSize: 70
        }
    }

    Rectangle{
        id:right
        color:"#028000"
        height:screen.height
        width:screen.width
        transformOrigin: Item.Left
        Behavior on scale{NumberAnimation{duration:aniSpeed}}
        scale:1.2
        Text{
            text:"Right"
            anchors.fill: parent
            font.pixelSize: 70
        }
    }

    Rectangle{
        id:front
        color:"red"
        height:screen.height
        width:screen.width
        Behavior on scale{ NumberAnimation{duration:aniSpeed;}}
        Behavior on x{NumberAnimation{duration:aniSpeed}}
        Text{
            text:"Front"
            anchors.fill: parent
            font.pixelSize: 70
        }
    }
}


回答2:

OK guys. I've got it working but it complains to me saying Imperative code is not supported in the Qt Quick Designer.

import QtQuick 2.0
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
MouseArea {
    id:screen
    width: 320
    height: 460

    property int startX;property int startY
    signal swipeRight;signal swipeLeft;signal swipeUp;signal swipeDown

    property int size_addition:100
    property bool swiped: false
    property int swiped_direction:1
    property int aniSpeed: 200;

    states: [
        State {
            name: "frontToRight"
            PropertyChanges {target: front;x:(screen.width - (screen.width/3) + (screen.width/24) - 25)}
            PropertyChanges {target: front;scale:0.5}
            //PropertyChanges {target: right;x:screen.width}
            PropertyChanges {target: left;scale:1}
        },
        State {
            name: "frontToLeft"
            PropertyChanges {target: front;x:-(screen.width - (screen.width/3) + (screen.width/24) - 25)}
            PropertyChanges {target: front;scale:0.5}
            PropertyChanges {target: right;scale:1}
        }
    ]

    onPressed: {startX=mouse.x;startY=mouse.y;}
    onReleased: {
        var swipe_a = 115; var deltax = mouse.x - startX; var deltay = mouse.y - startY
        if (Math.abs(deltax) > 100 || Math.abs(deltay) > 100) {
            if (deltax > swipe_a && Math.abs(deltay) < swipe_a) {swipeRight()}
            else if (deltax < -swipe_a && Math.abs(deltay) < swipe_a){swipeLeft()}
            else if (Math.abs(deltax) < swipe_a && deltay > swipe_a) {swipeDown()}
            else if (Math.abs(deltax) < swipe_a && deltay < swipe_a) {swipeUp()}
        }
    }

I fixed it here by setting the z property of the left panel. Is there a better way of doing this? and also I've tried putting some easing on it to make the animation look a little better, but nothing seems to look very good. does anyone have and suggestions?

    onSwipeRight: {
        //scale to right
        if(front.height == screen.height && swiped_direction!=0 && swiped_direction!=2)
        {screen.state = "frontToRight";swiped = true;swiped_direction = 0;left.z=2}
        //back to center from left
        else if(swiped && swiped_direction!=0)
        {screen.state = "";swiped = false;swiped_direction = 1;}
    }

    onSwipeLeft: {
        //scale to left // here is where the righ tbg menu swipe problem lies
        if(front.height == screen.height && swiped_direction!=2 && swiped_direction!=0)
        {screen.state = "frontToLeft";swiped = true;swiped_direction = 2;left.z=0}
        //back to center from right
        else if(swiped && swiped_direction!=2)
        {screen.state = "";screen.swiped = false;screen.swiped_direction = 1;}
    }

    Rectangle{
        id:left
        color:"#0500ff"
        height:screen.height
        width:screen.width
        z:0
        transformOrigin: Item.Right
        scale:1.2
        Behavior on scale{NumberAnimation{duration:aniSpeed}}
        Text{
            text:"Left"
            anchors.fill: parent
            font.pixelSize: 70
        }
    }

    Rectangle{
        id:right
        z:1
        color:"#028000"
        height:screen.height
        width:screen.width
        transformOrigin: Item.Left
        Behavior on scale{NumberAnimation{duration:aniSpeed}}
        scale:1.2
        Text{
            text:"Right"
            anchors.fill: parent
            font.pixelSize: 70
        }
    }

    Rectangle{
        id:front
        color:"red"
        height:screen.height
        width:screen.width
        z:2
        Behavior on scale{ NumberAnimation{duration:aniSpeed;}}
        Behavior on x{NumberAnimation{duration:aniSpeed}}
        Text{
            text:"Front"
            anchors.fill: parent
            font.pixelSize: 70
        }
    }
}


回答3:

I fixed some other issues that I was having with this app. So I restarted it and this is the new version with no errors and works very nicely.

import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 1.0

GestureArea {
    id:main
    width: 470
    height: 700
    property int swiped_direction:1
    property bool swiped:false
    property int aniSpeed: 90

    onSwipeRight: {doRightSwipeProcess()}
    onSwipeLeft: {doLeftSwipeProcess()}

    states: [
        State {
            name: "toLeft"
            PropertyChanges {target: front;x:(main.width - (main.width/3) + (main.width/24) - 25)}
            PropertyChanges {target: front;scale:0.5}
            PropertyChanges {target: left;scale:1}
        },
        State {
            name: "toRight"
            PropertyChanges {target: front;x:-(main.width - (main.width/3) + (main.width/24) - 25)}
            PropertyChanges {target: front;scale:0.5}
            PropertyChanges {target: right;scale:1}
        }
    ]

    Rectangle{
        id:front
        width:main.width
        height:main.height
        property int direction:1
        color:"#fff"
        Behavior on scale{NumberAnimation{duration:aniSpeed;}}
        Behavior on x{NumberAnimation{duration:aniSpeed}}
        z:2
    }

    Image{
        id:left
        source:"images/app_bg_left.png"
        Behavior on scale{NumberAnimation{duration: main.aniSpeed}}
        width:main.width
        height:main.height
        transformOrigin: Item.Right
        scale:1.3
        anchors.right:{if(scale<1.3){return main.right}else{return main.left}}
        z:0
    }

    Settings{
        id:right
        //source:"images/app_bg_right.png"
        Behavior on scale{NumberAnimation{duration: main.aniSpeed}}
        width:main.width
        height:main.height
        transformOrigin: Item.Left
        scale:1.3
        anchors.left:{if(scale<1.3){return main.left}else{return main.right}}
        z:1
        onDoLeftSwipe: doLeftSwipeProcess()
        onDoRightSwipe: doRightSwipeProcess()
    }


    function doRightSwipeProcess(){
        //scale to right
        if(front.height == main.height && swiped_direction!=0 && swiped_direction!=2)
        {main.state = "toLeft";swiped = true;swiped_direction = 0;front.direction = 0}
        //back to center from left
        else if(swiped && swiped_direction!=0)
        {main.state = "";swiped = false;swiped_direction = 1;front.direction = 1;}
    }

    function doLeftSwipeProcess(){
        //scale to left // here is where the righ tbg menu swipe problem lies
        if(front.height == main.height && swiped_direction!=2 && swiped_direction!=0)
        {main.state = "toRight";swiped = true;swiped_direction = 2;front.direction = 2}
        //back to center from right
        else if(swiped && swiped_direction!=2)
        {main.state = "";main.swiped = false;main.swiped_direction = 1;front.direction = 1}
    }
}