Skip to content

Instantly share code, notes, and snippets.

@mitchcurtis
Created October 4, 2022 09:05
Show Gist options
  • Save mitchcurtis/4f7814ad472fb1a318502243ee3657b0 to your computer and use it in GitHub Desktop.
Save mitchcurtis/4f7814ad472fb1a318502243ee3657b0 to your computer and use it in GitHub Desktop.
FrameNumberAnimation
// FrameAnimation that operates on a property, like NumberAnimation,
// except the duration and easing can be change while it's animating.
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
ApplicationWindow {
id: window
width: 640
height: 480
visible: true
title: qsTr("progress %1 rotation %2").arg(frameAnimation.progress.toFixed(2)).arg(rect.rotation.toFixed(2))
ColumnLayout {
RowLayout {
Label {
text: "Speed"
}
Slider {
id: speedSlider
from: 0.1
value: 1
to: 2
stepSize: 0.1
}
Label {
text: speedSlider.value.toFixed(2)
}
Button {
text: "Restart"
onClicked: frameAnimation.restart()
}
}
ButtonGroup {
id: easingGroup
buttons: easingLayout.children
}
RowLayout {
id: easingLayout
RadioButton {
text: "Linear"
checked: true
function easingFunction(t) {
return t
}
}
RadioButton {
text: "InQuart"
function easingFunction(t) {
return t * t
}
}
RadioButton {
text: "EaseInQuart"
function easingFunction(t) {
t*=2.0;
if(t < 1) {
return 0.5*t*t*t;
} else {
t -= 2.0;
return 0.5*(t*t*t + 2);
}
}
}
}
Label {
text: "Duration: " + frameAnimation.duration.toFixed(2)
}
Label {
text: "Effective duration: " + frameAnimation.effectiveDurationInSeconds.toFixed(2)
}
Label {
text: "Distance each second: " + frameAnimation.progressEachSecond.toFixed(2)
}
}
Rectangle {
id: rect
x: (parent.width - width) / 2
y: (parent.height - height) / 2
width: 100
height: 100
color: "red"
Rectangle {
width: 4
height: 12
anchors.horizontalCenter: parent.horizontalCenter
}
}
component FrameNumberAnimation: FrameAnimation {
id: root
required property QtObject target
required property string property
property real duration
property var easingFunction
property real from: 0
property real to: 0
property real progressEachSecond: 1 / durationInSeconds
readonly property real durationInSeconds: duration / 1000
property real effectiveDurationInSeconds: 0
property real progress: 0
readonly property Binding binding: Binding {
target: root.target
property: root.property
value: from + to * root.easingFunction(root.progress)
}
signal finished
function finish() {
progress = 0
stop()
finished()
}
onRunningChanged: {
if (running) {
progress = 0
reset()
}
}
onTriggered: {
progress += progressEachSecond * frameTime;
if (progress >= 1.0)
finish()
}
}
Component.onCompleted: frameAnimation.start()
FrameNumberAnimation {
id: frameAnimation
duration: 4000 * (1 / speedSlider.value)
to: 360
target: rect
property: "rotation"
easingFunction: easingGroup.checkedButton.easingFunction
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment