Generalizing Animation Setup in QML
-
I've been tinkering with animations in QML lately and wondering if there's a more streamlined way to set them up. Specifically, I find myself declaring PropertyAnimations for various elements individually, and it feels a bit repetitive.
For instance, let's say I'm setting up opacity animations for different elements (same animation, for various elements in different time). Currently, I'm creating separate PropertyAnimation blocks for each element:
PropertyAnimation { id: changeOpacity1 target: passwordRequirement1 property: "opacity" from: passwordRequirement1.opacity to: passwordRequirement1.opacity === 1 ? 0 : 1 duration: 500 } PropertyAnimation { id: changeOpacity2 target: passwordRequirement2 property: "opacity" from: passwordRequirement2.opacity to: passwordRequirement2.opacity === 1 ? 0 : 1 duration: 500 } PropertyAnimation { id: changeOpacity3 target: passwordRequirement3 property: "opacity" from: passwordRequirement3.opacity to: passwordRequirement3.opacity === 1 ? 0 : 1 duration: 500 }
However, I'm wondering if there's a more generalized approach. Maybe something like a function createAnimation where I could pass the target element and property as arguments? This way, I wouldn't have to repeat the animation setup logic for each element. Thank u!
-
@afalsa
Sorry i dont get it ;/PasswordRequirement { id: passwordRequirement1 anchors.left: usernameTextField.left anchors.top: dummyRec2.bottom text: "Password should be at least 8 characters long." opacity: 0 } PasswordRequirement { id: passwordRequirement2 anchors.left: usernameTextField.left anchors.top: passwordRequirement1.bottom text: "Password should contain at least one special character." opacity: 0 } PasswordRequirement { id: passwordRequirement3 anchors.left: usernameTextField.left anchors.top: passwordRequirement2.bottom text: "Password should contain at least one uppercase letter." opacity: 0 }
I have a custom Password Requirement component, so I suppose it serves as a base. What should I do next? Should I specify only one property animation and somehow change the target dynamically? Could you please provide an example? Also, what if an animation on a different target starts playing while the previous one hasn't stopped animating the property yet?
-
@Veltroniv How do you want your animations to be triggered?
I've shared some prewritten animations to be used as Behavior here : https://github.com/oKcerG/QuickBehaviors/
-
Hello!
I agree with @GrecKo , how do you want your animations to start? Do you only want one running at a time?
Here is an example of what I understood you needed:
You define your base component with everything you want it to share:
// BaseComponent.qml import QtQuick 2.15 import QtQuick.Controls 2.15 Rectangle { id: root implicitHeight: base.implicitHeight implicitWidth: base.implicitWidth color: "transparent" border.color: "red" opacity: 0 property alias text: base.text Label { id: base anchors.fill: parent color: "black" horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } Behavior on opacity { NumberAnimation { duration: 1000 } } }
You create your base component as many times as you want:
import QtQuick 2.15 import QtQuick.Controls 2.15 Item { width: 500 height: 500 Column { id: container anchors.fill: parent anchors.margins: 64 property int showComponent: -1 Button { anchors.left: parent.left anchors.right: parent.right height: 80 text: "Change item visible" onClicked: { container.showComponent++ if (container.showComponent === 3) { container.showComponent = 0 } } } BaseComponent { anchors.left: parent.left anchors.right: parent.right height: 80 text: "Password should be at least 8 characters long." opacity: container.showComponent === 0 ? 1 : 0 } BaseComponent { anchors.left: parent.left anchors.right: parent.right height: 80 text: "Password should contain at least one special character." opacity: container.showComponent === 1 ? 1 : 0 } BaseComponent { anchors.left: parent.left anchors.right: parent.right height: 80 text: "Password should contain at least one uppercase letter." opacity: container.showComponent === 2 ? 1 : 0 } } }
Or even if you want to avoid more duplicate code you can still use inline components:
import QtQuick 2.15 import QtQuick.Controls 2.15 Item { width: 500 height: 500 component BaseComponentInline: BaseComponent { anchors.left: parent.left anchors.right: parent.right height: 80 } Column { id: container anchors.fill: parent anchors.margins: 64 property int showComponent: -1 Button { anchors.left: parent.left anchors.right: parent.right height: 80 text: "Change item visible" onClicked: { container.showComponent++ if (container.showComponent === 3) { container.showComponent = 0 } } } BaseComponentInline { text: "Password should be at least 8 characters long." opacity: container.showComponent === 0 ? 1 : 0 } BaseComponentInline { text: "Password should contain at least one special character." opacity: container.showComponent === 1 ? 1 : 0 } BaseComponentInline { text: "Password should contain at least one uppercase letter." opacity: container.showComponent === 2 ? 1 : 0 } } }
-
@afalsa Thank u so much! it helps me a lot. Now im dealing with last thing.
states: [ State { name: "upConfirmPassword" AnchorChanges { target: confirmPasswordTextField anchors.top: dummyRec2.bottom } PropertyChanges { target: passwordRequirement1 opacity: 0 } PropertyChanges { target: passwordRequirement2 opacity: 0 } PropertyChanges { target: passwordRequirement3 opacity: 0 } PropertyChanges { target: passwordRequirement4 opacity: 0 } }, State { name: "downConfirmPassword" AnchorChanges { target: confirmPasswordTextField anchors.top: dummyRec3.bottom } PropertyChanges { target: passwordRequirement1 opacity: 1 } PropertyChanges { target: passwordRequirement2 opacity: 1 } PropertyChanges { target: passwordRequirement3 opacity: 1 } PropertyChanges { target: passwordRequirement4 opacity: 1 } }, State { name: "upEmailAddress" AnchorChanges { target: emailAddressTextField anchors.top: dummyRec4.bottom } PropertyChanges { target: passwordRequirement5 opacity: 0 } }, State { name: "downEmailAddress" AnchorChanges { target: emailAddressTextField anchors.top: dummyRec5.bottom } PropertyChanges { target: passwordRequirement5 opacity: 1 } } ]
is any option to set up targets: [] or make this solution more "cleaner" or it is what it is ? :D
-
Hello!
I dont get what you mean with "set up targets". I don't know of a better way to make that cleaner, the only thing I can think of is to group all the
PropertyChanges
into one. Coming back to my example:import QtQuick 2.15 import QtQuick.Controls 2.15 Item { id: root width: 500 height: 500 component BaseComponentInline: BaseComponent { anchors.left: parent.left anchors.right: parent.right height: 80 } Column { id: container anchors.fill: parent anchors.margins: 64 property int showComponent: -1 Button { anchors.left: parent.left anchors.right: parent.right height: 80 text: "Change item visible" onClicked: { if (root.state === "upConfirmPassword") { root.state = "downConfirmPassword" } else { root.state = "upConfirmPassword" } } } BaseComponentInline { id: passwordRequeriment1 text: "Password should be at least 8 characters long." } BaseComponentInline { id: passwordRequeriment2 text: "Password should contain at least one special character." } BaseComponentInline { id: passwordRequeriment3 text: "Password should contain at least one uppercase letter." } } state: "upConfirmPassword" states: [ State { name: "upConfirmPassword" PropertyChanges { passwordRequeriment1.opacity: 0 passwordRequeriment2.opacity: 0 passwordRequeriment3.opacity: 0 } }, State { name: "downConfirmPassword" PropertyChanges { passwordRequeriment1.opacity: 1 passwordRequeriment2.opacity: 1 passwordRequeriment3.opacity: 1 } } ] }
-