摘要

为了实现Carte Blanche的卡片系统,我们专门开发了一套可扩展的框架,以用于创建动态的可滚动的对象列表。本文章则会针对该框架的架构和内容做详细探讨。代码和示例场景可以在Unity资源商店中获得,也可从Unity开源库中获取。

介绍

Carte Blanche项目(PCB)是Unity实验室的研发计划,目的是为非技术用户提供VR-in-VR的编程工具。正如概念视频中所演示的一样,其用户交互界面类似于一种卡牌的玩法。Carte Blanched的核心设计理念主要在于对象与行为的设计,它的一种典型示例:用户可以抓取虚拟的扑克牌,并将其放置在虚拟的桌子上,借助动作捕捉真实地与卡牌互动。

Carte Blanche概念视频:



PCB的卡牌系统是一种较传统滚动列表要复杂得多的系统。列表视图作为GUI组件,在很多GUI工具包中都存在。Unity的UI系统包含了数个布局组件和可定制,用于制作可滚动的、带有悬浮状态特性的动态列表。一般来说GridLayout或VerticalLayout就能搞定大部分工作,而且资源商店就列表一项就有很多便捷的工具包可供使用。然而我们能找到的现有的解决方案都存在一个前提,即列表只能存在于UI系统中,受画布(Canvas)管理。而PCB系统要求卡牌必须能够动态出现或消失,且用户可以触碰到它们。此外,VR应用程序对性能的要求也极其苛刻。传统UI列表视图的一个普遍缺点是用来表示整个列表的场景对象都是需要被“遮罩”的。如果列表结构发生了改变,或者列表中的某一个条目的大小发生了变化需要占据更多空间时,系统就必须必须重新计算列表中的所有条目。我们还想尽量避免实例化/销毁场景对象,因为这些操作的开销非常之大。最后,为了可重用性,外观和感觉上的统一性起见,我们还需要一套可扩展的解决方案,能够让我们使用其他类型的UI元素制造出相似的体验。

我们为列表视图开发了一套通用框架作为PCB卡牌系统的基础。考虑到这样的框架还有很大的应用空间,我们决定将它发布在资源商店上供社区下载使用。

173009jtddntmctcg2gc3m.png

Model 与 View的解藕

本框架的一个设计目标是遵循MVC或MVVM设计模式,将数据的显示逻辑(view)与数据的状态(model)本身解藕。对于任何一个框架而言,框架本身应自动处理列表当前状态的显示。这种实现下我们只需要考虑数据的当前状态,而不用关心如何处理视图的更新。同理,即便用户的操作执行非常快或框架本身需要较长时间来渲染时,我们也不需要顾虑同步问题。此外这样做还有一个好处,列表所使用的CPU时间会相对地较为和缓,因为它要做的差不多都是一样的事情。这样即便当列表的尺寸发生显著增长或状态的变化超出预期时,整体的性能也不会受到太大的影响。

为了实现这样的列表,我们借鉴了Android和iOS的UI框架。尽管它们的实现略有不同,但大体思路上是一样的。一个容器元素会控制其下属一系列子元素的位置,这些子元素也会使用对象池缓存,用以避免元素进入或离开屏幕时内存的分配与释放产生的花销。其次,我们还定义了一个接口,用于描述关于视图如何为列表元素从数据源获取数据。开发者只需要为数据源编写代码,设计列表项目就好,其他的框架会负责解决。两个SDK都提供了实用的引导教程,帮助开发者了解如何遵循相同的设计缓存池设计模式以及与数据源之间建立接口。iOS称之为UITableView,而Android方面则称它为带有ListAdapter的ListView——它们都负责与数据进行沟通。

两种实现都为可滚动UI元素的布局提供了框架,同时允许开发者为如何使用这些元素提供函数定义,而这些元素可以来自数据库,文本文件,或任何它们想要的数据源。视图需要知道数据集合中总元素的数量,也需要一个能够得到信息的方法,例如显示电影标题和电影评价。如果仅要显示文字的话,默认的模板就可以实现,开发者也可以自定义列表的设计,使用开发者想要的UI布局。框架本身会负责搞定这些列表行的内存分配问题,并在列表元素离开屏幕时回收并重用在接下来要显示的元素上。如果列表行使用了相同的模板,则系统理论上不需要为超出一个屏幕大小的元素分配内存(当然还要多分配一个条目的内存空间,为列表滚动的流畅起见)。这里多出的一行存在的目的是考虑到首个条目和最后一个条目只在屏幕上显示一半时的情况。我们姑且就认为这是为列表提供额外的空间用于混合列表就好了。

