cocos2dx - 控件扩展之pageview循环显示
接上一节内容: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