如何在qml中创建粘滞按钮?

时间:2015-07-07 22:27:46

标签: qt qml qtquick2

我想创建一个可以被用户拖动的按钮,当释放时将返回到其原始位置。

在移动过程中,必须按照一些缓动曲线为按钮设置动画。

到目前为止我所拥有的是:

import QtQuick 2.2
import QtGraphicalEffects 1.0

Item {
    property bool wasDragged: false
    property real basePosX: (menuButton.width / 2) - (menuButtonIcon.width / 2) //menuButton.horizontalCenter
    property real basePosY: (menuButton.height / 2) - (menuButtonIcon.height / 2) //menuButton.verticalCenter

    id: menuButton
    x: parent.width - 55
    y: parent.height - 60
    state: "Closed"

    Rectangle {
        id: menuButtonIcon
        x: basePosX
        y: basePosY
        color: "#D23F31"
        width: 65;
        height: 65;
        radius: width * 0.5
        antialiasing: true
        smooth: true
    }

    Rectangle {
        id: menuButtonIconBar1
        anchors.centerIn: menuButtonIcon
        width: 17
        height: 3
        antialiasing: true
    }

    Rectangle {
        id: menuButtonIconBar2
        anchors.centerIn: menuButtonIcon
        width: 17
        height: 3
        antialiasing: true
        rotation: 90
    }

    MouseArea {
        id: mouseArea
        anchors.fill: menuButtonIcon
        onPressed: menuButton.state = menuButton.state === "Open" ? "Closed" : "Open"
        onReleased: {
            if (wasDragged) {
                wasDragged = false
                menuButton.state = "Closed"
            }
        }

        onPositionChanged:
        {
            wasDragged = true
            var currentPosition = mapToItem(parent, mouse.x, mouse.y)
            updateButtonPosition(currentPosition.x, currentPosition.y)
        }
    }

    function updateButtonPosition(mouseX, mouseY)
    {
        console.log("pos change")
        menuButtonIcon.x = mouseX - (menuButtonIcon.width / 2);
        menuButtonIcon.y = mouseY - (menuButtonIcon.height / 2);
    }

    states: [
        State {
            name: "Closed"
            PropertyChanges { target: menuButtonIcon; x: basePosX; y: basePosY}
        },
        State {
            name: "Open"
            PropertyChanges { target: menuButtonIconBar1; rotation: 135;}
            PropertyChanges { target: menuButtonIconBar2; rotation: 225;}
            PropertyChanges { target: menuButtonIcon; x: basePosX; y: basePosY}
        }
    ]

    transitions: [
        Transition {
            SpringAnimation { target: menuButtonIcon; properties: "x, y"; spring: 3; damping: 0.25; epsilon: 0.2; mass: 1; modulus: 0; velocity: 0 }
            SpringAnimation { target: menuButtonIconBar1; properties: "rotation, scale"; spring: 3; damping: 0.25; epsilon: 0.5; mass: 1; modulus: 0; velocity: 0 }
            SpringAnimation { target: menuButtonIconBar2; properties: "rotation, scale"; spring: 3; damping: 0.25; epsilon: 0.5; mass: 1; modulus: 0; velocity: 0 }
        }
    ]
}

但问题是,如果你在旋转动画结束前拖动并保持静止,按钮将返回其原始位置,即使你从未发布它。

如果删除构成十字架的两个Rectangle以及它们的动画,那么它就可以正常工作。

为什么按钮会自动返回原始位置,如何修复?

1 个答案:

答案 0 :(得分:1)

试试这个:

import QtQuick 2.0
import QtGraphicalEffects 1.0

Item {
    property bool wasDragged: false
    property real basePosX: (menuButton.width / 2) - (menuButtonIcon.width / 2)
    property real basePosY: (menuButton.height / 2) - (menuButtonIcon.height / 2)
    property real currentPosX: (menuButton.width / 2) - (menuButtonIcon.width / 2)
    property real currentPosY: (menuButton.height / 2) - (menuButtonIcon.height / 2)

    id: menuButton
    x: parent.width - 55
    y: parent.height - 60
    state: "Closed"

    Rectangle {
        id: menuButtonIcon
        x: basePosX
        y: basePosY
        color: "#D23F31"
        width: 65;
        height: 65;
        radius: width * 0.5
        antialiasing: true
        smooth: true
    }

    Rectangle {
        id: menuButtonIconBar1
        anchors.centerIn: menuButtonIcon
        width: 17
        height: 3
        antialiasing: true
    }

    Rectangle {
        id: menuButtonIconBar2
        anchors.centerIn: menuButtonIcon
        width: 17
        height: 3
        antialiasing: true
        rotation: 90
    }

    MouseArea {
        id: mouseArea
        anchors.fill: menuButtonIcon
        onPressed: menuButton.state = menuButton.state === "Open" ? "Closed" : "Open"
        onReleased: {
            if (wasDragged) {
                wasDragged = false
                menuButton.state = "Closed"
            }
        }

        onPositionChanged:
        {
            wasDragged = true
            var currentPosition = mapToItem(parent, mouse.x, mouse.y)
            updateButtonPosition(currentPosition.x, currentPosition.y)
        }
    }

    function updateButtonPosition(mouseX, mouseY)
    {
        console.log("pos change")
        menuButtonIcon.x = mouseX - (menuButtonIcon.width / 2);
        menuButtonIcon.y = mouseY - (menuButtonIcon.height / 2);
        currentPosX = mouseX - (menuButtonIcon.width / 2);
        currentPosY = mouseY - (menuButtonIcon.height / 2);
    }

    states: [
        State {
            name: "Closed"
            PropertyChanges { target: menuButtonIcon; x: currentPosX; y: currentPosY}
        },
        State {
            name: "Open"
            PropertyChanges { target: menuButtonIconBar1; rotation: 135;}
            PropertyChanges { target: menuButtonIconBar2; rotation: 225;}
            PropertyChanges { target: menuButtonIcon; x: currentPosX; y: currentPosY}
        }
    ]

    onStateChanged: if(state === "Closed"){
                        currentPosX = basePosX
                        currentPosY = basePosY
                    }

    transitions: [
        Transition {
            SpringAnimation {
                target: menuButtonIcon;
                properties: "x, y";
                spring: 3;
                damping: 0.25;
                epsilon: 0.2;
                mass: 1;
                modulus: 0;
                velocity: 0
            }
            SpringAnimation {
                id:tr1;
                target: menuButtonIconBar1;
                properties: "rotation, scale";
                spring: 3;
                damping: 0.25;
                epsilon: 0.5;
                mass: 1;
                modulus: 0;
                velocity: 0
            }
            SpringAnimation {
                id:tr2;
                target: menuButtonIconBar2;
                properties: "rotation, scale";
                spring: 3;
                damping: 0.25;
                epsilon: 0.5;
                mass: 1;
                modulus: 0;
                velocity: 0
            }
        }
    ]
}

在打开的状态下你应该在当前位置做一个x和y的propertyChanges,基础位置的绑定导致x和y的重置。你需要其他属性来获取当前的x和当前的y。 随着90%的问题得到解决,你会看到一个小的decalage大约1秒,按钮将返回到好的位置。 解决它我把属性更改置于关闭状态,x和y更改为currentPosition并在其中添加一个StateChanged插槽我重置位置。 我不知道这种奇怪行为的根本原因。但随着这种解决方法,它的工作正常。 问候