惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

雷峰网
雷峰网
宝玉的分享
宝玉的分享
I
InfoQ
P
Privacy International News Feed
V
V2EX
IT之家
IT之家
S
SegmentFault 最新的问题
D
Darknet – Hacking Tools, Hacker News & Cyber Security
V2EX - 技术
V2EX - 技术
C
CERT Recently Published Vulnerability Notes
C
Check Point Blog
The Register - Security
The Register - Security
爱范儿
爱范儿
博客园 - 三生石上(FineUI控件)
AWS News Blog
AWS News Blog
M
MIT News - Artificial intelligence
C
Cyber Attacks, Cyber Crime and Cyber Security
F
Fortinet All Blogs
B
Blog
N
Netflix TechBlog - Medium
B
Blog RSS Feed
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Last Week in AI
Last Week in AI
T
Threatpost
Forbes - Security
Forbes - Security
U
Unit 42
A
Arctic Wolf
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
P
Palo Alto Networks Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Recorded Future
Recorded Future
L
Lohrmann on Cybersecurity
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Proofpoint News Feed
月光博客
月光博客
Spread Privacy
Spread Privacy
MongoDB | Blog
MongoDB | Blog
Jina AI
Jina AI
I
Intezer
V
Visual Studio Blog
阮一峰的网络日志
阮一峰的网络日志
The Hacker News
The Hacker News
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
L
LangChain Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园_首页
MyScale Blog
MyScale Blog
腾讯CDC
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
量子位

涛哥的博客

玩转QtQuick(2)-默认渲染器 | 涛哥的博客 玩转QtQuick(2)-默认渲染器 | 涛哥的博客 玩转QtQuick(1)-SceneGraph场景图简介 | 涛哥的博客 玩转QtQuick(1)-SceneGraph场景图简介 | 涛哥的博客 QQuickWidget中文输入法问题的正确解法 | 涛哥的博客 玩转Qml(18)-用户向导 | 涛哥的博客 玩转Qml(18)-用户向导 | 涛哥的博客 玩转Qml(17)-树组件的定制 | 涛哥的博客 玩转Qml(17)-树组件的定制 | 涛哥的博客 玩转Qt(15)-操控Web小车案例 | 涛哥的博客 玩转Qt(15)-操控Web小车案例 | 涛哥的博客 玩转Qt(14)-Qt与Web混合开发 | 涛哥的博客 玩转Qt(14)-Qt与Web混合开发 | 涛哥的博客 玩转Qt(13)-安卓5.12.4环境搭建 | 涛哥的博客 玩转Qt(13)-安卓5.12.4环境搭建 | 涛哥的博客 玩转Qt(12)-github-Actions缓存优化 | 涛哥的博客 玩转Qt(12)-github-Actions缓存优化 | 涛哥的博客 玩转Qt(11)-github-Actions自动化发行 | 涛哥的博客 玩转Qt(11)-github-Actions自动化发行 | 涛哥的博客 玩转Qt(10)-github-Actions自动化编译 | 涛哥的博客 玩转Qt(10)-github-Actions自动化编译 | 涛哥的博客 玩转Qt(9)-程序发布指南 | 涛哥的博客 玩转Qt(9)-程序发布指南 | 涛哥的博客 玩转Qt(8)-掌握信号槽使用细节 | 涛哥的博客 玩转Qt(8)-掌握信号槽使用细节 | 涛哥的博客 玩转Qt(7)-窥探信号槽的实现细节 | 涛哥的博客 玩转Qt(7)-窥探信号槽的实现细节 | 涛哥的博客 玩转Qt(6)-认清信号槽的本质 | 涛哥的博客 玩转Qt(6)-认清信号槽的本质 | 涛哥的博客 玩转Qt(5)-理解事件循环 | 涛哥的博客 玩转Qt(5)-理解事件循环 | 涛哥的博客 玩转Qml(16)-移植ShaderToy | 涛哥的博客 玩转Qml(16)-移植ShaderToy | 涛哥的博客 玩转Qml(15)-着色器效果ShaderEffect | 涛哥的博客 玩转Qml(15)-着色器效果ShaderEffect | 涛哥的博客 玩转Qml(14)-动画特效-梯度 | 涛哥的博客 玩转Qml(14)-动画特效-梯度 | 涛哥的博客 玩转Qml(13)-动画特效-飞入 | 涛哥的博客
玩转Qml(13)-动画特效-飞入 | 涛哥的博客
2019-06-08 · via 涛哥的博客

