对于列表,引擎提供了几种实现方式,既有2.x版本中extension 命名空间的ScrollView类和 TableView 类,又有 3.x 版本中 ui 命名空间的 ScrollView 类、PageView 类和 ListView类。由于作者接触引擎的时间比较早,即使用 3.x 版本开发时,对于列表的使用,还是使用2.x 版本中的类。所以本节就围绕 ScrollView 类和 TableView 类来讲解列表方面的知识。对于ui命名空间下对应的类,效果是一样的,只是实现方式不一样而已。
ScrollView 类实现了一个滚动视图,可以向一个容器中(如 Node 节点)加入各种对象,如图片对象(Sprite)、文字(Label)和菜单(Menu)等的控制这个节点的显示方式,让它可以上下或左右滚动,而又不让节点超出它的显示范围。该类有个对应的委托类ScrollViewDelegate,它有两个函数,如程序片段2-42所示。
程序片段2-42 ScrollViewDelegate类的方法
当要用到这两个方法的功能时,可以继承 ScrollViewDelegate 类,重写这两个方法,然后在创建ScrollView对象的时候调用setDelegate方法即可,这两个方法的使用是可选的。对于这种视图的使用,和引擎创建其他类型的对象一样,如程序片段2-43所示。
程序片段2-43 ScrollView类的使用
程序片段2-43中,向m_pContainer对象的容器中加入3张图片对象,这3张图片的大小都为(480,320),然后创建 ScrollView 对象来控制 m_pContainer 对象容器,设置它的滚动方向为HORIZONTAL。另外两种分别是VERTICAL和BOTH,其中BOTH指在两个方向上都可以滚动。由于容器中有 3 张图片,且是水平摆放的,所以整个容器的宽度是图片长度的3倍,而高度和图片高度一样。程序片段2-42中调用了setContentSize函数来设置容器的大小,g_strPath是图片存储的相对路径。
在创建 ScrollView 对象时,create 函数的第一个参数是指滚动视图裁剪区域的大小,和图片大小相同,所以每次只能完全显示一张图,但可以通过滚动的方式来查看其他两张图。
对于这种滚动视图,可以通过移动让两张图片都显示一部分。然而,在游戏中,当手指在屏幕上松开时,应该只能显示其中一张完整图,而不是分别显示一部分。
对于这种需求的视图,可以通过继承ScrollView 类,重写事件响应函数来实现,给移动设定一个阈值,当手指在屏幕上移动的距离小于阈值时,还是滚回到上一张图的显示,否则显示下一张图。以水平滚动为例,在事件响应函数 onTouchBegan 中记录单击时的初始位置信息,而在 onTouchEnded 函数中,通过将此时的位置和初始位置在水平方向上的差值与阈值做一个对应,然后做出响应的判断。而对于 onTouchEnded 函数中距离差值的判断,如程序片段2-44所示。
程序片段2-44 滚动距离判断
程序片段 2-44 中,以 100 个像素作为判断条件,而实际运用中要转换到屏幕上的英寸长度,ScrollView 类中提供 convertDistanceFromPointToInch 函数来实现这种转换。通过移动距离和阀值的比较,计算出在手指离开屏幕时应该显示哪一个页面,然后调用 setContent Offset 函数,指定第二个参数为 true,让视图平滑地移动到当前页面。在随书配送的光盘中,有一个 XJScrollView 来实现这种翻页的功能,关于它的使用,在创建滚动视图时,把ScrollView换成XJScrollView即可,其他的一样,读者可以对照光盘中提供的两个例子。
当使用滚动视图时,对于显示的每一项没有什么规律时,一般使用ScrollView 类实现,如游戏中使用文字的方式介绍游戏或聊天系统等。但当其中每一项的格式都类似时,则使用TableView的方式来实现,如游戏中的充值列表、好友榜等,该类继承自ScrollView。
TableView 有 3 个与它相关的类,TableViewCell 类表示列表中的一项,是 Node 的子类,可以往里面加入其他的节点;TableViewDelegate 类是当列表中的某一项被单击时响应对应的函数,它一共有4个函数,如程序片段2-45所示。
程序片段2-45 TableViewDelegate类的函数
从程序片段 2-45 中可以看出,TableViewDelegate 类负责列表中的某项被单击时,执行响应的回调函数。还有一个相关类是 TableViewDataSource,它是列表的数据来源,列表中的每项数据都在该类提供的函数中创建和设置,该类也有 4 个函数,具体如程序片段2-46所示。
程序片段2-46 TableViewDataSource类的函数
numberOfCellsInTableView函数返回所有项的数目,如列表中一共有20项要显示,则返回的值就为 20。然而,在一个界面中不可能一次性将 20 项全部显示出来,只能显示其中一部分。这个可以通过设置裁剪区域做到。假如设置的裁剪区域是在每一项都是完全显示状态(即没有被裁剪)时,显示的数目是 5 项,则通过滚动视图,最多可以看到列表项的数目是6。所以TableView在实现时,也就创建了6个TableViewCell对象,该类把创建的表项存储在两个列表中,一个类表存储的是当前显示的项,另外一个则是存储空闲的表项。当要显示一项时,就去空闲的列表中取,并重新设置该项的内容,然后把它加到正在使用的列表中,而如果一个表项被裁剪掉后,则该表项会从使用列表中删除。下面通过实例来讲解TableView的内容和使用。
程序片段2-47中创建了两个TableView,一个水平滚动,另一个垂直滚动。
程序片段2-47 TableView的创建
在创建 TableView 的节点类中,应该继承 TableViewDataSource 类和 TableViewDelegate类,并实现相应的方法。tableCellSizeForIndex 函数是设置每一项大小的地方;tableCellAt Index 函数是创建和设置每一项内容的地方;而 numberOfCellsInTableView 函数是设置列表中一共有多少项的地方,它们对应的实现代码如程序片段2-48所示。
程序片段2-48 TableViewDataSource类实现函数
程序片段 2-48 中,列表中一共有 20 项。对于水平列表,它的裁剪区域大小为(240,60),而每一项的大小为(60,60),所以正常显示 4 项,最多只能显示 5 项,垂直列表类似。tableCellAtIndex函数中else语句的作用是,如果从空闲列表中取到了一项,则该项的内容是上一次放入列表的,对于那些每一项都不同的数据,在else 语句中要重新设置,如代码中 Label 显示的序号。而对于那些每一项都相同的数据,则可以不用更改,如代码中的 Icon图片。对于空闲列表中没有取到表项,则要创建一个,同时设置该项的内容。
列表创建后,它的所有项都是同时显示在界面上的,为了增加可视效果,可以给列表或者它的每一项增加一个动画。对于列表动画,可以让它淡入淡出,或者打开时由小变大、关闭时由大变小等。而对于列表项动画,可以让它们交叉进入,或者从左到右依次进入等。列表的动画效果和给其他节点增加动画效果一样,下面以列表项的动画来介绍。
在 tableCellAtIndex 函数的 if 语句中,把创建的 TableViewCell 和索引 idx 加入到一个map 中,然后在 TableView 列表创建完成的后面,让列表中的所有项都运行动画,运行动画的函数封装到了CellAniHelp类中,由静态函数runAction实现列表项动画的功能,对应的实现代码如程序片段2-49所示。
程序片段2-49 TableViewCell动画
程序片段 2-49 中,通过索引的奇偶性来判断列表项的进入方式,分别让它们从左到右进入,参数p_CellMap为存储项索引和TableViewCell对象的容器。
列表类中,ScrollView 的作用是控制一个容器的显示,可以向该容器中加入其他要显示的任意内容。而TableView中的内容直接在tableCellAtIndex函数中设置,每一项内容的显示格式都是类似的。