如何在 qml 中创建一个粘性按钮?
How can I create a sticky button in qml?
我想创建一个可以被用户拖动的按钮,当释放时将 return 回到原来的位置。
在移动过程中,按钮必须按照一些缓和曲线进行动画处理。
我目前的情况是这样的:
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 }
}
]
}
但这样做的问题是,如果您在旋转动画结束前拖动它并保持不动,即使您从未松开它,该按钮也会 return 到其原始位置。
如果删除构成十字的两个 Rectangle
以及它们的动画,则它会按预期工作。
为什么按钮 return 会自行回到原来的位置,如何修复?
试试这个:
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
}
}
]
}
在 open 状态下你应该做一个 属性当前位置的 x 和 y 的变化,绑定在基础位置导致 x 和 y 的重置。您将需要采用当前 x 和当前 y 的其他属性。
解决了 90% 的问题后,您会看到一个小的 decalage 大约 1 秒,按钮将 return 移到合适的位置。
为了解决它,我将 属性 更改为关闭状态,x 和 y 更改为 currentPosition 并在其中添加了一个 StateChanged 插槽,我重置了位置。
我不知道这种奇怪行为的根本原因。但有了这个解决方法,它工作正常。
问候
我想创建一个可以被用户拖动的按钮,当释放时将 return 回到原来的位置。
在移动过程中,按钮必须按照一些缓和曲线进行动画处理。
我目前的情况是这样的:
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 }
}
]
}
但这样做的问题是,如果您在旋转动画结束前拖动它并保持不动,即使您从未松开它,该按钮也会 return 到其原始位置。
如果删除构成十字的两个 Rectangle
以及它们的动画,则它会按预期工作。
为什么按钮 return 会自行回到原来的位置,如何修复?
试试这个:
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
}
}
]
}
在 open 状态下你应该做一个 属性当前位置的 x 和 y 的变化,绑定在基础位置导致 x 和 y 的重置。您将需要采用当前 x 和当前 y 的其他属性。 解决了 90% 的问题后,您会看到一个小的 decalage 大约 1 秒,按钮将 return 移到合适的位置。 为了解决它,我将 属性 更改为关闭状态,x 和 y 更改为 currentPosition 并在其中添加了一个 StateChanged 插槽,我重置了位置。 我不知道这种奇怪行为的根本原因。但有了这个解决方法,它工作正常。 问候