Cocos2d-x source code analysis of CCTableView source code (with discussion)

Source: Internet
Author: User

Cocos2d-x source code directory

Http://blog.csdn.net/u011225840/article/details/31743129


The source code is from 2.x. For more information, see


1. Inheritance Structure

First, let's take a look at the inherited structure of CCTableView.

In terms of the inheritance structure, CCTableView is a CCScrollView. To study the source code of CCTableView, read the source code of CCScrollView http://blog.csdn.net/u042425840/article/details/30033501. Secondly, CCTableView inherits CCScrollViewDelegate. From the source code analysis, we can see that it is mainly used to implement the scrollViewDidScroll function. In this way, you can perform operations on the CCScrollView itself when you scroll through the CCScrollView. (If you do not understand the source code, you must first understand the source code of CCScrollView .) Finally, in addition to the inheritance structure, we also need to understand three important classes. CCTableViewCell, CCTableViewDelegate, and CCTableViewDataSource. Using these three classes, CCTableView decouples data from other operations.
2. Analysis of related classes 2.1CCTableViewCellCCtableViewCell mainly contains a unique identifier, allowing TableView to update TableviewCell through different idx. Generally, a CustomCell will be written to inherit the class. The Cell contains the style of each cell (including label? Contains sprite? All implemented in this cell)

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 <code>idx</code> property.     */    void reset();    void setObjectID(unsigned int uIdx);    unsigned int getObjectID();private:    unsigned int m_uIdx;};


2.2CCTableViewDataSourceCCTableViewDataSource is a very important class. The data processing of TableView is related to this class. Please refer to the four functions provided by TableView. The comments have been provided. In general, we will let a m class inherit from it and implement the method. This M class generally inherits DataSource, TableViewDelegate, and a CClayer, and contains a CCTableView. (At the end of the article, I will give an example ).
// Tell tableview cell size based on different idx virtual CCSize tableCellSizeForIndex (CCTableView * table, unsigned int idx) {return cellSizeForTable (table );}; // provides a general method to show the cell size of a table. If the cell size of the table is the same, the cells are generally the same .. Virtual CCSize cellSizeForTable (CCTableView * table) {return CCSizeZero;}; // obtain the corresponding cell of the table based on different idx. This method will be explained in detail when analyzing the dequeceCell of the table. Virtual CCTableViewCell * tableCellAtIndex (CCTableView * table, unsigned int idx) = 0; // return the number of cells in the table. Virtual unsigned int numberOfCellsInTableView (CCTableView * table) = 0;


2.3 CCTableViewDelegate
Several Delegate functions are provided for TableView. The Delegate usage is described in the source code analysis of CCScrollView.
Virtual void tableCellTouched (CCTableView * table, CCTableViewCell * cell) = 0;
This function must be implemented. This method is called when the table obtains that the user is touching the cell through idx. (After selecting an object, put it on the character. This method is used to respond .)
3. CCTableView Source Code Analysis 3.1 when it is created, CCTableView provides two create functions: create (CCTableViewDataSource * dataSource, CCSize size); create (CCTableViewDataSource * dataSource, CCSize size, CCNode * container); the first function, the second one is called and the container is set to NULL. Next let's look at the second function.
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;}

Isn't the heap memory insufficient. Three important functions are found: 3.1.1 initWithViewSize
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<unsigned int>();        m_eVordering      = kCCTableViewFillBottomUp;        this->setDirection(kCCScrollViewDirectionVertical);        CCScrollView::setDelegate(this);        return true;    }    return false;}

