The source code is from 2.x. For more information, see
1. inherit the Tree Structure
It can be seen that CCScrollView is essentially a CCLayer and has all the attributes and methods of the layer. The source code analysis of CCLayer will be available in the future. 2. Important members
1.
CCScrollViewDelegate * m_pDelegate;
A lot of delegate Patterns are used in cocos2d-x. The following describes the delegate mode. (For the differences between delegate and proxy, please refer to the three cases of proxy in headfirst, and then google differences. I will not go into details here .) XXXDelegate encapsulates interfaces (implementations in c ++ are virtual functions and pure virtual functions that must be implemented). Some methods exist in Class A, such as getDataNum in View, view determines the display mode of the interface based on the amount of data, but A is not directly associated with the data. Therefore, getDataNum in View A calls the DataDelegate method in View A to obtain the amount of data. As to what the data is, you only need to implement a specific class of DataDelegate. In this way, the coupling between views and data is very low. View only depends on the abstract DataDelegate. In the subsequent source code analysis, we can see the beauty of delegate.
3. source code parsing 3.1 ccTouchBegan
For the important part of ccTouchBegan, I added a comment. The Code shows that CCscrollView supports single point and double point touch.
Bool CCScrollView: ccTouchBegan (CCTouch * touch, CCEvent * event) {if (! This-> isVisible () |! M_bCanTouch) {return false;} CCRect frame = getViewRect (); // dispatcher does not know about clipping. reject touches outside visible bounds. /* 1. ccScrollView only allows up to two touch points. If there are more than two touch points, it will not be considered as a touch. 2. When the CCScrollView is in the moving status, a new touch in this status will not be considered. 3. note that the frame is not the current size, but the current ViewSize frame, that is, the touch point must be recognized as a touch within the displayed Rect (you can set the size through setViewSize) */if (m_pTouches-> count ()> 2 | m_bTouchMoved |! Frame. containsPoint (m_pContainer-> convertToWorldSpace (m_pContainer-> convertTouchToNodeSpace (touch) {m_pTouches-> removeAllObjects (); return false;} if (! M_pTouches-> containsObject (touch) {m_pTouches-> addObject (touch);} // CCLOG ("CCScrollView: ccTouchBegan % d", m_pTouches-> count ()); /* set the single-touch attribute when the touch point is 1. In particular, the m_bDragging attribute indicates that the touch action is to drag */if (m_pTouches-> count () = 1) {// scrolling m_tTouchPoint = this-> convertTouchToNodeSpace (touch ); m_bTouchMoved = false; m_bDragging = true; // dragging started m_tScrollDistance = ccp (0.0f, 0.0f); m_fTouchLength = 0.0f;}/* when the number of touch points is 2, set double-point touch properties */else if (m_pTouches-> count () = 2) {m_tTouchPoint = ccpMidpoint (this-> convertTouchToNodeSpace (CCTouch *) m_pTouches-> objectAtIndex (0), this-> convertTouchToNodeSpace (CCTouch *) m_pTouches-> objectAtIndex (1 ))); m_fTouchLength = ccpDistance (m_pContainer-> convertTouchToNodeSpace (CCTouch *) m_pTouches-> objectAtIndex (0), m_pContainer-> convertTouchToNodeSpace (CCTouch *) m_pTouches-> objectAtIndex (1); m_bDragging = false;} return true ;}
3.2 ccTouchMoved is the same as above. Comments are added to the Code.
Void CCScrollView: ccTouchMoved (CCTouch * touch, CCEvent * event) {if (! This-> isVisible () {return;}/* exit if scrolling is not allowed at this time. This can be set through the set function. The default value is false */if (this-> m_bScrollLock) {return;} if (m_pTouches-> containsObject (touch. When rolling status */if (m_pTouches-> count () = 1 & m_bDragging) {// scrolling CCPoint moveDistance, newPoint, maxInset, minInset; CCRect frame; float newX, newY; frame = getViewRect (); // obtain the coordinates of the current vertex, and obtain the distance between the current vertex and the last touch vertex (moveDistance is also a CCPoint, the distance between x and y is the distance between the current point and the previous point, and y) newPoint = this-> convertTouchToNodeSpace (CCTouch *) m_pTouches-> objectAtIndex (0 )); moveDistance = ccpSub (newPoint, m_tTouchPoint); float dis = 0.0f; // if there is a direction Limitation. obtain the corresponding distance if (m_eDirection = kCCScrollViewDirectionVertical) {dis = moveDistance according to the direction limitation. y;} else if (m_eDirection = kccscrollviewdirehorhorizontal) {dis = moveDistance. x;} else {dis = sqrtf (moveDistance. x * moveDistance. x + moveDistance. y * moveDistance. y);} // if the moving distance is too short, the moving if (! M_bTouchMoved & fabs (convertDistanceFromPointToInch (dis) <MOVE_INCH) {// CCLOG ("Invalid movement, distance = [% f, % f], disInch = % f", moveDistance. x, moveDistance. y); return;} // if it is moved for the first time, set moveDistance to 0 if (! M_bTouchMoved) {moveDistance = CCPointZero;} m_tTouchPoint = newPoint; m_bTouchMoved = true; // The point must be inside viewRect if (frame. containsPoint (this-> convertToWorldSpace (newPoint) {// set moveDistance switch (m_eDirection) {case kccscrollviewdirevertical: moveDistance = ccp (0.0f, moveDistance. y); break; case kCCScrollViewDirectionHorizontal: moveDistance = ccp (moveDistance. x, 0.0f); B Reak; default: break;} // This version is useless .... MaxInset = m_fMaxInset; minInset = m_fMinInset; // get the new coordinates of the container. Note that it is the container. newX = m_pContainer-> getPosition (). x + moveDistance. x; newY = m_pContainer-> getPosition (). y + moveDistance. y; // set m_tScrollDistance = moveDistance for the scrolled CCPoint vector; this-> setContentOffset (ccp (newX, newY);} // when the two-point touch occurs, the effect is scaling, len is the distance when the double-point touch moves each time, // while m_fTouchLength is the distance when the double-point starts, else if (m_pTouches-> count () = 2 &&! M_bDragging) {const float len = ccpDistance (m_pContainer-> values (CCTouch *) m_pTouches-> objectAtIndex (0), m_pContainer-> convertTouchToNodeSpace (CCTouch *) m_pTouches-> objectAtIndex (1); this-> setZoomScale (this-> getZoomScale () * len/m_fTouchLength );}}}A single-point touch function is called setContentOffset. Next we will continue to analyze contentOffset.
SetContentOffset
Void CCScrollView: setContentOffset (CCPoint offset, bool animated/* = false */) {// by default, if (animated) is not processed) {// animate scrolling this-> setContentOffsetInDuration (offset, BOUNCE_DURATION);} // else {// set the container position directly // whether to perform out-of-bounds processing, what is out-of-bounds? When you drag the entire container, if you have reached the container boundary, can you drag it again? You can use the set function to set if (! M_bBounceable) {const CCPoint minOffset = this-> minContainerOffset (); const CCPoint maxOffset = this-> maxContainerOffset (); offset. x = MAX (minOffset. x, MIN (maxOffset. x, offset. x); offset. y = MAX (minOffset. y, MIN (maxOffset. y, offset. y);} // CCLOG ("The offset x is % f, y is % f", offset. x, offset. y); m_pContainer-> setPosition (offset); // The Great delegate comes. When you want to perform additional operations in addition to the basic interface scrolling, implement the delegate ~ according to your own situation ~ Perfect dependency abstraction design, nice if (m_pDelegate! = NULL) {m_pDelegate-> scrollViewDidScroll (this );}}}
An important function setZoomScale is called during double-point touch. SetZoomScale
Void CCScrollView: setZoomScale (float s) {if (m_pContainer-> getScale ()! = S) {CCPoint oldCenter, newCenter; CCPoint center; // set the zoom center if (m_fTouchLength = 0.0f) {center = ccp (m_tViewSize.width * 0.5f, m_tViewSize.height * 0.5f ); center = this-> convertToWorldSpace (center);} else {center = m_tTouchPoint;} // offset is generated when the center position is scaled relative to the world coordinate system, here, offset is calculated for oldCenter = m_pContainer-> convertToNodeSpace (center); m_pContainer-> setScale (MAX (m_fMinScale, MIN (m_fMaxScale, s); newCe Nter = m_pContainer-> convertToWorldSpace (oldCenter); const CCPoint offset = ccpSub (center, newCenter); // if (m_pDelegate! = NULL) {m_pDelegate-> scrollViewDidZoom (this);} // process the generated offset this-> setContentOffset (ccpAdd (m_pContainer-> getPosition (), offset ));}}
3.3 ccTouchEnded can insist on seeing this. Now we can see the dawn of victory...
Void CCScrollView: ccTouchEnded (CCTouch * touch, CCEvent * event) {if (! This-> isVisible () {return;} // remove if (m_pTouches-> containsObject (touch) from pTouches {// when there is one touch left, call the method when (m_pTouches-> count () = 1 & m_bTouchMoved) {this-> schedule (schedule_selector (CCScrollView: deaccelerateScrolling) in each frame ));} m_pTouches-> removeObject (touch); // CCLOG ("CCScrollView: ccTouchEnded % d", m_pTouches-> count (); // m_pDelegate-> scrollViewDidStop (this );} // when there is no touch, you need to set the status if (m_pTouches-> count () = 0) {m_bDragging = false; m_bTouchMoved = false ;}}DeaccelerateScrolling
In this function, there is something I don't understand.
Void CCScrollView: deaccelerateScrolling (float dt) {// if a began occurs at another touch point just before the start of the frame, causing the scroll status, the cancellation and return if (m_bDragging) {this-> unschedule (schedule_selector (CCScrollView: deaccelerateScrolling); return ;}// float newX, newY; CCPoint maxInset, minInset; CCLOG ("The end distance is % f", m_tScrollDistance.x); // I don't know why it is coming out here. I used The output to find that The offset has been set in move, I don't know why I need to set it up. M_pContainer-> setPosition (ccpAdd (m_pContainer-> getPosition (), m_tScrollDistance); // whether to allow cross-border access. The obtained inset information if (m_bBounceable) {maxInset = m_fMaxInset; minInset = m_fMinInset;} else {maxInset = this-> maxContainerOffset (); minInset = this-> minContainerOffset ();} // check to see if offset lies within the inset bounds newX = MIN (m_pContainer-> getPosition (). x, maxInset. x); newX = MAX (newX, minInset. x ); NewY = MIN (m_pContainer-> getPosition (). y, maxInset. y); newY = MAX (newY, minInset. y); newX = m_pContainer-> getPosition (). x; newY = m_pContainer-> getPosition (). y; m_tScrollDistance = ccpSub (m_tScrollDistance, ccp (newX-m_pContainer-> getPosition (). x, newY-m_pContainer-> getPosition (). y); m_tScrollDistance = ccpMult (m_tScrollDistance, SCROLL_DEACCEL_RATE); this-> setContentOffset (ccp (newX, newY); if (Fabsf (m_tScrollDistance.x) <= SCROLL_DEACCEL_DIST & fabsf (m_tScrollDistance.y) <= SCROLL_DEACCEL_DIST) | newY> maxInset. y | newY <minInset. y | newX> maxInset. x | newX <minInset. x | newX = maxInset. x | newX = minInset. x | newY = maxInset. y | newY = minInset. y) {this-> unschedule (schedule_selector (CCScrollView: deaccelerateScrolling); // a function that moves slowly from the out-of-bounds part to the function that is not out-of-bounds. This-> relocateContainer (true); // great delegate... M_pDelegate-> scrollViewDidStop (this );}}
RelocateContainer
Void CCScrollView: relocateContainer (bool animated) {// This function moves the container from the current location to the allowed offset location set by the player through animation CCPoint oldPoint, min, max; float newX, newY; // you can set min = this-> minContainerOffset (); max = this-> maxContainerOffset (); oldPoint = m_pContainer-> getPosition (); newX = oldPoint. x; newY = oldPoint. y; if (m_eDirection = kccscrollviewdiredireboth | m_eDirection = kccscrollviewdirehorizontal) {newX = MAX (newX, min. x); newX = MIN (newX, max. x);} if (m_eDirection = kCCScrollViewDirectionBoth | m_eDirection = kCCScrollViewDirectionVertical) {newY = MIN (newY, max. y); newY = MAX (newY, min. y);} // still call setContentOffset, but the animation if (newY! = OldPoint. y | newX! = OldPoint. x) {this-> setContentOffset (ccp (newX, newY), animated );}}
SetContentOffsetInDuration
Void CCScrollView: setContentOffsetInDuration (CCPoint offset, float dt) {CCFiniteTimeAction * scroll, * expire; // scroll = CCMoveTo: create (dt, offset ); // The animation after rolling (responsible for stopping the performedAnimatedScroll and calling delegate) expire = CCCallFuncN: create (this, callfuncN_selector (CCScrollView: stoppedAnimatedScroll )); m_pContainer-> runAction (CCSequence: create (scroll, expire, NULL); // call delegate this-> schedule (schedule_selector (CCScrollView: Invalid medanimatedscroll ));}
4. here we can see that the content of CCScrollView's unique part has basically been read. It can be seen that: 1. CCScrollView supports two operations: Scroll and zoom. 2. CCScrollView decouples data from the interface through delegate. 3. In essence, CCScrollView is a CClayer that presents its own internal iner, And the touch and display of CCScrollView are determined by the fact that ViewSize is not its own SIze.