1. 程式人生 > >Cocos2d—X遊戲開發之CCScrollView(滑動檢視)(十三)

Cocos2d—X遊戲開發之CCScrollView(滑動檢視)(十三)

CCScrollView在Cocos2d-X引擎中主要使用在圖片尺寸遠大於螢幕尺寸的時候使用。

總體來說,使用起來比較簡單。

一個是CCScrollView控制元件本身,一個是CCScrollViewDelegate代理。

#1.現在我們先來看CCScrollView的主要方法:

 */
//滑動方向
typedef enum {
	kCCScrollViewDirectionNone = -1,
    kCCScrollViewDirectionHorizontal = 0,
    kCCScrollViewDirectionVertical,
    kCCScrollViewDirectionBoth
} CCScrollViewDirection;

class CCScrollView;

class CCScrollViewDelegate
{
public:
    virtual ~CCScrollViewDelegate() {}
    virtual void scrollViewDidScroll(CCScrollView* view) = 0;  //滑動呼叫
    virtual void scrollViewDidZoom(CCScrollView* view) = 0;  //縮放呼叫
};


/**
 * ScrollView support for cocos2d for iphone.
 * It provides scroll view functionalities to cocos2d projects natively.
 */
class CCScrollView : public CCLayer
{
public:
    CCScrollView();
    virtual ~CCScrollView();

    bool init();
    virtual void registerWithTouchDispatcher();

    /**
     * Returns an autoreleased scroll view object.
     *
     * @param size view size
     * @param container parent object
     * @return autoreleased scroll view object
     */
    static CCScrollView* create(CCSize size, CCNode* container = NULL);

    /**
     * Returns an autoreleased scroll view object.
     *
     * @param size view size
     * @param container parent object
     * @return autoreleased scroll view object
     */
    static CCScrollView* create();

    /**
     * Returns a scroll view object
     *
     * @param size view size
     * @param container parent object
     * @return scroll view object
     */
    bool initWithViewSize(CCSize size, CCNode* container = NULL);


    /**
     * Sets a new content offset. It ignores max/min offset. It just sets what's given. (just like UIKit's UIScrollView)
     *
     * @param offset new offset
     * @param If YES, the view scrolls to the new offset
     */
    void setContentOffset(CCPoint offset, bool animated = false);
    CCPoint getContentOffset();
    /**
     * Sets a new content offset. It ignores max/min offset. It just sets what's given. (just like UIKit's UIScrollView)
     * You can override the animation duration with this method.
     * 設定新的容器座標
     * @param offset new offset
     * @param animation duration
     */
    void setContentOffsetInDuration(CCPoint offset, float dt); 

    void setZoomScale(float s);
    /**
     * Sets a new scale and does that for a predefined duration.
     * 設定CCScrollView的縮放
     * @param s a new scale vale
     * @param animated if YES, scaling is animated
     */
    void setZoomScale(float s, bool animated);

    float getZoomScale();

    /**
     * Sets a new scale for container in a given duration.
     *
     * @param s a new scale value
     * @param animation duration
     */
    void setZoomScaleInDuration(float s, float dt);
    /**
     * Returns the current container's minimum offset. You may want this while you animate scrolling by yourself
     */
    CCPoint minContainerOffset();
    /**
     * Returns the current container's maximum offset. You may want this while you animate scrolling by yourself
     */
    CCPoint maxContainerOffset(); 
    /**
     * Determines if a given node's bounding box is in visible bounds
     *
     * @return YES if it is in visible bounds
     */
    bool isNodeVisible(CCNode * node);
    /**
     * Provided to make scroll view compatible with SWLayer's pause method
     */
    void pause(CCObject* sender);
    /**
     * Provided to make scroll view compatible with SWLayer's resume method
     */
    void resume(CCObject* sender);


    bool isDragging() {return m_bDragging;} 
    bool isTouchMoved() { return m_bTouchMoved; }
    bool isBounceable() { return m_bBounceable; } //是否開啟彈性滑動,預設true,false滑動失效
    void setBounceable(bool bBounceable) { m_bBounceable = bBounceable; }

