【问题标题】:ListView scrolling animationListView 滚动动画
【发布时间】:2015-07-31 12:31:14
【问题描述】:

我想为 QML ListView 实现滚动动画。这是一个示例图像:

有人可以建议我实施这个吗?

谢谢。

【问题讨论】:

  • 只需使用 PathView... 稍微复杂一些,但足以满足用例的需要。不建议在 ListView 中执行此操作,因为您需要在委托中保存状态(如 BaCaRoZzo 所建议),这是一种不好的做法。
  • @TOHO PathView 是一个循环列表。在这种情况下它是没有用的。

标签: qt listview animation qml qtquick2


【解决方案1】:

ViewTransition 提供了很多有趣的示例,说明如何为ListView 等操作设置动画,例如populate(组件创建时的初始项的转换)、add、remove(不言自明) ) 以及其他操作。

给定一个ListView,您可以为每个要设置动画的操作定义一个元素Transition。 The animation framework 可用于创建复合动画,只需简单地组合基本动画即可创建(或多或少)您感兴趣的复杂行为(另请参阅 here 以获取实际示例)。

这里是ListView 的定义(第一个链接文档提供了一些漂亮的图像):

ListView {

    // data model, delegate, other usual stuff here...

    // transitions for insertion/deletation of elements
    add: Transition {
        NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 500 }
        NumberAnimation { property: "scale"; easing.type: Easing.OutBounce; from: 0; to: 1.0; duration: 750 }
    }

    addDisplaced: Transition {
        NumberAnimation { properties: "y"; duration: 600; easing.type: Easing.InBack }
    }

    remove: Transition {
        NumberAnimation { property: "scale"; from: 1.0; to: 0; duration: 200 }
        NumberAnimation { property: "opacity"; from: 1.0; to: 0; duration: 200 }
    }

    removeDisplaced: Transition {
        NumberAnimation { properties: "x,y"; duration: 500; easing.type: Easing.OutBack }
    }
}

最后,请注意,可以通过使用着色器并结合元素上的动画和委托/委托的元素上的过渡来获得一些行为。一个很好的例子是Tweet Search,其中条形项目上的阴影效果(参见[ShaderEffect][5])与ListViewadd 上的简单Transition 相结合。

编辑

提供像示例中一样的自定义滚动,需要考虑Items 在ListView 中的位置。一个可行的解决方案的关键是找到一种方法来计算Item 在视图的可见部分 内的当前位置,并使用该值来计算适当的转换。 ListView 派生自 Flickable,它为此目的具有几个有用的属性。

但是,Item 的y 属性是指ListView 内内容的整体高度。有它的位置 w.r.t.可见区域的开头我们可以使用contentY 属性。在这种情况下,一张图片值一千字:

y 和contentY 之间的差异提供了一个值,可用于计算所需的转换因子(可能与height 的ListView 相关)。实际上,随着ListView 的轻弹,这两个值及其差异会发生变化,因此会更改特定Item 的转换因子。

这样的转换只涵盖了问题的部分。一旦轻弹/移动结束,Items 动画必须“完成”以使所有可见的items 可用。为此,我们可以利用Binding 及其when 属性仅在需要时激活结束动画,即当flicking 或dragging 结束时。

鉴于所有这些(无聊的)介绍,让我们考虑第二个动画(更简单的动画)。这里我们可以使用scale来获得想要的效果。 ListView 中的 delegate 代码如下所示:

ListView {
    id: list
    model: 100
    spacing: 10

    delegate: Rectangle {
        id: itemDelegate
        property int listY: y - list.contentY       // stores the difference between the two values
        width: parent.width
        height: 50
        border.color: "lightgray"
        color: "red"

        Binding {
            target: itemDelegate
            property: "scale"
            value: 1 - listY / list.height / 2      // the "scale" property accepts values in the range [0, 1]
            when: list.moving || list.flicking || list.dragging     // ...when moved around
        }

        Binding {
            target: itemDelegate
            property: "scale"
            value: 1                                // flick finished --> scale to full size!
            when: !(list.moving || list.dragging)   // not moving or dragging any more
        }

        Behavior on scale {
            NumberAnimation { duration: 100; to: 1}
            enabled: !(list.flicking || list.dragging) // active only when flick or dragging ends!
        }
    }
}

第一个Binding 定义基于listY 的缩放因子,而第二个将缩放设置为1,但仅当ListView 不移动时。最后的Behavior 是平滑过渡到完全缩放的Item 所必需的。