本文于 1032 天之前发表,文中内容可能已经过时。

  • 简介
  • 关于文章
  • 飞入效果预览
  • 实现原理
  • QtQuick动画系统
    • 动画组件
    • 动画的使用
      • 用例一 直接声明动画
      • 用例二 on语法
      • 用例三 Transitions或状态机
  • ShaderEffect
  • 飞入效果源码

简介

这次涛哥将会教大家一些Qml动画相关的知识。

源码

《玩转Qml》系列文章,配套了一个优秀的开源项目:TaoQuick

github https://github.com/jaredtao/TaoQuick

访问不了或者速度太慢,可以用国内的镜像网站gitee

https://gitee.com/jaredtao/TaoQuick

飞入效果预览

第一篇文章,就放一个简单的动画效果

实现原理

进场动画,使用了QtQuick的动画系统,以及ShaderEffect特效。

Qml中有一个模块QtGraphicalEffects,提供了部分特效,就是使用ShaderEffect实现的。

使用ShaderEffect实现特效,需要有一些OpenGL/DirectX知识,了解GPU渲染管线,同时也需要一些数学知识。

QtQuick动画系统

动画组件

Qt动画系统,在帮助文档有详细的介绍,搜索关键词”Animation”,涛哥在这里说一些重点。

涛哥用思维导图列出了Qml中所有的动画组件:

  • 右边带虚线框的部分比较常用,是做动画必须要掌握的,尤其是属性动画PropertyAnimation和数值动画NumberAinmation。
    常见的各种坐标动画、宽高动画、透明度动画、颜色动画等等,都可以用这些组件来实现。

  • 底下的States、Behavior 和 Traisitions,也是比较常用的和动画相关的组件。可在帮助文档搜索
    关键词”Qt Quick States”、”Behavior”、”Animation and Transitions”。后续的文章,涛哥会专门讲解。

  • 左边的Animator系列,属于Scene Graph渲染层面的优化,其属性Change信号只在最终值时发出,不发出中间值,使用的时候需要注意。

  • 顶上的AnimationController,属于高端玩家,用来控制整个动画的进度。

动画的使用

用例一 直接声明动画

直接声明动画,指定target和property,之后可以在槽函数/js脚本中通过id控制动画的运行。

也可以通过设定loops 和 running属性来控制动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Rectangle {
id: flashingblob
width: 75; height: 75
color: "blue"
opacity: 1.0

MouseArea {
anchors.fill: parent
onClicked: {
animateColor.start()
animateOpacity.start()
}
}

PropertyAnimation {id: animateColor; target: flashingblob; properties: "color"; to: "green"; duration: 100}

NumberAnimation {
id: animateOpacity
target: flashingblob
properties: "opacity"
from: 0.99
to: 1.0
loops: Animation.Infinite
easing {type: Easing.OutBack; overshoot: 500}
}
}

用例二 on语法

on语法可以使用动画组件,也可以用Behavior,直接on某个特定的属性即可。效果一样。

on动画中,如果直接指定了running属性,默认就会执行这个动画。

也可以不指定running属性,其它地方修改这个属性时,会自动按照动画来执行。

示例代码 on动画

1
2
3
4
5
6
7
8
9
Rectangle {
width: 100; height: 100; color: "green"
RotationAnimation on rotation {
loops: Animation.Infinite
from: 0
to: 360
running: true
}
}