    /**
     * size to clip. CCNode boundingBox uses contentSize directly.
     * It's semantically different what it actually means to common scroll views.
     * Hence, this scroll view will use a separate size property.
     */
    CCSize getViewSize() { return m_tViewSize; } 
    void setViewSize(CCSize size);

    CCNode * getContainer();
    void setContainer(CCNode * pContainer);  //設定,獲取容器的一對方法

    /**
     * direction allowed to scroll. CCScrollViewDirectionBoth by default.
     */
    CCScrollViewDirection getDirection() { return m_eDirection; }
    virtual void setDirection(CCScrollViewDirection eDirection) { m_eDirection = eDirection; }   //設定,獲取CCScrollView的對齊方向

    CCScrollViewDelegate* getDelegate() { return m_pDelegate; }
    void setDelegate(CCScrollViewDelegate* pDelegate) { m_pDelegate = pDelegate; }  //設定代理物件

    /** override functions */
    // optional
    virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
    virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);
    virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
    virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);

    virtual void setContentSize(const CCSize & size); //設定容器大小
    virtual const CCSize& getContentSize() const;

	void updateInset();
    /**
     * Determines whether it clips its children or not.
     */
    bool isClippingToBounds() { return m_bClippingToBounds; }
    void setClippingToBounds(bool bClippingToBounds) { m_bClippingToBounds = bClippingToBounds; }

    virtual void visit();
    virtual void addChild(CCNode * child, int zOrder, int tag);
    virtual void addChild(CCNode * child, int zOrder);
    virtual void addChild(CCNode * child);
    void setTouchEnabled(bool e);
private:
    /**
     * Relocates the container at the proper offset, in bounds of max/min offsets.
     *
     * @param animated If YES, relocation is animated
     */
    void relocateContainer(bool animated);
    /**
     * implements auto-scrolling behavior. change SCROLL_DEACCEL_RATE as needed to choose
     * deacceleration speed. it must be less than 1.0f.
     *
     * @param dt delta
     */
    void deaccelerateScrolling(float dt);
    /**
     * This method makes sure auto scrolling causes delegate to invoke its method
     */
    void performedAnimatedScroll(float dt);
    /**
     * Expire animated scroll delegate calls
     */
    void stoppedAnimatedScroll(CCNode* node);
    /**
     * clip this view so that outside of the visible bounds can be hidden.
     */
    void beforeDraw();
    /**
     * retract what's done in beforeDraw so that there's no side effect to
     * other nodes.
     */
    void afterDraw();
    /**
     * Zoom handling
     */
    void handleZoom();

protected:
    CCRect getViewRect();
    
    /**
     * current zoom scale
     */
    float m_fZoomScale;
    /**
     * min zoom scale
     */
    float m_fMinZoomScale;
    /**
     * max zoom scale
     */
    float m_fMaxZoomScale;
    /**
     * scroll view delegate
     */
    CCScrollViewDelegate* m_pDelegate;

    CCScrollViewDirection m_eDirection;
    /**
     * If YES, the view is being dragged.
     */
    bool m_bDragging;

    /**
     * Content offset. Note that left-bottom point is the origin
     */
    CCPoint m_tContentOffset;

    /**
     * Container holds scroll view contents, Sets the scrollable container object of the scroll view
     */
    CCNode* m_pContainer;
    /**
     * Determiens whether user touch is moved after begin phase.
     */
    bool m_bTouchMoved;
    /**
     * max inset point to limit scrolling by touch
     */
    CCPoint m_fMaxInset;
    /**
     * min inset point to limit scrolling by touch
     */
    CCPoint m_fMinInset;
    /**
     * Determines whether the scroll view is allowed to bounce or not.
     */
    bool m_bBounceable;

    bool m_bClippingToBounds;

    /**
     * scroll speed
     */
    CCPoint m_tScrollDistance;
    /**
     * Touch point
     */
    CCPoint m_tTouchPoint;
    /**
     * length between two fingers
     */
    float m_fTouchLength;
    /**
     * UITouch objects to detect multitouch
     */
    CCArray* m_pTouches;
    /**
     * size to clip. CCNode boundingBox uses contentSize directly.
     * It's semantically different what it actually means to common scroll views.
     * Hence, this scroll view will use a separate size property.
     */
    CCSize m_tViewSize;
    /**
     * max and min scale
     */
    float m_fMinScale, m_fMaxScale;
    /**
     * scissor rect for parent, just for restoring GL_SCISSOR_BOX
     */
    CCRect m_tParentScissorRect;
    bool m_bScissorRestored;
};