第三个效果可以用Rotation类似的方式获得:

ListView {
    anchors.fill: parent
    id: list
    spacing: 10
    model: 100

    delegate: Rectangle {
        id: itemDelegate
        property int listY: y - list.contentY
        property real angleZ: (90 * listY)  / list.height       // 0 - 90 degrees
        transform: Rotation { origin.x: width / 2; origin.y: 30; axis { x: 1; y: 0; z: 0 } angle: angleZ}
        //transform: Rotation { origin.x: 0; origin.y: 30; axis { x: 1; y: 1; z: 0 } angle: angleZ}     <--- I like this one more!
        width: parent.width
        height: 50
        border.color: "lightgray"
        color: "red"

        Binding {
            target: itemDelegate
            property: "angleZ"
            value: 0
            when: !(list.moving || list.dragging)
        }

        Behavior on angleZ {
            NumberAnimation {duration: 200; to: 0}
            enabled: !(list.flicking || list.dragging)
        }
    }
}

这一次我选择(任意)只使用一个Binding。 同样可以在第一个示例中进行,即我们可以在第一个委托scale: 1 - listY / list.height / 2中编写。

按照类似的方法,您还可以创建第一个动画和其他动画。对于第一个动画,我认为将 Rotation 与 Translate 组合就足够了。

【讨论】:

  • 我知道 ListView 和 ViewTransition。请注意,我希望滚动动画不仅仅是添加/删除/...置换动画。你能给我建议吗?
  • 对不起,我似乎完全没有抓住重点。对于问题的重点,我研究了相同的功能,我记得一个有趣的例子。一旦找到它,我将发布一个链接(并重新编辑答案)。再次抱歉。
  • @S.M.Mousavi 抱歉耽搁了。我的示例仅针对所选项目,因此没有逐步过渡,我不在办公室,最后但并非最不重要的是,我对y 有一些问题(只是深夜...更长的故事here 和最后非常感谢 Jens)。无论如何,我希望这种方法能够满足您的需求。
  • 非常感谢。你让我对这个问题有了更好的认识。我为您和任何人分享了我的最终解决方案。我想给你一些分数,但似乎没有任何办法:(再次感谢
  • 这样就好。写答案很有趣,你的解决方案给了我一些好主意。 +1 为正确答案。 :)
【解决方案2】:

经过数小时的工作、研究和@BaCaRoZzo 的大力帮助(感谢@BaCaRoZzo),我终于找到了正确的解决方案。只需使用Component.onCompleted() 事件处理程序来运行与每个委托关联的动画。

这是一个例子,享受吧!

import QtQuick 2.3

ListView {
    anchors.fill: parent
    id: list
    model: 100
    cacheBuffer: 50

    delegate: Rectangle {
        id: itemDelegate
        Component.onCompleted: showAnim.start();
        transform: Rotation { id:rt; origin.x: width; origin.y: height; axis { x: 0.3; y: 1; z: 0 } angle: 0}//     <--- I like this one more!
        width: parent.width
        height: 50
        color: index % 2 === 0 ? "#EEE" : "#DDD"
        SequentialAnimation {
            id: showAnim
            running: false
            RotationAnimation { target: rt; from: 180; to: 0; duration: 800; easing.type: Easing.OutBack; property: "angle" }
        }
    }
}

【讨论】:

  • 是的,很好的解决方案!我仍然不符合您的要求,但至少我很有帮助,我很高兴。 :) 另外,我肯定会尝试使用您的解决方案。爱它。 :)
【解决方案3】:

PathView 显示来自内置 QML 类型(如 ListModel 和 XmlListModel)创建的模型的数据,或从 QAbstractListModel 继承的 C++ 中定义的自定义模型类。 视图有一个模型,它定义了要显示的数据,还有一个委托,它定义了数据应该如何显示。为路径上的每个项目实例化委托。可以轻弹这些项目以沿路径移动它们。

【讨论】:

  • 谢谢。我检查了它。它似乎适用于分辨率。但是滚动动画有不同的行为。不可见的项目,必须变为可见并在滚动时用动画填充列表的可见区域。 PathView 没有足够的行为并且不满足这个问题:\。观看示例视频codecanyon.net/item/android-listview-animations/4179731
猜你喜欢
  • 2011-09-16
  • 1970-01-01
  • 2014-03-02
  • 2014-07-14
  • 2019-11-21
  • 1970-01-01
  • 2016-04-21
  • 2016-06-08
  • 1970-01-01
相关资源
最近更新 更多