接上一節內容:cocos2dx - shader實現任意動畫的殘影效果
本節主要講一下擴展PageView控件功能
在實際游戲應用中,經常會碰到用原來的控件難以實現的功能。這時候就需要根據需求,通過選擇合適的控件進行方便的擴展來實現。
擴展控件一般是通過對原來的控件進行繼承來實現,這樣可以很好的應用原來的屬性及方法,同時可以方便的添加自己需要的方法及屬性。
例子:實現對pageview進行循環翻頁效果。
分析:
1、翻頁方法有2個方式,滑動翻頁及點擊按鈕左右翻動。
2、在觸發翻頁后需要移動頁面位置保持當前新的選中頁面在中間。
3、每次翻頁后需要觸發事件,實現更新內容。
實現:
1、為了優化顯示,我們不在一開始創建所有頁面,僅創建3個layout來存儲顯示的內容,然后在翻頁觸發后刷新頁面內容。
Layout* m_pLeftLayout; Layout* m_pRightLayout; Layout* m_pCurLayout;
2、同時重寫覆蓋以下幾個方法,來實現移動頁面的判斷。
void scrollToPage(ssize_t idx) ; virtual bool scrollPages(Vec2 touchOffset) override; virtual void handleMoveLogic(Touch *touch) override; virtual void handleReleaseLogic(Touch *touch) override; void movePages(Vec2 offset);
主要是通過判斷移動的方向,來判斷需要更新的下一個頁面。然后在移動了一定比例的頁面距離后(0.75),將下一個頁面設為當前界面,重設對應左右界面。
代碼如下:
void CCyclePageView::movePages(Vec2 offset) { if (!m_pCurLayout || !m_pRightLayout || !m_pLeftLayout) { return; } m_pCurLayout->setPosition(m_pCurLayout->getPosition() + offset); m_pRightLayout->setPosition(m_pRightLayout->getPosition() + offset); m_pLeftLayout->setPosition(m_pLeftLayout->getPosition() + offset); Size size = getContentSize(); switch (_touchMoveDirection) { case TouchDirection::LEFT: // left if (m_pCurLayout->getPositionX()<-size.width*0.75) { Layout* newRight = m_pLeftLayout; newRight->setPositionX(m_pRightLayout->getPositionX() + size.width); m_pLeftLayout = m_pCurLayout; m_pCurLayout = m_pRightLayout; m_pRightLayout = newRight; ++_curPageIdx; UpdateShowLayout(_curPageIdx, m_pCurLayout,true); } break; case TouchDirection::RIGHT: // right if (m_pCurLayout->getPositionX()>size.width*0.75) { Layout* newLeft = m_pRightLayout; newLeft->setPositionX(m_pLeftLayout->getPositionX() - size.width); m_pRightLayout = m_pCurLayout; m_pCurLayout = m_pLeftLayout; m_pLeftLayout = newLeft; --_curPageIdx; UpdateShowLayout(_curPageIdx, m_pCurLayout, true); } break; case TouchDirection::UP: if (m_pCurLayout->getPositionY()>size.width*0.75) { Layout* newLeft = m_pRightLayout; newLeft->setPositionX(m_pLeftLayout->getPositionX() - size.height); m_pRightLayout = m_pCurLayout; m_pCurLayout = m_pLeftLayout; m_pLeftLayout = newLeft; --_curPageIdx; UpdateShowLayout(_curPageIdx, m_pCurLayout, true); } break; case TouchDirection::DOWN: if (m_pCurLayout->getPositionY()<-size.height*0.75) { Layout* newRight = m_pLeftLayout; newRight->setPositionX(m_pRightLayout->getPositionX() + size.height); m_pLeftLayout = m_pCurLayout; m_pCurLayout = m_pRightLayout; m_pRightLayout = newRight; ++_curPageIdx; UpdateShowLayout(_curPageIdx, m_pCurLayout, true); } break; default: break; } if (_curPageIdx<0) { _curPageIdx = m_nPageSize-1; } if (_curPageIdx >= m_nPageSize) { _curPageIdx = 0; } }
3、通過以下幾個方法實現更新界面顯示
Layout* GetCurPage(){ return m_pCurLayout;} void addPageChangedListener(const std::function<void(Layout*, size_t)> callback){ m_callback = callback; } void UpdateShowLayout(ssizs_t nCurIdx, Layout* layout, bool isForceCallBack=false);
在UpdateshowLayout中將傳入待更新的頁面更新內容為nCurIdx的內容,這里通過Tag標識來判斷。若Tag與待顯示的Idx不一致則通過addPageChangedListener中設置的回調來實現更新。
void CCyclePageView::UpdateShowLayout(ssize_t nCurIdx, Layout* layout,bool isForceCallBack) { if (nCurIdx<0) { nCurIdx = m_nPageSize - 1; } if (nCurIdx >= m_nPageSize) { nCurIdx = 0; } if (layout && (isForceCallBack || layout->getTag() != nCurIdx)) { layout->setTag(nCurIdx); if (m_callback) { m_callback(layout,nCurIdx); } } }
這里的 isForceCallBack 用來在void movePages(Vec2 offset)中實現最后更新的一個頁面為當前選中的頁面。
使用:
1、在創建后,通過SetPageSize設置循環頁面個數,並通過addPageChangedListener中添加頁面變化監聽。
2、翻頁使用scrollToPage()翻到指定頁面,或者直接通過拖動控件活動實現。
3、在監聽中必須添加更新顯示效果。
CCyclePageView* pNewPageView = CCyclePageView::create(); pNewPageView->addPageChangedListener(std::bind(&CMainWnd::onPageViewUpdate, this, std::placeholders::_1, std::placeholders::_2)); pNewPageView->setDirection(cocos2d::ui::PageView::Direction::HORIZONTAL); pNewPageView->SetPageSize(nCount); pNewPageView->scrollToPage(0);
完整代碼地址:https://github.com/mydishes/cocos2dx-Ex/tree/master/CyclePageView