[Qt6][QML][教程]QML创建带图片的物理弹跳-快速隐藏效果的弹窗

最近看到MAC上的网易云音乐播放音乐切换歌曲的时候会有一个弹窗,个人感觉这功能挺不错的,但是Windows却没有这个功能,所以就想着去实现一下,正好加一些功能,再和单片机做配合做成一整个体系算了。

教程被应用在MediaStateT中

MediaStateT Github项目地址: https://github.com/taxue-alfred/MediaStateT

MediaStateT Gitee项目地址: https://gitee.com/MediaState/MediaStateT

效果展示

窗口调用:

  • PopWindow使用Loader控件进行了模块化,非常好用,可以随便在Loader里面添加控件

需要注意的是,添加到Loader中的控件id不能被外部所访问,所以建议在外部先加载好控件然后传递到Loader

  • 直接在source_component添加Conponent控件即可

需要注意的是Component只能有一个控件,所以建议先创建一个大的Rectangle然后再在Rectangle里面创建其他控件,最后传递Component也就传递了Rectangle及其整个界面

  • 文章最后有调用示例,可以参考
代码参考

整体的代码不是很难,必要的注释都写在代码里了。需要注意的是:

  1. PopWindow.qmlWindow属性的x y 可以被外部调用的时候被覆盖.
  2. 窗口的大小根据Loader里面content_loader的内容大小改变
  3. sign这个变量只是一个标志,为了防止动画被多次执行。
//PopWindow.qml
import QtQuick
import QtQuick.Controls 2.5
import QtQuick.Window 2.3

Window{
    id: pop_window
    visible: false
    color: "transparent"
    // 透明度
    opacity: 0
    // 取消边框
    flags:Qt.FramelessWindowsHint | Qt.ToolTip
    // 设置为非模态
    modality: Qt.NonModal
    //设置初始位置(外部设置会覆盖此设置)
    x: Screen.width - content_loader.width
    y: 100
    //根据Loader设置大小
    width: content_loader.width
    height: content_loader.height

    MouseArea{
        id:content_mouse
        anchors.fill: parent
        hoverEnabled: true
    }

    // 设置出现后显示时间的计时器
    Timer{
        id:show_timer
        interval: 2500
        repeat: true
        onTriggered:{
            //这个if实现了鼠标悬停保留窗口的效果
            if(!loader_mouse.containsMouse){
                hideWindow();
            }
        }
    }

    //绘制图形的Loader,供外部使用
    property alias source_component:content_loader.sourceComponent
    Loader{
        id:content_loader
        MouseArea{
            id:loader_mouse
            anchors.fill:parent
            hoverEnabled:true
        }
    }

//---------------------------动画部分开始-------------------
    //设置出现显示动画
    property int x_offset: 0
    //设置sign标志,防止多次showWindow调用造成多次动画显示
    property int sign: 0
    ParallelAnimation{
        id: show_anim
        // 透明度动画
        PropertyAnimation{
            target:pop_window
            property: "opacity"
            easing.type: Easing.InQuart
            from:pop_window.opacity
            to: 1
            duration:350
        }
        //位置移动动画
        PropertyAnimation{
            target:pop_window
            property: "x"
            easing.type: Easing.OutBounce
            //从当前值开始移动
            from: Screen.width
            to: pop_window.x - content_loader.width - x_offset
            duration:800
        }
        onStarted:{
            pop_window.show()
        }
        //出现动画结束信号
        onFinished:{
            show_timer.start()
        }
    }
    //设置关闭显示动画
    ParallelAnimation{
        id: hide_anim
        // 透明度动画
        PropertyAnimation{
            target:pop_window
            property: "opacity"
            easing.type: Easing.OutCubic
            from:pop_window.opacity
            to: 0
            duration:800
        }
        //位置移动动画
        PropertyAnimation{
            target:pop_window
            property: "x"
            easing.type: Easing.InExpo
            //从当前值开始移动
            from: pop_window.x
            to: Screen.width
            duration:800
        }
        //结束动画结束之后隐藏窗口
        onFinished:{
            show_timer.stop();
            pop_window.hide();
        }
    }

    //显示弹窗
    function showWindow(){
        if(sign === 0){
            show_anim.start()
            sign = 1
        }
    }

    //隐藏弹窗
    function hideWindow(){
        if(sign === 1){
            show_anim.stop()
            hide_anim.start()
            sign = 0
        }
    }
//---------------------------动画部分结束-------------------
}

调用:

//main.qml
import QtQuick
import QtQuick.Controls 2.5
import QtQuick.Window 2.3
import Qt5Compat.GraphicalEffects

Item{
    Timer{
        interval:500
        repeat:false
        running:true
        onTriggered:{
            pop.showWindow();
        }
    }

    PopWindow{
        id:pop
        // 设置初始位置,对PopWindow里面的x,y进行了覆盖
        x: get_screen_pixel(1, Screen.width)
        y: get_screen_pixel(0.13, Screen.height)
        x_offset: get_screen_pixel(0.005, Screen.width)
        source_component:
            Component{
                id:test_component
                Rectangle{
                    id:bk_rectangle
                    width:200
                    height:70
                    radius:10
                    color: Qt.rgba(0.8,0.8,0.8,0.8)

                    Image {
                        id: img
                        width: 60
                        height: 60
                        anchors.verticalCenter: parent.verticalCenter
                        anchors.left: parent.left
                        anchors.leftMargin:6
                        source: "/album.jpg"
                        smooth: true
                        mipmap:true
                        visible: false
                        cache:false
                    }

                    Rectangle {
                        id: img_mask
                        width: img.width
                        height: img.height
                        radius: 10
                        color: "red"
                        visible: false
                    }

                    OpacityMask {
                        anchors.fill: img
                        source: img
                        maskSource: img_mask
                    }

                    Text{
                        id:music_name_label
                        width:110
                        anchors.verticalCenter: parent.verticalCenter
                        anchors.verticalCenterOffset: -16
                        anchors.left:img.right
                        anchors.leftMargin:10
                        font.pixelSize: 17
                        text:qsTr("Music Name")
                    }

                    Text{
                        id:player_name_label
                        width:110
                        anchors.verticalCenter: parent.verticalCenter
                        anchors.verticalCenterOffset: 16
                        anchors.left:img.right
                        anchors.leftMargin:10
                        font.pixelSize: 14
                        text:qsTr("Player")
                    }
                }
            }
        // 为了适应不同的屏幕,需要使用百分比表示
        function get_screen_pixel(percent, sum_pixel){
            return percent * sum_pixel
        }
    }
}

参考:

  1. QML实现桌面右下角弹窗
  2. PropertyAnimation QML Type
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值