基本效果:上浮逐渐显示,短暂停留后上浮逐渐消失
为了能同时显示多个提示框,一是需要动态创建每个弹框 Item,二是弹出位置问题,如果是底部为基准位置就把已经弹出的往上移动。
效果展示:
主要实现代码:
(github链接:https://github.com/gongjianbo/MyTestCode/tree/master/Qml/TestQml_20240622_Toast)
(组件分ToastItem、ToastManager两个部分)
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
// 消息提示框
// 龚建波 2024-06-22
Window {
id: control
// width: context.implicitWidth + 40
// height: context.implicitHeight + 30
y: yShow - yOffset
flags: Qt.ToolTip
color: "transparent"
// 移动起始位置
property real yFrom: 0
// 移动暂留位置
property real yStay: 0
// 移动结束位置
property real yTo: 0
// 移动当前位置
property real yShow: 0
// 位置偏移
property real yOffset: 0
// 背景
Rectangle {
id: bg
anchors.fill: parent
radius: 4
color: "#99000000"
}
// 文字内容
Text {
id: context
anchors.centerIn: parent
color: "white"
}
Behavior on yOffset {
NumberAnimation {
duration: 200
}
}
SequentialAnimation {
id: sequential
ParallelAnimation {
NumberAnimation {
target: control
properties: "opacity"
from: 0.1
to: 1
duration: 200
}
NumberAnimation {
target: control
properties: "yShow"
from: control.yFrom
to: control.yStay
duration: 200
}
}
NumberAnimation {
target: control
properties: "opacity"
to: 1
duration: 2500
}
ParallelAnimation {
NumberAnimation {
target: control
properties: "opacity"
to: 0.1
duration: 200
}
NumberAnimation {
target: control
properties: "yShow"
to: control.yTo
duration: 200
}
}
onFinished: {
control.close()
}
}
// 弹出消息框
function pop(tipText, screenRect) {
context.text = tipText
control.width = context.implicitWidth + 40
control.height = context.implicitHeight + 20
control.x = screenRect.x + (screenRect.width - control.width) / 2
control.yStay = screenRect.y + (screenRect.height - control.height) / 4
control.yFrom = control.yStay + 80
control.yTo = control.yStay - 80
control.opacity = 0.1
control.yShow = control.yFrom
control.show()
sequential.start()
}
// 需要显示下一个消息,位置上移
property int nextCount: 0
function next() {
// 限制同时显示的个数,多余的关闭
if (nextCount >= 2) {
control.close()
return
}
nextCount++
// 消息框之间保留间隔
control.yOffset = nextCount * (control.height + 10)
}
}
import QtQuick 2.15
import Test 1.0
// 消息框管理
// 龚建波 2024-06-22
Item {
id: control
// 弹出新的消息时,信号通知已有的消息框上移
signal showNext()
property var toastArray: []
Component {
id: toast_comp
ToastItem {
id: toast_item
Connections {
target: control
function onShowNext() {
toast_item.next()
}
}
onClosing: {
toastArray.shift()
toast_item.destroy()
}
Component.onDestruction: {
console.log("onDestruction")
}
Component.onCompleted: {
console.log("onCompleted")
}
}
}
ScreenTool {
id: screen_tool
}
function showToast(msg) {
let rect = screen_tool.focusRect()
if (rect.width <= 0)
return
control.showNext()
let toast = toast_comp.createObject()
// 存起来避免被gc
toastArray.push(toast)
toast.pop(msg, rect)
}
}
#include "ScreenTool.h"
#include <QGuiApplication>
#include <QWindow>
QRect ScreenTool::focusRect()
{
QScreen *screen{nullptr};
auto &&window = qApp->focusWindow();
if (window) {
screen = window->screen();
} else {
screen = qApp->primaryScreen();
}
if (screen) {
return screen->availableGeometry();
}
return QRect();
}
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 640
height: 480
visible: true
title: qsTr("Qml Toast")
// 也可以注册为单例使用
ToastManager {
id: toast_manager
}
Row {
anchors.centerIn: parent
spacing: 10
TextField {
id: text_filed
text: "GongJianBo"
}
Button {
text: "Pop"
onClicked: {
toast_manager.showToast(text_filed.text)
}
}
}
}