Last active
July 19, 2024 14:10
-
-
Save jonmcclung/bae669101d17b103e94790341301c129 to your computer and use it in GitHub Desktop.
Toast in QML. This implementation creates black toast with white text that appears at the bottom of the screen. It also supports adding multiple toast at a time using ToastManager with the newest toast at the bottom.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import QtQuick 2.0 | |
import QtQuick.Controls 2.0 | |
ApplicationWindow { | |
visible: true | |
height: 640 | |
width: 480 | |
id: root | |
ToastManager { | |
id: toast | |
} | |
Timer { | |
interval: 1000 | |
repeat: true | |
running: true | |
property int i: 0 | |
onTriggered: { | |
toast.show("This timer has triggered " + (++i) + " times!"); | |
} | |
} | |
Timer { | |
interval: 3000 | |
repeat: true | |
running: true | |
property int i: 0 | |
onTriggered: { | |
toast.show("This important message has been shown " + (++i) + " times.", 5000); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import QtQuick 2.0 | |
/** | |
* adapted from StackOverflow: | |
* http://stackoverflow.com/questions/26879266/make-toast-in-android-by-qml | |
*/ | |
/** | |
* @brief An Android-like timed message text in a box that self-destroys when finished if desired | |
*/ | |
Rectangle { | |
/** | |
* Public | |
*/ | |
/** | |
* @brief Shows this Toast | |
* | |
* @param {string} text Text to show | |
* @param {real} duration Duration to show in milliseconds, defaults to 3000 | |
*/ | |
function show(text, duration) { | |
message.text = text; | |
if (typeof duration !== "undefined") { // checks if parameter was passed | |
time = Math.max(duration, 2 * fadeTime); | |
} | |
else { | |
time = defaultTime; | |
} | |
animation.start(); | |
} | |
property bool selfDestroying: false // whether this Toast will self-destroy when it is finished | |
/** | |
* Private | |
*/ | |
id: root | |
readonly property real defaultTime: 3000 | |
property real time: defaultTime | |
readonly property real fadeTime: 300 | |
property real margin: 10 | |
anchors { | |
left: parent.left | |
right: parent.right | |
margins: margin | |
} | |
height: message.height + margin | |
radius: margin | |
opacity: 0 | |
color: "#222222" | |
Text { | |
id: message | |
color: "white" | |
wrapMode: Text.Wrap | |
horizontalAlignment: Text.AlignHCenter | |
anchors { | |
top: parent.top | |
left: parent.left | |
right: parent.right | |
margins: margin / 2 | |
} | |
} | |
SequentialAnimation on opacity { | |
id: animation | |
running: false | |
NumberAnimation { | |
to: .9 | |
duration: fadeTime | |
} | |
PauseAnimation { | |
duration: time - 2 * fadeTime | |
} | |
NumberAnimation { | |
to: 0 | |
duration: fadeTime | |
} | |
onRunningChanged: { | |
if (!running && selfDestroying) { | |
root.destroy(); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import QtQuick 2.0 | |
/** | |
* adapted from StackOverflow: | |
* http://stackoverflow.com/questions/26879266/make-toast-in-android-by-qml | |
* @brief Manager that creates Toasts dynamically | |
*/ | |
ListView { | |
/** | |
* Public | |
*/ | |
/** | |
* @brief Shows a Toast | |
* | |
* @param {string} text Text to show | |
* @param {real} duration Duration to show in milliseconds, defaults to 3000 | |
*/ | |
function show(text, duration) { | |
model.insert(0, {text: text, duration: duration}); | |
} | |
/** | |
* Private | |
*/ | |
id: root | |
z: Infinity | |
spacing: 5 | |
anchors.fill: parent | |
anchors.bottomMargin: 10 | |
verticalLayoutDirection: ListView.BottomToTop | |
interactive: false | |
displaced: Transition { | |
NumberAnimation { | |
properties: "y" | |
easing.type: Easing.InOutQuad | |
} | |
} | |
delegate: Toast { | |
Component.onCompleted: { | |
if (typeof duration === "undefined") { | |
show(text); | |
} | |
else { | |
show(text, duration); | |
} | |
} | |
} | |
model: ListModel {id: model} | |
} |
There are a few problems with this implementation. For a start, toasts are never deleted (model.count
never decreases). It is noticeable because if a newer toast expires before an older one, the older ones will not "slide" to fill the empty space.
In my cases, I found the selfDestroying
to be useless. I removed this line
-property bool selfDestroying: false
and changed
onRunningChanged: {
- if (!running && selfDestroying) {
- root.destroy();
+ if (!running) {
+ toastManager.model.remove(index);
}
}
since root.destroy();
gave errors and usually shouldn't be used this way. Finally, I also changed these lines:
anchors {
- left: parent.left
- right: parent.right
+ left: (parent != null) ? parent.left : undefined
+ right: (parent != null) ? parent.right : undefined
margins: margin
}
because they gave errors when a toast was being destroyed.
With these changes, older toasts will always fill the empty space left by a newer toast expiring.
It's in use in https://github.com/cagnulein/qdomyos-zwift as well! Thanks!
@gpollo
Thanks. Please can I get help with this Reference error below?
onRunningChanged: {
if (!running) {
toastManager.model.remove(index); // ReferenceError: toastManager is not defined
}
}
ReferenceError: toastManager is not defined
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This would be a great candidate to put up on https://cutes.io btw.