关于 QML 动画的 transitions 属性使用的注意事项

transitions 需要搭配 states 属性使用, 因为在 states 的状态发生改变时, transitions 才会触发.

测试图:

在这里插入图片描述

测试代码:

// === view.qml ===
import QtQuick 2.14

Rectangle {
    // 令一个矩形在被点击时, 颜色从白色变为黑色.
    id: _rect
    width: 500; height: 500

    property bool p_active: false

    states: [
        State {
            when: !p_active
            PropertyChanges {
                target: _rect
                color: "white"
            }
        },
        State {
            when: p_active
            PropertyChanges {
                target: _rect
                color: "black"
            }
        }
    ]

    transitions: [
        Transition {
            ColorAnimation {
                duration: 1000
            }
        }
    ]

    MouseArea {
        id: _area
        anchors.fill: parent
        onClicked: {
            // console.log(p_active)
            p_active = !p_active
        }
    }
}

# === main.py ===
# https://doc.qt.io/qtforpython/tutorials/basictutorial/qml.html
from PySide2.QtWidgets import QApplication
from PySide2.QtQuick import QQuickView
from PySide2.QtCore import QUrl

app = QApplication()
view = QQuickView()
url = QUrl("./view.qml")

view.setSource(url)
view.show()
app.exec_()

本文章主要说一下使用 transitions 属性时的注意事项, 有很多小坑需要避开:

import QtQuick 2.14

Rectangle {
    // 令一个矩形在被点击时, 颜色从白色变为黑色.
    id: _rect
    width: 500; height: 500

    property bool p_active: false

    states: [
        State {
            when: !p_active  // (1) 当 when 属性为 true 时, 该状态被激发.
            PropertyChanges {
                target: _rect  // (2) 不要忘了 target 属性.
                color: "white"
            }
        },  // (3) 主要这里的逗号不能少.
        State {
            when: p_active  // (4) 我们设这两个状态的 when 正好相反.
            PropertyChanges {
                target: _rect
                color: "black"
            }
        }  // (5) 这里不要有逗号, 不然 QML 会报语法错误.
    ]

    transitions: [  // (6) 在 transitions 属性中, 如果我们写多个 Transition, 那
    // 么很遗憾告诉你, 它们并不会按照列表顺序逐个执行, QML 只会选择其中最合适的
    // 一个 (一般来说是最后一个 Transition) 来执行.
        Transition {
            ColorAnimation {
                duration: 1000
            }
        }
    ]

    MouseArea {
        id: _area
        anchors.fill: parent
        onClicked: {
            // console.log(p_active)
            p_active = !p_active
        }
    }
}

扩展阅读: 如何实现 “渐隐渐入” 的效果?

根据上述第 6 条注意事项, 我们知道如果要实现渐隐渐入, 下面的做法是不行的:

import QtQuick 2.14

Rectangle {
    // 实现渐隐渐入效果: 前 500ms 由白转黑, 后 500ms 由黑转白.
    ...
    
    transitions: [
        // 这样写是行不通的, _trans1 会完全失效, QML 只会执行 _trans2. 也就是说
        // 会有这样的效果: 矩形突然变黑, 然后花 500ms 变为白色, 后 500ms 无变化.
        Transition {
            id: _trans1
            ColorAnimation {
                properties: "color"
                duration: 1000 / 2
                from: "white"; to: "black"
            }
        },
        Transition {
            id: _trans2
            ColorAnimation {
                properties: "color"
                duration: 1000 / 2
                from: "black"; to: "white"
            }
        }
    ]
}

正确的解决思路有两种: 一种是设置两个相同的矩形, 一个负责渐隐, 一个负责渐入. 后者的 State 的 when 属性设为 when: _rect1.color == "black".

另一种思路是使用序列动画 – SequentialAnimation. 这里我展示一下序列动画的实现:

// === view.qml ===
import QtQuick 2.14

Rectangle {
    // 实现渐隐渐入效果: 前 500ms 由白转黑, 后 500ms 由黑转白.
    id: _rect
    width: 500; height: 500

    property bool p_active: false

    states: [
        State {
            when: !p_active
            PropertyChanges {
                target: _rect
                color: "white"
            }
        },
        State {
            when: p_active
            PropertyChanges {
                target: _rect
                color: "white"  // 这里改了一下, 因为两个状态的最终颜色要求都是 
                // white.
            }
        }
    ]

    transitions: [
        Transition {
            SequentialAnimation {
                ColorAnimation {
                    // 因为 states 已经指明了 target 和 color, 所以这里可以略过
                    // target 和 properties 属性.
                    // target: _rect
                    // properties: "color"
                    duration: 1000 / 2
                    from: "white"; to: "black"
                }
                ColorAnimation {
                    // target: _rect
                    // properties: "color"
                    duration: 1000 / 2
                    from: "black"; to: "white"
                }
            }
        }
    ]

    MouseArea {
        id: _area
        anchors.fill: parent
        onClicked: {
            // console.log(p_active)
            p_active = !p_active
        }
    }
}

效果图:

在这里插入图片描述

(PS: 这个效果有个小问题, 在布局初始化完成时, 会自动触发一次渐隐渐入动画. 笔者暂时没弄清楚为什么会触发.)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值