资源包

List View 框架现已上架Unity资源商店,一同开放的还有Unity BitBucket官方账号的开源Git仓库。我们希望这个包以及我们将要发布的资源可以为社区所用,并不断地进行提升。您可以随意地将这个框架fork到您的工程中。代码受MIT/X11授权保护,这就是说只要您保留免责声明,您可以对代码做任何您想做的事情。将来我们Unity的这些人还要发布更多模块化的开源资源包,希望能够为社区提供帮助,并帮助我们提升代码的质量。本文的框架是Carte B lanche项目资源包的首个模块,其他的模块将会陆续地以同样地方式对社区公布。

本框架可以归结为三个C#类:ListViewController(以两个文件存在),ListViewItem与ListViewItemData:

[C#] 纯文本查看 复制代码public abstract class ListViewControllerBase : MonoBehaviour { public float scrollOffset; public GameObject[] templates; ... } public abstract class ListViewController<DataType, ItemType> : ListViewControllerBase where DataType : ListViewItemData where ItemType : ListViewItem { public DataType[] data; ... } public class ListViewItem<DataType> : ListViewItemBase where DataType : ListViewItemData { public DataType data; public virtual void Setup(DataType data) { this.data = data; data.item = this; } } public class ListViewItemData { public string template; public MonoBehaviour item; }

将ListViewController分为两部分的理由如下:如果我们这样做,我们就可以访问这些无关数据类型的属性,无需关心使用了什么样的列表实现。通过这种实现方式,InputHandler脚本可以对任意类型的列表做滚动操作,而无需关心是什么类真正实现了ListViewController。框架本身包括了一个非常基础的ListViewController实现,它可以接收空数据条目(数据可以在检视器中设定):

[C#] 纯文本查看 复制代码public class ListViewController : ListViewController {}


最简单的列表实现(样例0)使用了所有的基类,允许用户对一系列基于模板的Prefab的对象进行滚动操作,以及在检视器中为一个数据数字提供设定。如需显示真正的内容,用户应扩展ListViewItemData类和ListViewController类,并在其中具体描述他们需要使用的数据,正如下面的示例中展示的一样。

173038vew2ywlwbe3yaewp.png
ListViewInputHandler类为基于鼠标输入的滚动或点击行为提供了基础。当然,ListViewScroller子类也为滚动行为设定了一些有用的模式。鼠标与触摸输入也是非常容易处理的。除此之外,在处理游戏手柄,UI,手势输入或VR设备时这些类也能让开发者很方便地完成需要的特性。在PCB的例子中,列表视图的控制是通过手势追踪来实现的。

结论

我们希望本篇文章能够给您一个清晰的印象,让您了解框架的工作原理,样例以及如何在您的工程中整合这个列表视图框架。如需了解更多详细的信息,您可以访问该项目的Wiki来获取更多信息,更深层次地了解核心类和示例。即便您对这里提供的代码没有直接上的需求,这里讨论的有关模型与视图代码之间的解藕仍然能提供很大的启发,帮助您编写更高效的代码,使得您的项目更加容易管理。游戏系统通常会从无状态设计中获得极大的提升,因为这种设计仅使用非常少的资源,也会持续不断尽可能多地评估信息。我们的目标是设计一套系统,创造一种可深度定制的、能够处理任何给定类型数据的可滚动列表。现在我们已经有了一套性能很好的工具、拥有同步缓存、不均匀的缓存尺寸、嵌套数据以及复杂的动画行为等特性。最终,我们无论如何要记住由于示例代码的局限性,它可能不能考虑到所有的情况,每种功能实现都有着其局限性,因此有可能存在某些没有考虑到的情况。

示例效果:

182059lrz9nmnr0cnl5ra5.gif

Unity Labs网站分享了不少好玩的干货,欢迎大家前去查看!

原文链接:https://labs.unity.com/article/list-view-framework
感谢Unity官方翻译组成员“Yvlein”对本文翻译所做的贡献。
转载请注明来源:Unity官方中文社区 (forum.china.unity3d.com)。请勿私自更改任何版权说明信息。
Unity, Unity Labs, VR List View锐亚教育

锐亚教育 锐亚科技 unity unity教程