【QML Model-View】ListView-动画+上移下移(三)
ListView 提供了 add、remove、move、populate、displaced 几种场景的过渡动画效果,你 可以通过设置相应的属性来改变特定场景对应的过渡动画。这些场景对应的属性,类型都是 Transition,—个场景也可能有多个属性,比如新增 Item 会触发 add 过渡动画,同时也可能引 起其他 Item 的位置变化,进而触发 addDisplaced 或 displaced 过渡动画。
效果
初始化 动画
ListView 第一次初始化使用 populate 动画:
// 在ListView第一次实例化或者因Model变化而需要创建Item时应用
populate: Transition {
NumberAnimation {
property: "opacity"
from: 0
to: 1.0
duration: 1000
}
}
这将产生一个渐显效果。
add 动画
add 属性指定向 ListView 新增一个 Item 时针对该 Item 应用的过渡动画。其设置了一个 ParallelAnimation,内含一个变换透明度的动画和一个变换 y 位置的动画。
// add过渡动画(新增Item触发)
add: Transition {
ParallelAnimation{
NumberAnimation {
property: "opacity"
from: 0
to: 1.0
duration: 1000
}
NumberAnimation {
properties: "x,y"
from: 0
duration: 1000
}
}
}
最终的效果是,新增 Item 从 ListView 上方渐现、缓缓下落到特定位置。 需要注意的是,尽量不要在 add 动画中改变 Item 的高度,因为这样会引起它下面的其他 Item 被重新布局进而错放位置,也会带来性能上的损耗。
displaced 动画
我点击 “Insert” 按钮时,新增 Item 下方的那些被迫移位的 Item,没有明显的动画效果。 这是因为 displaced 属性默认为 null,ListView 没有提供默认的移位动画。
displaced 属性用于指定通用的、由于 Model 变化导致 Item 被迫移位时的动画效果,而相应 的 addDisplaced、moveDisplaced、removeDisplaced 则用于指定由特定的 add、move、remove 操作引起的移位动画。如果你同时指定了 displaced 和 xxxDisplaced,那 xxxDisplaced生效;如果你只指定 displaced,那只要有移位发生,displaced 动画就会被应用。
// 用于指定通用的、由于Model变化导致Item被迫移位时的动画效果
displaced: Transition {
SpringAnimation {
property: "y"
spring: 3
damping: 0.1
epsilon: 0.25
}
}
再运行看看,点击 “Insert” 按钮,会发现位于新增 Item 下方的那些 Item 会向下移动,来回弹几次才平静下来。
remove 动画
remove 属性指定将一个 Item 从 ListView 中移除时应用的过渡动画。当动画开始执行时, Item 已经被移除,此时任何对该 Item 的引用都是非法的。移除一个 Item 可能会导致其他 Item 移位,此时会触发 removeDisplaced 或 displaced 过渡动画。给 ListView 指定 remove 动画如下:
// remove过渡动画(移除Item触发)
remove: Transition {
SequentialAnimation{
NumberAnimation {
properties: "y"
to: 0
duration: 600
}
NumberAnimation {
property: "opacity"
to: 0
duration: 400
}
}
}
再运行看看,双击一个 Item,它会先移动到 ListView 顶部,然后再慢慢变得看不见。
move 动画
move 属性指定移动一个 Item 时要应用的过渡动画。
// move过渡动画(移动Item触发)
move: Transition {
NumberAnimation {
property: "y"
duration: 700
easing.type: Easing.InQuart
}
}
上移 + 下移
我们以之前的示例为基础,构造一个专门演示动画效果的示例,phone_list_animation. qml。我给 footer 添加了 Up 和 Down 按钮,还增加了 moveUp 和 moveDown 信号,连接到 ListView 新增的 moveUp() 和 moveDown() 方法上。新的 footer 组件定义如下:
// 定义footer
Component {
id: footerView
Item{
id: footerRootItem
width: parent.width
height: 30
// 自定义信号
signal add()
signal insert()
signal moveUp()
signal moveDown()
// 新增按钮
Button {
id: addOne
anchors.right: parent.right
anchors.rightMargin: 4
anchors.verticalCenter: parent.verticalCenter
text: "Add"
onClicked: footerRootItem.add()
}
// 插入按钮
Button {
id: insertOne
anchors.right: addOne.left
anchors.rightMargin: 4
anchors.verticalCenter: parent.verticalCenter
text: "Insert"
onClicked: footerRootItem.insert()
}
// 下移按钮
Button {
id: moveDown;
anchors.right: insertOne.left
anchors.rightMargin: 4
anchors.verticalCenter: parent.verticalCenter
text: "Down"
onClicked: footerRootItem.moveDown()
}
// 上移按钮
Button {
id: moveUp;
anchors.right: moveDown.left
anchors.rightMargin: 4
anchors.verticalCenter: parent.verticalCenter
text: "Up"
onClicked: footerRootItem.moveUp()
}
}
}
ListView 新增 moveUp() 和 moveDown() 方法,计算当前 Item 的索引,调用 model 的 move() 方法让当前 Item 下移一个位置。给 move 属性设置了一个 Transition 对象。新的 ListView 声明如下:
// 定义ListView
ListView {
id: listView
anchors.fill: parent
interactive: false
delegate: phoneDelegate
model: phoneModel.createObject(listView)
header: headerView
footer: footerView
focus: true
highlight: Rectangle{
color: "lightblue"
}
// 在ListView第一次实例化或者因Model变化而需要创建Item时应用
populate: Transition {
NumberAnimation {
property: "opacity"
from: 0
to: 1.0
duration: 1000
}
}
// add过渡动画(新增Item触发)
add: Transition {
ParallelAnimation{
NumberAnimation {
property: "opacity"
from: 0
to: 1.0
duration: 1000
}
NumberAnimation {
properties: "x,y"
from: 0
duration: 1000
}
}
}
// 用于指定通用的、由于Model变化导致Item被迫移位时的动画效果
displaced: Transition {
SpringAnimation {
property: "y"
spring: 3
damping: 0.1
epsilon: 0.25
}
}
// remove过渡动画(移除Item触发)
remove: Transition {
SequentialAnimation{
NumberAnimation {
properties: "y"
to: 0
duration: 600
}
NumberAnimation {
property: "opacity"
to: 0
duration: 400
}
}
}
// move过渡动画(移动Item触发)
move: Transition {
NumberAnimation {
property: "y"
duration: 700
easing.type: Easing.InQuart
}
}
// 新增函数
function addOne() {
model.append(
{
"name": "MX3",
"cost": "1799",
"manufacturer": "MeiZu"
}
)
}
// 插入函数
function insertOne() {
model.insert( Math.round(Math.random() * model.count),
{
"name": "HTC One E8",
"cost": "2999",
"manufacturer": "HTC"
}
)
}
// 上移函数
function moveUp() {
if(currentIndex - 1 >= 0){
model.move(currentIndex, currentIndex - 1, 1)
}
}
// 下移函数
function moveDown() {
if(currentIndex + 1 < model.count){
model.move(currentIndex, currentIndex + 1, 1)
}
}
// 连接信号槽
Component.onCompleted: {
listView.footerItem.add.connect(listView.addOne)
listView.footerItem.insert.connect(listView.insertOne)
listView.footerItem.moveUp.connect(listView.moveUp)
listView.footerItem.moveDown.connect(listView.moveDown)
}
}
}
现在可以执行 “qmlscenephone_list_animation.qml” 看看效果了。
下载链接
全部代码下载链接:https://github.com/confidentFeng/QML_Demo/tree/master/ListViewPhone
参考:
《Qt Quick核心编程》第13章