一、QML中的动画
1.1、动画类型
- 在QML中存在多种动画类型:
PropertyAnimation: 属性值改变播放动画--通用类型NumberAnimation:qreal-type值改变播放动画ColorAnimation:颜色值改变播放动画RotationAnimation:旋转值改变播放动画OpacityAnimation: 渐变透明
- 属性值改变播放的动画-PropertyAnimation
最通用的动画类型,可以动画任何属性。
javascript
import QtQuick
Image{
id: root
source: "qrc:/image/bgd.jpg"
anchors.fill: parent
property int padding: 40
property bool running: false
// 资源加载状态检查
onStatusChanged: {
if(status === Image.Error){
console.log("背景图片加载失败:", source)
}else if(status === Image.Ready){
console.log("背景图片加载成果...")
}
}
Image{
id:ss
source: "qrc:/image/cd2.jpg"
width: 50
height: 50
x:root.padding
y:(root.height - height) * 0.5
// 资源加载状态检查
onStatusChanged: {
if(status === Image.Error){
console.log("子图片加载失败:", source)
}else if(status === Image.Ready){
console.log("子图片...")
}
}
// 平移动画
PropertyAnimation on x{
to:root.width - ss.width
duration: 3000
running: root.running
}
// 旋转动画
RotationAnimation on rotation {
to:360
duration: 3000
running: root.running
}
// 颜色进行透明
PropertyAnimation on opacity {
to:0
duration: 3000
running: root.running
}
}
MouseArea{
anchors.fill: parent
onClicked: {
console.log("clicked...")
root.running = true
}
}
}
注意:
此处是将动画放在控件里面,所有默认作用的对象是该控件;如果想放在控件之外,那么需要显示声明,目标对象,比如:
javascript
Image{
id:ss
source: "qrc:/image/cd2.jpg"
width: 50
height: 50
}
PropertyAnimation on x{
target: ss //指明作用对象
to:root.width - ss.width
duration: 3000
running: root.running
}
//还可以这样写
PropertyAnimation{
target:ss
property:"x" //指明属性
to:root.width - ss.width
duration:3000
runing:root.running
}
- 专门处理数值属性 - NumberAnimation
其实就是属性动画的特化版本
javascript
NumberAnimation on x{
target: ss
to:root.width - ss.width
duration: 3000
running: root.running
}
// 其实等同于
PropertyAnimation on x{
target: ss //指明作用对象
to:root.width - ss.width
duration: 3000
running: root.running
}
- 专门处理颜色变化 - ColorAnimation
PropertyAnimation特化版
javascript
ColorAnimation {
target: colorRect
property: "color"
from: "red"
to: "blue"
duration: 2000
loops: Animation.Infinite
running: true
}
// 等同于
PropertyAnimation on color{
target: colorRect //指明作用对象
from: "red"
to: "blue"
duration: 2000
loops: Animation.Infinite
running: true
}
1.2、动画的触发方式
- 主要存在以下几种方式触发:
- 属性上的动画:在元素完全加载后自动运行
- 属性上的行为:属性值更改时自动运行
- 独立动画:使用
start()显示启动动画或将running设置为true时运行
- 属性上的动画:
在元素加载完成之后,立即自动运行,标志在于on
javascript
PropertyAnimation on color{
target: colorRect //指明作用对象
from: "red"
to: "blue"
duration: 2000
loops: Animation.Infinite
running: true
}
- 属性上的行为
当属性值发生变化时自动触发动画,标志在于behavior
javascript
// 行为动画:当x值改变时自动触发
Behavior on x {
NumberAnimation {
duration: 1000
}
}
- 独立动画
动画作为独立对象,需要通过代码进行显示启动- 调用
start() - 设置
running为true
- 调用
javascript
PropertyAnimation on color{
id: color_anim
target: colorRect //指明作用对象
from: "red"
to: "blue"
duration: 2000
//注意此处没有设置running为true,不会自动触发
}
Button {
text: "running = true"
onClicked: color_anim.running = true //手动控制
}
小结:
| 触发方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 属性上的动画 | 页面加载动画、循环动画、不需要用户交互的动画 | 简单直接,自动运行 | 无法手动控制时机 |
| 属性上的行为 | 用户交互反馈、状态切换、属性绑定变化 | 自动响应属性变化 | 可能会在不希望的时机触发 |
| 独立动画 | 复杂动画序列,需要精确控制的动画 | 完全控制,可组合复杂动画 | 需要更多代码,手动进行管理 |
1.3、动画分组
- 分组有两种方式:
- 并行:将两组及以上动画同时执行
- 顺序:先执行完一个动画后,再执行另一个动画
- 并行动画
关键词:ParallelAnimation
javascript
ParallelAnimation{
id:parallel_anim
running: true
// 水平移动
NumberAnimation{
target: object
property: "x" //注意此时没使用on
duration: 200
}
// 旋转动画
RotationAnimation{
target: object
property: "rotation"
from: 0
to: 360
duration: 2000
}
}
- 顺序动画
关键词SequentialAnimation
javascript
SequentialAnimation{
id:sequent_anim
running: true
// 先水平移动
NumberAnimation{
target: object
property: "x" //注意此时没使用on
duration: 200
}
// 再旋转动画
RotationAnimation{
target: object
property: "rotation"
from: 0
to: 360
duration: 2000
}
}
二、缓动曲线(Easing Curves)
2.1、什么是缓动曲线
描述了动画过程中属性值随时间变化的速率。它决定了动画是匀速运动、加速运动、减速运动还是有弹性的运动。
基本概念:
- 线性(Linear): 匀速运动
- 缓入(Easeln):开始慢,然后加速
- 缓出(EaseOut): 开始快,然后减速
- 缓入缓出(EaseInOut): 开始和结束都慢,中间快
2.2、缓动曲线类型
主要是通过easing.type属性来设置
javascript
Behavior on scale{
PropertyAnimation{
duration:200
easing.type:Easing.OutElastic
}
}
QML提供曲线类型:
| 类型 | 说明 |
|---|---|
Easing.Linear |
线性变化,无加速减速 |
Easing.InQuad |
开始慢,然后加速 |
Easing.OutQuad |
开始快,然后减速 |
Easing.InOutQuad |
开始结束都慢,中间加速 |
Easing.OutInQuad |
开始结束都快,中间慢 |
Easing.InCubic |
立方缓入,比Quad更明显的加速 |
Easing.OutCubic |
立方缓出 |
Easing.InOutCubic |
立方缓入缓出 |
Easing.InElastic |
弹性效果,在开始时有回弹 |
Easing.OutElastic |
弹性效果,在结束时有回弹 |
Easing.InBack |
开始时稍微后退再前进 |
Easing.OutBack |
结束时超过目标值再退回 |
Easing.InOutBack |
开始和结束都有超过再退回的效果 |
Easing.InBounce |
弹跳效果,开始有弹跳 |
Easing.OutBounce |
弹跳效果,结束时有弹跳 |
Easing.InOutBounce |
开始和结束都有弹跳 |
2.3、自定义贝塞尔曲线
如果需要更精确的控制,可以使用自定义贝塞尔曲线:
javascript
PropertyAnimation {
target: item
property: "x"
to: 300
duration: 1000
easing.type: Easing.Bezier
easing.bezierCurve: [0.68, -0.55, 0.265, 1.55] // 自定义贝塞尔控制点
}
注意:
缓动曲线虽然带线,但只强调运动轨迹,运动的速率,而不是真的画线---视觉上的线条
三、小测
场景:画一个油量表,类似进度条,超过20%时,显示绿色,低于20%时显示红色报警
javascript
import QtQuick
Item {
id: oil_
width:parent.width
height: parent.height
// 油量属性, 范围0-100
property real fuelLevel: 75
property color normalColor: "#00ff00"
property color warnningColor: "#ff0000"
property real warningValue: 20 // 警告阈值
property int autoChangeDirection: -1 //自动改变方向
Rectangle{
id:background
anchors.fill: parent
color:"#2d2d2d"
radius: 10
}
Column{
anchors.fill: parent
anchors.margins: 10
spacing: 5
Row{
width:parent.width
height: 20
Text{
text:"E"
color:"white"
font.pixelSize: 16
font.bold: true
}
Item{
width: parent.width - 40
height: 1
}
Text{
text:"F"
color: "white"
font.pixelSize: 16
font.bold: true
}
}
Rectangle{
width: parent.width
height: 25
radius: 15
// 进度条
Rectangle{
id:progressBar
width: (fuelLevel / 100) * parent.width
height: parent.height
radius: parent.radius
color:fuelLevel <= warningValue ? warnningColor : normalColor
// 渐变效果
gradient: Gradient{
GradientStop{
position: 0.0
color: Qt.lighter(progressBar.color, 1.2)
}
GradientStop{
position: 1.0
color: Qt.darker(progressBar.color, 1.2)
}
}
// 属性值动画
Behavior on width{
NumberAnimation{
duration: 500
easing.type: Easing.OutCubic
}
}
// 颜色动画
Behavior on color{
ColorAnimation {
duration: 300
}
}
}
// 油量显示
Text{
id:fuelText
anchors.horizontalCenter: parent.horizontalCenter
text:fuelLevel.toFixed(1) + "%"
color: fuelLevel <= warningValue ? warnningColor : normalColor
font.pixelSize: 16
font.bold: true
Behavior on color{
ColorAnimation {
duration: 300
}
}
}
}
}
Timer{
id: autoChangeTimer
interval: 200
running: true
repeat:true
onTriggered: {
//更新油量值
fuelLevel += autoChangeDirection * 0.5
if(fuelLevel >= 100){
fuelLevel = 100
autoChangeDirection = -1
}else if (fuelLevel <= 0){
fuelLevel = 0
autoChangeDirection = 1
}
}
}
}
