CCTableView是参照UITableView来写的,因此其对于tablecell的处理基本原理也是相通的。
在CCTableView的头文件中声明了三个类
1.
class
CCTableViewDelegate
2.
class
CCTableViewDataSource
3.
class
CCTableView
:
public
CCScrollView
,
public
CCScrollViewDelegate
使用时需要继承CCTableViewDelegate和CCTableViewDataSource这两个类,实现其中的下列三个方法:
1、 响应table触摸事件的方法,其中
CCTableView
*
table为包含给定cell的table,
CCTableViewCell
*
cell为触摸到的cell。
virtual
void
tableWithcellTouched
(
CCTableView
*
table
,
CCTableViewCell
*
cell
);
常常在该方法里取得cell的idx,cell->
Getidx()
2、 返回给定table中cell的数量。
virtual
int
numberOfCellsInTableView
(
CCTableView
*
table
);
比如你想要建立一个包含10个cell的table,可以return 10。
3、 对于给定idx的cell实例变量进行初始化和更新
virtual
CCTableViewCell
*
tablecellAtIndex
(
CCTableView
*
table
,
int
idx
);
该方法主要用来初始化cell和cell包括的内容,并负责更新该cell。继承后的写法一般如下:
{
CCTableViewCell
*
cell
;
cell
=
table
->
dequeueCell
();
if
(
!
cell
)
{
cell
=
new
CCTableViewCell
;
CCNode
*
node
=
CCNode
::
node
();
// 初始化cell信息
cell
->
Setnode
(
node
);
}
CCNode
*
node
=
cell
->
Getnode
();
// 更新cell的内容
return
cell
;
}
}
===================Everybody, everybody wants to love===================
可见CCTableView是继承自CCScrollView的,但是在CCScrollView之上做了一些优化。
其中最赞的一点即tableview对cell的内存管理机制,这得益于上面tablecellAtIndex方法中的dequeueCell()方法,我们来详细介绍一下:
cell
=
table
->
dequeueCell
();
dequeueCell的方法如下:
CCTableViewCell
*
CCTableView
::
dequeueCell
()
{
CCTableViewCell
*
cell
;
_evictCell
(); // 将不在显示区域的cell放入一个临时的vector中
if
(
cellsFreed_
.
size
()
==
0
) // cellsFreed即为那个临时的vector,其中保存了当前不在显示区域的cell
{
cell
=
NULL
;
return
cell
;
}
else
{ // 如果cellsFreed非空,则取出其中的一个cell来复用
cell
=
cellsFreed_
[
0
];
cellsFreed_
.
erase
(
cellsFreed_
.
begin
());
return
cell
;
}
}
{
}
其中的根据scrollView的偏移来计算当前显示的tableview中可见cell的算法可以在
_evictCell
();中看到。
因此一般情况下,如果当前屏幕中有N个可见cell,那么tableView会创建N+2个cell,其中在头部和尾部之外都还有一个“预加载”的cell。
但是这只是外部表现出来的,就像这样
当向下移动table的时候,cell0会出现。cellsFreed_中的数据会被给到cellsUsed_内,因此预加载的cell内存地址和当cell可见时候的内存地址是不一样。
预加载的cell在地理位置上也不像图中所见的那样,在cell1上方。
最近遇到的一个bug就是点击cell中的图片,显示图片的基本信息。使用判断触摸点是否在图片内部的方法。
CCPoint
point
=
convertTouchToNodeSpaceA R
(
touch
);
在cell和cell中间的位置上,有时候点击会触发预加载的cell内图片的ccTouchBegan方法,因为预加载的cell内图片的触摸优先级和普通的可见的cell中图片的触摸优先级是一样的,我们将该图片封装为一个单独的类。
为此想了很多方法,如何区分预加载的cell和已经加载的cell。
最终我是这么做的,在ccTouchBegan中加入如下代码:
if
(
dynamic_cast
<</span>CCNode *>(this->getParent())) {
if (dynamic_cast<</span>CCLayer *>(this->getParent()->getParent())) {
// 为已经加载的cell,执行接下来的判断是否在图片内部的方法
CCLog("this->getParent->getParent");
} else {
// 为预加载cell,直接返回
return true;
}
}
}
CCTableViewCell继承自CCObject方法,由于在tableAtIndex中,有了cell->SetNode(node);的代码,所以判断parent的时候不能判断为CCTableViewCell*,而应该为CCNode*
CCTableView继承自CCScrollView,最上层继承自CCLayer,因此
(
this
->
getParent
()
->
getParent
())时,应该判断是否为CCLayer*。