#2.現在看下示例程式碼:

.h宣告
class HelloWorld : public cocos2d::CCLayer, public CCScrollViewDelegate
{
private:
    
    CCScrollView *scroll ;
    float xOffSet;
    float yOffSet;
    
public:
    
    virtual bool init();
    static cocos2d::CCScene* scene();
    void menuCloseCallback(CCObject* pSender);
    CREATE_FUNC(HelloWorld);
    
    virtual void scrollViewDidScroll(CCScrollView* view);
    virtual void scrollViewDidZoom(CCScrollView* view);
   
    
};
.cpp實現
bool HelloWorld::init()
{
    // 1. super init first
    if ( !CCLayer::init() )
    {
        return false;
    }

    CCSize winSize = CCDirector::sharedDirector()->getWinSize();
    
    
    //設定scrollView的大小,為顯示的view的尺寸
    scroll = CCScrollView::create(CCSizeMake(960, 640));
    
    CCSprite *bg = CCSprite::create("11.png");
    
    //bg->setPosition(ccp(winSize.width/2, winSize.height/2));
    //容器的錨點是(0,0)
    bg->setPosition(ccp(0, 0));
    
    CCMenuItemImage *back = CCMenuItemImage::create("Icon.png", "Icon.png");
    back->setPosition(CCPoint(200, 200));
    bg->addChild(back);
    
    //bg->setAnchorPoint(ccp(0.5, 0.5));
    //scroll->setAnchorPoint(ccp(0, 0));
    
    //設定容器
    scroll->setContainer(bg);
        
    //是開啟彈性效果,關閉的話就不用使用這個控制元件
    //scroll->setBounceable(false);
    bool flag = scroll->isBounceable();
    CCLog("flag: %d",flag);
    
    //設定滑動方向
    //kCCScrollViewDirectionHorizontal——水平滑動
    //kCCScrollViewDirectionVertical——垂直滑動
    scroll->setDirection(kCCScrollViewDirectionBoth);
    
    //設定容器大小
    scroll->setContentSize(CCSizeMake(978, 2189));
    //觸控有效
    this->setTouchEnabled(true);
    CCSize scrollSize = scroll->getContentSize();
    CCLog("scrollSize: %f %f",scrollSize.width,scrollSize.height);
    
    //設定代理為自身
    scroll->setDelegate(this);
    this->addChild(scroll);
    
    //黑邊防禦座標
    xOffSet = winSize.width - scrollSize.width;
    yOffSet = winSize.height - scrollSize.height;
    
    
    
    return true;
}

void HelloWorld::scrollViewDidScroll(CCScrollView* view)
{
    static int flag = 0;
    CCLog("Scroll %d",flag++);
    
    CCPoint offSet = this->scroll->getContentOffset();
    CCLog("offSet : %f %f",offSet.x,offSet.y);
    if (offSet.x < this->xOffSet || offSet.y < this->yOffSet) {
        
        CCLog("scrollView 已經出現黑邊問題了!");
        
        if (offSet.x < this->xOffSet ) {
            CCLog("scrollView X軸 出現黑邊問題了!");
            this->scroll->setContentOffset(CCPoint(this->xOffSet, offSet.y));
        }else{
            CCLog("scrollView Y軸 已經出現黑邊問題了!");
            this->scroll->setContentOffset(CCPoint(offSet.x, this->yOffSet));
        }
    }
    
    if (offSet.x > 0 || offSet.y > 0) {
        CCLog("scrollView 已經出現黑邊問題了!");
        
        if (offSet.x > 0 ) {
            CCLog("scrollView X軸 出現黑邊問題了!");
            this->scroll->setContentOffset(CCPoint(0, offSet.y));
        }else{
            CCLog("scrollView Y軸 已經出現黑邊問題了!");
            this->scroll->setContentOffset(CCPoint(offSet.x, 0));
        }
        
    }
    
}

#3.現在,我們來看下效果

原圖的尺寸是978*2189