每一个代理都可以访问一系列属性和附加属性。这些属性及附加属性中,有些来自于数据模型,有些则来自于视图。前者为代理提供了每一个数据项的数据信息;后者则是有关视图的状态信息。

    代理中最常用到的是来自于视图的附加属性和ListView.view。前者是一个布尔值,用于表示代理所代表的数据项是不是视图所展示的当前数据项;后者则是一个只读属性,表示该代理所属于的视图。通过访问视图的相关数据,我们就可以创建通用的可复用的代理,用于适配视图的大小和展示特性。下面的例子展示了每一个代理的宽度都绑定到视图的宽度,而代理的背景色则根据附加属性ListView.isCurrentItem的不同而有所不同。

    代码运行结果如下图所示:

    如果该模型的每一个数据项都关联一个动作,例如,响应对该数据项的点击操作,那么,这种功能就应该是每一个代理的一部分。这将事件管理从视图分离出来。视图主要处理的是各个子视图之间的导航、切换,而代理则是对一个特定的数据项的事件进行处理。完成这一功能最常用的方法是,为每一个视图创建一个MouseArea,然后响应其onClicked信号。我们会在后面看到这种实现的示例。

    为了达到这一目的,QML 为每个代理提供了两个信号,onAddonRemove,只要将这些信号与动画效果关联起来即可。

    下面的例子演示了为动态修改ListModel增加动画效果。在屏幕下方有一个用于新增数据项的按钮。点击该按钮,会通过调用append函数向模型增加一个数据项。这将触发视图创建一个新的代理,并且发出GridView.onAdd信号。该信号关联了一个SequentialAnimation类型的动画,利用属性的变化,将代理缩放到视图。当视图中的一个数据项被点击时,该项会通过调用视图的remove函数被移除。这会发出GridView.onRemove信号,触发另一个SequentialAnimation类型的动画。不过,这一次代理需要在动画结束之后才能被销毁(相比之下,在添加代理时,代理必须在动画开始之前就被创建)。为了达到这一目的,我们使用PropertyAction元素,在动画开始之前将GridView.delayRemove属性设置为true,动画完成之后,再将其设置为false。这保证了在代理被销毁之前,动画能够顺利完成。

    下图是运行初始效果。

    为代理添加动画

    改变代理的形状

    在表现列表时,常常会有这么一种机制:当数据项被选中时,该项会变大以充满屏幕。这种行为可以将被激活的数据项放置在屏幕中央,或者为用户显示更详细的信息。在下面的例子中,ListView的每一个数据项在点击时都会充满整个列表视图,多出来的额外空间用于显示更多信息。我们使用状态实现这种机制。在这个过程中,列表的很多属性都会发生改变。

    运行结果如下所示:

    点击每一项可以开始一个动画:

    代理点击动画

    这里展示的技术在某些方面非常实用,比如一些歌曲播放器允许用户在点击某首歌曲后,会将该歌曲的信息放大显示等。