CellsUsed is used to store cells that are in use and displayed on The view. CellsFreed is used to store cells that are not currently used and are not displayed on the view (removed from cellsUsed and added to cellsFreed). cellsFreed provides a caching mechanism. Allow us to get cells from tableCellAtIndex without re-creating them. We only need to update the display according to idx. Indices is used to store the region value that each cell should occupy.
3.1.2 _ updateCellPositions
Assign values to indices based on the orientation and order of CCTableView.
Void CCTableView: _ updateCellPositions () {// update the cell location based on dataSource. 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 ); // obtain the size cellSize = m_pDataSource-> tableCellSizeForIndex (this, I); switch (this-> getDirection () {case kccscrollviewdirehorizontal: currentPos + = cellSize according to idx. width; break; default: currentPos + = cellSize. height; break ;}// n + 1 Pos are required for n cells to specify the position m_vCellsPositions [cellsCount] = currentPos; // 1 extra value allows us to get right/bottom of the last cellCCLog ("The postion is % f", currentPos );}}


3.1.3 _ updateContentSize
This method adjusts the size and offset of CCTableView. (Note that the scrollViewDidScroll method is called when the offset is adjusted .)
Void CCTableView: _ updateContentSize () {CCSize size = CCSizeZero; unsigned int cellsCount = m_pDataSource-> numberOfCellsInTableView (this ); // obtain the maximum length and width if (cellsCount> 0) {float maxPosition = m_vCellsPositions [cellsCount]; switch (this-> getDirection () {case kccscrollviewdirehorizontal: size = CCSizeMake (maxPosition, m_tViewSize.height); break; default: size = CCSizeMake (m_tViewSize.width, ma XPosition); break ;}/// call setContenSize of CCScrollView after obtaining this-> setContentSize (size); // adjust the direction and initial offset offsetif (m_eOldDirection! = M_eDirection) {if (m_eDirection = kccscrollviewdirehorhorizontal) {this-> setContentOffset (ccp (0, 0 ));} else {// this is not really familiar with this-> setContentOffset (ccp (0, this-> minContainerOffset (). y);} m_eOldDirection = m_eDirection ;}}

As shown in the comment, I have a small problem. If it is in the vertical direction, it will put the initial position on minContainerOffset. Why...

The following section focuses on scrollviewDidScroll.

3.2 When scrolling, The scrollviewDidScroll method is called every time an offset is set based on the parent class CCScrollView.
Void CCTableView: scrollViewDidScroll (CCScrollView * view) {// inherits from CCScrollViewDelegate, and according to the source code of CCScrollView, each time it is moved (setContentOffset function ), will call this function // No element unsigned int uCountOfItems = m_pDataSource-> numberOfCellsInTableView (this); if (0 = uCountOfItems) {return ;} // DidScroll of tableviewdelegate calls if (m_pTableViewDelegate! = NULL) {m_pTableViewDelegate-> scrollViewDidScroll (this);} unsigned int startIdx = 0, endIdx = 0, idx = 0, maxIdx = 0; // The reason for multiplying the value by-1 is very simple. When the offset value is in a positive value, that is, the cell is pulled to the right at the initial position, and the startIdx obtained in this case does not exist. 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 ();} // check the start startIdx = this-> _ indexFromOffset (offset ); // CCLog ("The offset is % f", offset. x); // CCLog ("The start index is % d", startIdx); if (startIdx = CC_INVALID_INDEX) {startIdx = uCou NtOfItems-1;} if (m_eVordering = kCCTableViewFillTopDown) {offset. y-= m_tViewSize.height/this-> getContainer ()-> getScaleY ();} else {offset. y + = m_tViewSize.height/this-> getContainer ()-> getScaleY ();} // The start offset plus the display View width is the offset of endIdx. x + = m_tViewSize.width/this-> getContainer ()-> getScaleX (); endIdx = this-> _ indexFromOffset (offset); // If endIdx exceeds, set endIdx to the maximum value 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); // find the cell in use. If idx is smaller than startIdx, remove it. Idx = cell-> getIdx (); while (idx <startIdx) {this-> _ 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 (); // same as above, remove all cell while (idx <= maxIdx & idx> endIdx) {th Is-> _ moveCellOutOfSight (cell); if (m_pCellsUsed-> count ()> 0) {cell = (CCTableViewCell *) m_pCellsUsed-> lastObject (); idx = cell-> getIdx () ;}else {break ;}}// update the cell for (unsigned int I = startIdx; I <= endIdx; I ++) {// if ([m_pIndices containsIndex: I]), if indices exists, it indicates that the cell at the position has been updated. If (m_pIndices-> find (I )! = M_pIndices-> end () {continue;} this-> updateCellAtIndex (I );}}


In this function, three internal functions are called:
3.2.1 _ indexFromOffset
Unsigned int CCTableView: _ indexFromOffset (CCPoint offset) {int index = 0; const int maxIdx = m_pDataSource-> numberOfCellsInTableView (this)-1; // if it is in the vertical direction, if it is TopDown, the offset is changed. y if (m_eVordering = kCCTableViewFillTopDown) {offset. y = this-> getContainer ()-> getContentSize (). height-offset. y;} // obtain the index in which the vertex is located. 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; // determine whether the x or y coordinate switch (this-> getDirection () to be searched based on the direction {case kccscrollviewdirehorizontal: search = offset. x; break; default: search = offset. y; break;} // binary search, locate the cell in which the vertex is located, and Return 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 ;}< span style = "white-space: pre "> </span> // if the result is-1, the maximum distance is exceeded, and the outer part is assigned the maximum distance return-1 ;}

3.2.2 _ moveCellOutOfSight
Void CCTableView: _ moveCellOutOfSight (CCTableViewCell * cell) {// call the delegate method at this time. CellWillCycle if (m_pTableViewDelegate! = NULL) {m_pTableViewDelegate-> tableCellWillRecycle (this, cell);} // process data 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 );;}}

3.2.3 updateCellAtIndex
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;} // first remove the cell used CCTableViewCell * cell = this-> cellAtIndex (idx); if (cell) {this-> _ moveCellOutOfSight (cell) ;}// call this method and obtain the new cell = m_pDataSource-> tableCellAtIndex (this, idx) based on idx ); // set cell this-> _ setIndexForCell (idx, cell); // Add cell to used this-> _ addCellIfNecessary (cell );}

We can see that during update, all cells are removed first, and then updated by tableCellAtIndex of dataSource. If you do not set the cache freed, it will cause a performance bottleneck.
Void CCTableView: _ setIndexForCell (unsigned int index, CCTableViewCell * cell) {// set the cell's anchor, location and 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];}


Here, the focus of CCTableView is basically finished. Continue.

3.3 touch
3.3.1 ccTouchBegan
Bool CCTableView: ccTouchBegan (CCTouch * pTouch, CCEvent * pEvent) {if (! This-> isVisible () {return false;} // The ccTouchBegan call to the parent class can obtain the touches quantity and determine whether the trip is bool touchResult = CCScrollView: ccTouchBegan (pTouch, pEvent); // ah, tableview does not support scaling. It only supports scrolling if (m_pTouches-> count () = 1) {unsigned int index; CCPoint; // obtain the CCpoint point = this-> getContainer ()-> convertTouchToNodeSpace (pTouch) of touch in the TableView coordinate system ); // obtain the position of the point in the Data index = this-> _ indexFromOffset (point); // obtain the tab on the index LeviewCellif (index = CC_INVALID_INDEX) {m_pTouchedCell = NULL;} else {m_pTouchedCell = this-> cellAtIndex (index);} // if the cell exists and delegate exists, call the delegate method. For example, you can use pressed if (m_pTouchedCell & m_pTableViewDelegate! = NULL) {m_pTableViewDelegate-> tableCellHighlight (this, m_pTouchedCell) ;}// when the number of touch points is not 1, but there is a cell being touched, set this cell to NULL, and call the method to cancel the highlight, for example, unpressed else if (m_pTouchedCell) {if (m_pTableViewDelegate! = NULL) {m_pTableViewDelegate-> tableCellUnhighlight (this, m_pTouchedCell);} m_pTouchedCell = NULL;} return touchResult ;}


3.3.2 ccTouchMoved
Void CCTableView: ccTouchMoved (CCTouch * pTouch, CCEvent * pEvent) {// first call the move CCScrollView of the parent class: ccTouchMoved (pTouch, pEvent ); // if a cell is still touched during the movement, leave it empty and call delegate if (m_pTouchedCell & isTouchMoved () {if (m_pTableViewDelegate! = NULL) {m_pTableViewDelegate-> tableCellUnhighlight (this, m_pTouchedCell);} m_pTouchedCell = NULL ;}}

3.3.3 ccTouchEnded
Void CCTableView: ccTouchEnded (CCTouch * pTouch, CCEvent * pEvent) {if (! This-> isVisible () {return;} // If the moving distance is too short, the cell touch action is identified and the cell is obtained, and the Delegate method is called. If (m_pTouchedCell) {CCRect bb = this-> boundingBox (); bb. origin = m_pParent-> convertToWorldSpace (bb. origin); if (bb. containsPoint (pTouch-> getLocation () & m_pTableViewDelegate! = NULL) {response-> tableCellUnhighlight (this, m_pTouchedCell); response-> tableCellTouched (this, m_pTouchedCell);} m_pTouchedCell = NULL;} CCScrollView: ccTouchEnded (pTouch, pEvent );}

3.4 Common Operations
3.4.1 reloadData
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);    }}

When your data source changes, call reloadData. We can see that he recalculates data-related operations.
3.4.2 refreshData
Void CCTableView: refreshData () {int startIndex = 0; int endIndex = 0; // retrieve the final index getStartEndIndex (startIndex, endIndex) of the currently visible item ); // only refresh the expected item // unsigned int uCountOfItems = m_pDataSource-> numberOfCellsInTableView (this); for (unsigned int I = startIndex; I <= endIndex; ++ I) {this-> updateCellAtIndex (I );}}

The difference is obvious. The data source has not changed, but the startIndex and endIndex have changed and are updated and displayed.

4. Conclusion 1. Three Friends of CCTableView: CCTableViewCell, responsible for a single cell, containing a unique idx for difference. CCTableViewDataSource is responsible for data sources, including data count, data acquisition based on different idx, and data size. CCTableViewDelegate, responsible for delegate operations. 2. CCTableView not only inherits CCScrollView, but also CCScrollViewDelegate.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.