I'm trying to make a three-way-toggle in qml where the red rectangle animates/slides to the clicked position. The toggle contains only images and no text:
MyToggle.qml
Rectangle {
color: "gray"
width: 400
height: 50
Row {
id: rowId
MyRadioButton {
id: button1
onClicked: {
console.log("clicked on button1")
animationId.restart()
}
}
MyRadioButton {
id: button2
onClicked: {
console.log("clicked on button2")
}
}
MyRadioButton {
id: button3
onClicked: {
console.log("clicked on button3")
}
}
}
}
PropertyAnimation {
id: animationId
target: button3
property: "x"
duration: 1000
to: 0
easing.type: Easing.InOutQuad
}
}
MyRadioButton.qml
RadioButton {
id: button1
width: 90
height: 100
Image {
source: "qrc:/image.png"
sourceSize.width: 50
sourceSize.height: 50
anchors.horizontalCenter: parent.horizontalCenter
}
indicator: Rectangle {
width: 100
height: 50
color: "red"
opacity: 0.8
visible: button1.checked
}
}
The PropertyAnimation is wrong because it moves the whole button and not just the indicator. If I move the animation into MyRadioButton, I won't know how far to move "x". Does anybody have some ideas how to implement this?
You can have your indicator Rectangle floating with a Behavior
defined on x
.
Thanks, @Greko for the improved indicator target
binding. I tried both but elected to go with ButtonGroup
as it seemed more qml.
import QtQuick
import QtQuick.Controls
Page {
Frame {
background: Rectangle { color: "gray" }
padding: 0
Row {
id: rowId
MyRadioButton {
id: button1
onClicked: {
console.log("clicked on button1")
animationId.restart()
}
}
MyRadioButton {
id: button2
onClicked: {
console.log("clicked on button2")
}
}
MyRadioButton {
id: button3
onClicked: {
console.log("clicked on button3")
}
}
}
}
ButtonGroup {
id: buttonGroup
buttons: rowId.children
}
Rectangle {
id: indicator
property Item target: buttonGroup.checkedButton
x: target ? target.x : 0
y: target ? target.y : 0
width: target ? target.width : 0
height: target ? target.height : 0
color: "red"
opacity: 0.5
Behavior on x { NumberAnimation { duration: 300 }}
}
}
// MyRadioButton.qml
import QtQuick
import QtQuick.Controls
RadioButton {
id: button1
width: 90
height: 50
Image {
source: "cross.svg"
sourceSize.width: 50
sourceSize.height: 50
anchors.horizontalCenter: parent.horizontalCenter
}
indicator: Item { }
}
// cross.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path stroke="black" stroke-width="2" fill="none" d="M 8 8 24 24"/>
<path stroke="black" stroke-width="2" fill="none" d="M 8 24 24 8"/>
</svg>
You can Try it Online!
The following edit describes how to limit the NumberAnimation to only when an onClick occurs:
import QtQuick
import QtQuick.Controls
Page {
Frame {
background: Rectangle { color: "gray" }
padding: 0
Row {
id: rowId
MyRadioButton {
id: button1
onClicked: NumberAnimation {
target: indicator
property: "x"
to: button1.x
}
}
MyRadioButton {
id: button2
onClicked: NumberAnimation {
target: indicator
property: "x"
to: button2.x
}
}
MyRadioButton {
id: button3
onClicked: NumberAnimation {
target: indicator
property: "x"
to: button3.x
}
}
}
}
ButtonGroup {
id: buttonGroup
buttons: rowId.children
}
Rectangle {
id: indicator
property Item target: buttonGroup.checkedButton
x: 0
y: target ? target.y : 0
width: target ? target.width : 0
height: target ? target.height : 0
color: "red"
opacity: target ? 0.5 : 0
}
}
// MyRadioButton.qml
import QtQuick
import QtQuick.Controls
RadioButton {
id: button1
width: 90
height: 50
Image {
source: "cross.svg"
sourceSize.width: 50
sourceSize.height: 50
anchors.horizontalCenter: parent.horizontalCenter
}
indicator: Item { }
}
// cross.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path stroke="black" stroke-width="2" fill="none" d="M 8 8 24 24"/>
<path stroke="black" stroke-width="2" fill="none" d="M 8 24 24 8"/>
</svg>