示例代码 Behavior 动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import QtQuick 2.0

Rectangle {
id: rect
width: 100; height: 100
color: "red"

Behavior on width {
NumberAnimation { duration: 1000 }
}

MouseArea {
anchors.fill: parent
onClicked: rect.width = 50
}
}

用例三 Transitions或状态机

过渡动画和状态机动画,本质还是直接使用动画组件。只不过是把动画声明并存储起来,以在状态切换时使用。

这里先不细说了,后面会有系列文章<Qml特效-页面切换动画>,会专门讲解。

ShaderEffect

动画只能控制组件的属性整体的变化,做特效需要精确到像素。

Qml中提供了ShaderEffect这个组件,就能实现像素级别的操作。

大名鼎鼎的ShaderToy网站,就是使用Shader实现各种像素级别的酷炫特效。

ShaderToy

作者iq大神

ShaderToy上面的特效都是可以移植到Qml中的。

使用Shader开发,需要一定的图形学知识。其中使用GLSL需要熟悉OpenGL, 使用HLSL需要熟悉DirectX。

飞入效果源码

封装了一个平移进入的动画组件,能够支持从四个方向进场。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

import QtQuick 2.12
import QtQuick.Controls 2.12
import "../.."
Item {
id: r
property int targetX: 0
property int targetY: 0
property alias animation: animation
enum Direct {
FromLeft = 0,
FromRight = 1,
FromTop = 2,
FromBottom = 3
}
property int dir: ASlowEnter.Direct.FromBottom
property int duration: 2000

property int extDistance: 10
property var __propList: ["x", "x", "y", "y"]
property var __fromList: [
-r.parent.width - r.width - extDistance,
r.parent.width + r.width + extDistance,
-r.parent.height - r.height - extDistance,
r.parent.height + r.height + extDistance]
property var __toList: [targetX, targetX, targetY, targetY]
NumberAnimation {
id: animation
target: r
property: __propList[dir]
from: __fromList[dir]
to: __toList[dir]
duration: r.duration
loops: 1
alwaysRunToEnd: true
}
}

进场组件的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74


import QtQuick 2.12
import QtQuick.Controls 2.12
import "../Animation/Enter"
Item {
anchors.fill: parent
ASlowEnter {
id: a1
width: 160
height: 108
x: (parent.width - width) / 2
targetY: parent.height / 2
dir: ASlowEnter.Direct.FromBottom
Image {
anchors.fill: parent
source: "qrc:/EffectImage/Img/baby.jpg"
}
}
ASlowEnter {
id: a2
width: 160
height: 108
x: (parent.width - width) / 2
targetY: parent.height / 2 - height
dir: ASlowEnter.Direct.FromTop
Image {
anchors.fill: parent
source: "qrc:/EffectImage/Img/baby.jpg"
}
}
ASlowEnter {
id: a3
width: 160
height: 108
targetX: parent.width / 2 - width * 1.5
y: (parent.height - height) / 2
dir: ASlowEnter.Direct.FromLeft
Image {
anchors.fill: parent
source: "qrc:/EffectImage/Img/baby.jpg"
}
}
ASlowEnter {
id: a4
width: 160
height: 108
targetX: parent.width / 2 + width / 2
y: (parent.height - height) / 2
dir: ASlowEnter.Direct.FromRight
Image {
anchors.fill: parent
source: "qrc:/EffectImage/Img/baby.jpg"
}
}
ParallelAnimation {
id: ani
ScriptAction{ script: {a1.animation.restart()} }
ScriptAction{ script: {a2.animation.restart()} }
ScriptAction{ script: {a3.animation.restart()} }
ScriptAction{ script: {a4.animation.restart()} }
}
Component.onCompleted: {
ani.restart()
}
Button {
anchors.right: parent.right
anchors.bottom: parent.bottom
text: "replay"
onClicked: {
ani.restart()
}
}
}