cocos2d-x源码总目录
http://blog.csdn.net/u011225840/article/details/31743129
源码来自2.x,转载请注明
首先来看下CCTableView的继承结构
class CCTableViewCell: public CCNode, public CCSortableObject
{
public:
CCTableViewCell() {}
/**
* The index used internally by SWTableView and its subclasses
*/
unsigned int getIdx();
void setIdx(unsigned int uIdx);
/**
* Cleans up any resources linked to this cell and resets idx
property.
*/
void reset();
void setObjectID(unsigned int uIdx);
unsigned int getObjectID();
private:
unsigned int m_uIdx;
};
//根据不同的idx,来告诉tableview cell的大小
virtual CCSize tableCellSizeForIndex(CCTableView *table, unsigned int idx) {
return cellSizeForTable(table);
};
//提供一个通用的方法,给出table的cell大小,如果该table的cell大小都一样,一般都一样。。
virtual CCSize cellSizeForTable(CCTableView *table) {
return CCSizeZero;
};
//根据不同的idx,获得table的相应cell,一会分析table的dequeceCell时,再详细讲解此方法。
virtual CCTableViewCell* tableCellAtIndex(CCTableView *table, unsigned int idx) = 0;
//返回table的cell个数。
virtual unsigned int numberOfCellsInTableView(CCTableView *table) = 0;
CCTableView* CCTableView::create(CCTableViewDataSource* dataSource, CCSize size, CCNode *container)
{
CCTableView *table = new CCTableView();
table->initWithViewSize(size, container);
table->autorelease();
table->setDataSource(dataSource);
table->_updateCellPositions();
table->_updateContentSize();
return table;
}
bool CCTableView::initWithViewSize(CCSize size, CCNode* container/* = NULL*/)
{
if (CCScrollView::initWithViewSize(size,container))
{
m_pCellsUsed = new CCArrayForObjectSorting();
m_pCellsFreed = new CCArrayForObjectSorting();
m_pIndices = new std::set();
m_eVordering = kCCTableViewFillBottomUp;
this->setDirection(kCCScrollViewDirectionVertical);
CCScrollView::setDelegate(this);
return true;
}
return false;
}
void CCTableView::_updateCellPositions() {
//根据dataSource,更新cell的位置。
int cellsCount = m_pDataSource->numberOfCellsInTableView(this);
m_vCellsPositions.resize(cellsCount + 1, 0.0);
if (cellsCount > 0)
{
float currentPos = 0;
CCSize cellSize;
for (int i=0; i < cellsCount; i++)
{
m_vCellsPositions[i] = currentPos;
CCLog("The postion is %f",currentPos);
//根据idx获取到相应cell的size
cellSize = m_pDataSource->tableCellSizeForIndex(this, i);
switch (this->getDirection())
{
case kCCScrollViewDirectionHorizontal:
currentPos += cellSize.width;
break;
default:
currentPos += cellSize.height;
break;
}
}
//n个cell需要n+1个Pos 来指定位置
m_vCellsPositions[cellsCount] = currentPos;//1 extra value allows us to get right/bottom of the last cell
CCLog("The postion is %f",currentPos);
}
}
void CCTableView::_updateContentSize()
{
CCSize size = CCSizeZero;
unsigned int cellsCount = m_pDataSource->numberOfCellsInTableView(this);
//获取到最大的长与宽
if (cellsCount > 0)
{
float maxPosition = m_vCellsPositions[cellsCount];
switch (this->getDirection())
{
case kCCScrollViewDirectionHorizontal:
size = CCSizeMake(maxPosition, m_tViewSize.height);
break;
default:
size = CCSizeMake(m_tViewSize.width, maxPosition);
break;
}
}
//获取后调用CCScrollView的setContenSize
this->setContentSize(size);
//调整方向与初始偏移offset
if (m_eOldDirection != m_eDirection)
{
if (m_eDirection == kCCScrollViewDirectionHorizontal)
{
this->setContentOffset(ccp(0,0));
}
else
{
//这里其实不是很懂
this->setContentOffset(ccp(0,this->minContainerOffset().y));
}
m_eOldDirection = m_eDirection;
}
}
void CCTableView::scrollViewDidScroll(CCScrollView* view)
{
//继承自CCScrollViewDelegate,并且根据CCScrollView的源码,每次移动时(setContentOffset函数),都会调用这个函数
//没有任何元素
unsigned int uCountOfItems = m_pDataSource->numberOfCellsInTableView(this);
if (0 == uCountOfItems)
{
return;
}
//tableviewdelegate的DidScroll调用
if(m_pTableViewDelegate != NULL) {
m_pTableViewDelegate->scrollViewDidScroll(this);
}
unsigned int startIdx = 0, endIdx = 0, idx = 0, maxIdx = 0;
//需要乘以-1的原因很简单,当offset处于正数时,即为cell在初始位置还要往右拉,此时得到的startIdx肯定是不存在的。
CCPoint offset = ccpMult(this->getContentOffset(), -1);
maxIdx = MAX(uCountOfItems-1, 0);
if (m_eVordering == kCCTableViewFillTopDown)
{
offset.y = offset.y + m_tViewSize.height/this->getContainer()->getScaleY();
}
//查到起始的startIdx
startIdx = this->_indexFromOffset(offset);
//CCLog("The offset is %f",offset.x);
//CCLog("The start index is %d",startIdx);
if (startIdx == CC_INVALID_INDEX)
{
startIdx = uCountOfItems - 1;
}
if (m_eVordering == kCCTableViewFillTopDown)
{
offset.y -= m_tViewSize.height/this->getContainer()->getScaleY();
}
else
{
offset.y += m_tViewSize.height/this->getContainer()->getScaleY();
}
//起始offset加上显示View的宽度就是endIdx的offset
offset.x += m_tViewSize.width/this->getContainer()->getScaleX();
endIdx = this->_indexFromOffset(offset);
//如果endIdx 超过,则将endIdx置为最大值
if (endIdx == CC_INVALID_INDEX)
{
endIdx = uCountOfItems - 1;
}
if(startIdx > endIdx)
{
int tmp = startIdx;
startIdx = endIdx;
endIdx = tmp;
}
if (m_pCellsUsed->count() > 0)
{
CCTableViewCell* cell = (CCTableViewCell*)m_pCellsUsed->objectAtIndex(0);
//找出正在使用的cell,只要是idx小于startIdx的,就移出。
idx = cell->getIdx();
while(idx _moveCellOutOfSight(cell);
if (m_pCellsUsed->count() > 0)
{
cell = (CCTableViewCell*)m_pCellsUsed->objectAtIndex(0);
idx = cell->getIdx();
}
else
{
break;
}
}
}
if (m_pCellsUsed->count() > 0)
{
CCTableViewCell *cell = (CCTableViewCell*)m_pCellsUsed->lastObject();
idx = cell->getIdx();
//同上,移除所有大于endIdx的cell
while(idx <= maxIdx && idx > endIdx)
{
this->_moveCellOutOfSight(cell);
if (m_pCellsUsed->count() > 0)
{
cell = (CCTableViewCell*)m_pCellsUsed->lastObject();
idx = cell->getIdx();
}
else
{
break;
}
}
}
//更新在start和end之间的cell
for (unsigned int i=startIdx; i <= endIdx; i++)
{
//if ([m_pIndices containsIndex:i]),indices存在即表明该位置上的cell已经被update。
if (m_pIndices->find(i) != m_pIndices->end())
{
continue;
}
this->updateCellAtIndex(i);
}
}
unsigned int CCTableView::_indexFromOffset(CCPoint offset)
{
int index = 0;
const int maxIdx = m_pDataSource->numberOfCellsInTableView(this)-1;
//如果是垂直方向上,并且是TopDown的,则改变offset.y
if (m_eVordering == kCCTableViewFillTopDown)
{
offset.y = this->getContainer()->getContentSize().height - offset.y;
}
//获取该点处于哪个index中
index = this->__indexFromOffset(offset);
if (index != -1)
{
index = MAX(0, index);
if (index > maxIdx)
{
index = CC_INVALID_INDEX;
}
}
return index;
}
int CCTableView::__indexFromOffset(CCPoint offset)
{
int low = 0;
int high = m_pDataSource->numberOfCellsInTableView(this) - 1;
float search;
//根据方向来判断需要寻找的是x还是y坐标
switch (this->getDirection())
{
case kCCScrollViewDirectionHorizontal:
search = offset.x;
break;
default:
search = offset.y;
break;
}
//二分查找,找出点在哪个cell的区间内,返回index
while (high >= low)
{
int index = low + (high - low) / 2;
float cellStart = m_vCellsPositions[index];
float cellEnd = m_vCellsPositions[index + 1];
CCLog("The start cell is %f",cellStart);
if (search >= cellStart && search <= cellEnd)
{
return index;
}
else if (search < cellStart)
{
high = index - 1;
}
else
{
low = index + 1;
}
}
if (low <= 0) {
return 0;
}
//结果是-1则表示超出最大距离,在外部将被赋值为最大距离
return -1;
}
void CCTableView::_moveCellOutOfSight(CCTableViewCell *cell)
{
//此时调用delegate方法。cellWillCycle
if(m_pTableViewDelegate != NULL) {
m_pTableViewDelegate->tableCellWillRecycle(this, cell);
}
//做数据处理
m_pCellsFreed->addObject(cell);
m_pCellsUsed->removeSortedObject(cell);
m_pIndices->erase(cell->getIdx());
// [m_pIndices removeIndex:cell.idx];
cell->reset();
if (cell->getParent() == this->getContainer()) {
this->getContainer()->removeChild(cell, true);;
}
}
void CCTableView::updateCellAtIndex(unsigned int idx)
{
if (idx == CC_INVALID_INDEX)
{
return;
}
unsigned int uCountOfItems = m_pDataSource->numberOfCellsInTableView(this);
if (0 == uCountOfItems || idx > uCountOfItems-1)
{
return;
}
//首先将cell移除used
CCTableViewCell* cell = this->cellAtIndex(idx);
if (cell)
{
this->_moveCellOutOfSight(cell);
}
//调用该方法,根据idx获取新cell
cell = m_pDataSource->tableCellAtIndex(this, idx);
//设置cell
this->_setIndexForCell(idx, cell);
//将cell加到used中
this->_addCellIfNecessary(cell);
}
void CCTableView::_setIndexForCell(unsigned int index, CCTableViewCell *cell)
{
//设置cell的锚点,位置与idx
cell->setAnchorPoint(ccp(0.0f, 0.0f));
cell->setPosition(this->_offsetFromIndex(index));
CCLog("The cell position is %f",this->_offsetFromIndex(index).x);
cell->setIdx(index);
}
void CCTableView::_addCellIfNecessary(CCTableViewCell * cell)
{
if (cell->getParent() != this->getContainer())
{
this->getContainer()->addChild(cell);
}
m_pCellsUsed->insertSortedObject(cell);
m_pIndices->insert(cell->getIdx());
// [m_pIndices addIndex:cell.idx];
}
bool CCTableView::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
if (!this->isVisible()) {
return false;
}
//父类的ccTouchBegan调用,可以获取touches的多少,并且判断出行为
bool touchResult = CCScrollView::ccTouchBegan(pTouch, pEvent);
//啊哦,tableview不支持缩放了哦,只支持滚动
if(m_pTouches->count() == 1) {
unsigned int index;
CCPoint point;
//获取touch在该TableView坐标系下的CCpoint
point = this->getContainer()->convertTouchToNodeSpace(pTouch);
//获取该point在数据中的位置
index = this->_indexFromOffset(point);
//获取在该index上的tableviewCell
if (index == CC_INVALID_INDEX)
{
m_pTouchedCell = NULL;
}
else
{
m_pTouchedCell = this->cellAtIndex(index);
}
//如果该cell存在并且delegate存在,调用delegate的方法,比如说可以pressed
if (m_pTouchedCell && m_pTableViewDelegate != NULL) {
m_pTableViewDelegate->tableCellHighlight(this, m_pTouchedCell);
}
}
//当触摸点个数不为1,但是存在正在触摸的cell时,将该cell置空,并且调用取消高亮的方法比如说unpressed
else if(m_pTouchedCell) {
if(m_pTableViewDelegate != NULL) {
m_pTableViewDelegate->tableCellUnhighlight(this, m_pTouchedCell);
}
m_pTouchedCell = NULL;
}
return touchResult;
}
void CCTableView::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
{
//先调用父类的move
CCScrollView::ccTouchMoved(pTouch, pEvent);
//如果移动过程中还存在触摸的cell,则置空并调用delegate
if (m_pTouchedCell && isTouchMoved()) {
if(m_pTableViewDelegate != NULL) {
m_pTableViewDelegate->tableCellUnhighlight(this, m_pTouchedCell);
}
m_pTouchedCell = NULL;
}
}
void CCTableView::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
if (!this->isVisible()) {
return;
}
//move距离过短,则识别为触摸到cell的动作并获取到该cell,调用Delegate的方法。
if (m_pTouchedCell){
CCRect bb = this->boundingBox();
bb.origin = m_pParent->convertToWorldSpace(bb.origin);
if (bb.containsPoint(pTouch->getLocation()) && m_pTableViewDelegate != NULL)
{
m_pTableViewDelegate->tableCellUnhighlight(this, m_pTouchedCell);
m_pTableViewDelegate->tableCellTouched(this, m_pTouchedCell);
}
m_pTouchedCell = NULL;
}
CCScrollView::ccTouchEnded(pTouch, pEvent);
}
void CCTableView::reloadData()
{
m_eOldDirection = kCCScrollViewDirectionNone;
CCObject* pObj = NULL;
CCARRAY_FOREACH(m_pCellsUsed, pObj)
{
CCTableViewCell* cell = (CCTableViewCell*)pObj;
if(m_pTableViewDelegate != NULL) {
m_pTableViewDelegate->tableCellWillRecycle(this, cell);
}
m_pCellsFreed->addObject(cell);
cell->reset();
if (cell->getParent() == this->getContainer())
{
this->getContainer()->removeChild(cell, true);
}
}
m_pIndices->clear();
m_pCellsUsed->release();
m_pCellsUsed = new CCArrayForObjectSorting();
this->_updateCellPositions();
this->_updateContentSize();
if (m_pDataSource->numberOfCellsInTableView(this) > 0)
{
this->scrollViewDidScroll(this);
}
}
void CCTableView::refreshData()
{
int startIndex = 0;
int endIndex = 0;
// 取出当前可见的item的收尾索引
getStartEndIndex(startIndex, endIndex);
// 只刷新看见的item
//unsigned int uCountOfItems = m_pDataSource->numberOfCellsInTableView(this);
for(unsigned int i = startIndex; i <= endIndex; ++i)
{
this->updateCellAtIndex(i);
}
}