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