add PageView vertical scroll support

This commit is contained in:
andyque 2015-08-01 18:18:46 +08:00
parent d52a5da1d8
commit 5f34c1f072
6 changed files with 336 additions and 59 deletions

View File

@ -249,6 +249,10 @@ ccui.PageView.EVENT_TURNING = 0;
ccui.PageView.TOUCH_DIR_LEFT = 0;
ccui.PageView.TOUCH_DIR_RIGHT = 1;
//PageView direction
ccui.PageView.DIRECTION_HORIZONTAL = 0;
ccui.PageView.DIRECTION_VERTICAL = 1;
/*
* UIButton
*/

View File

@ -161,6 +161,11 @@ ccui.PageViewEventType = {
turning = 0,
}
ccui.PageViewDirection = {
HORIZONTAL = 0,
VERTICAL = 1
}
ccui.PVTouchDir = {
touchLeft = 0,
touchRight = 1,

View File

@ -35,6 +35,7 @@ _isAutoScrolling(false),
_autoScrollDistance(0.0f),
_autoScrollSpeed(0.0f),
_autoScrollDirection(AutoScrollDirection::LEFT),
_direction(Direction::HORIZONTAL),
_curPageIdx(-1),
_touchMoveDirection(TouchDirection::LEFT),
_leftBoundaryChild(nullptr),
@ -231,10 +232,22 @@ float PageView::getPositionXByIndex(ssize_t idx)const
return (getContentSize().width * (idx-_curPageIdx));
}
float PageView::getPositionYByIndex(ssize_t idx)const
{
return (getContentSize().height * (idx-_curPageIdx));
}
void PageView::onSizeChanged()
{
Layout::onSizeChanged();
if (_direction == Direction::HORIZONTAL)
{
_rightBoundary = getContentSize().width;
}
else
{
_rightBoundary = getContentSize().height;
}
_doLayoutDirty = true;
}
@ -265,6 +278,8 @@ void PageView::updateAllPagesPosition()
// If the layout is dirty, don't trigger auto scroll
_isAutoScrolling = false;
if (_direction == Direction::HORIZONTAL)
{
float pageWidth = getContentSize().width;
for (int i=0; i<pageCount; i++)
{
@ -272,6 +287,18 @@ void PageView::updateAllPagesPosition()
page->setPosition(Vec2((i-_curPageIdx) * pageWidth, 0));
}
}
else if(_direction == Direction::VERTICAL)
{
float pageHeight = getContentSize().height;
for (int i=0; i<pageCount; i++)
{
Layout* page = _pages.at(i);
page->setPosition(Vec2(0,(i-_curPageIdx) * pageHeight));
}
}
}
void PageView::setCurPageIndex( ssize_t index )
@ -292,12 +319,44 @@ void PageView::scrollToPage(ssize_t idx)
}
_curPageIdx = idx;
Layout* curPage = _pages.at(idx);
if (_direction == Direction::HORIZONTAL)
{
_autoScrollDistance = -(curPage->getPosition().x);
if (_autoScrollDistance > 0)
{
_autoScrollDirection = AutoScrollDirection::RIGHT;
}
else
{
_autoScrollDirection = AutoScrollDirection::LEFT;
}
}
else if(_direction == Direction::VERTICAL)
{
_autoScrollDistance = -(curPage->getPosition().y);
if (_autoScrollDistance > 0)
{
_autoScrollDirection = AutoScrollDirection::UP;
}
else
{
_autoScrollDirection = AutoScrollDirection::DOWN;
}
}
_autoScrollSpeed = fabs(_autoScrollDistance)/0.2f;
_autoScrollDirection = _autoScrollDistance > 0 ? AutoScrollDirection::RIGHT : AutoScrollDirection::LEFT;
_isAutoScrolling = true;
}
void PageView::setDirection(cocos2d::ui::PageView::Direction direction)
{
this->_direction = direction;
}
PageView::Direction PageView::getDirection()const
{
return this->_direction;
}
void PageView::update(float dt)
{
if (_isAutoScrolling)
@ -308,32 +367,30 @@ void PageView::update(float dt)
void PageView::autoScroll(float dt)
{
float step = _autoScrollSpeed*dt;
int sign = 1;
switch (_autoScrollDirection)
{
case AutoScrollDirection::LEFT:
case AutoScrollDirection::DOWN:
{
float step = _autoScrollSpeed*dt;
if (_autoScrollDistance + step >= 0.0f)
{
step = -_autoScrollDistance;
_autoScrollDistance = 0.0f;
_isAutoScrolling = false;
_autoScrollDistance = 0.0f;
}
else
{
_autoScrollDistance += step;
}
scrollPages(-step);
if (!_isAutoScrolling)
{
pageTurningEvent();
}
sign = -1;
break;
}
break;
case AutoScrollDirection::RIGHT:
case AutoScrollDirection::UP:
{
float step = _autoScrollSpeed*dt;
if (_autoScrollDistance - step <= 0.0f)
{
step = _autoScrollDistance;
@ -344,19 +401,25 @@ void PageView::autoScroll(float dt)
{
_autoScrollDistance -= step;
}
scrollPages(step);
if (!_isAutoScrolling)
{
pageTurningEvent();
}
break;
}
default:
break;
}
if (_direction == Direction::HORIZONTAL)
{
scrollPages(Vec2(step * sign, 0));
}
else
{
scrollPages(Vec2(0, step * sign));
}
if (!_isAutoScrolling)
{
pageTurningEvent();
}
}
bool PageView::onTouchBegan(Touch *touch, Event *unusedEvent)
@ -409,16 +472,16 @@ void PageView::doLayout()
_doLayoutDirty = false;
}
void PageView::movePages(float offset)
void PageView::movePages(Vec2 offset)
{
for (auto& page : this->getPages())
{
page->setPosition(Vec2(page->getPosition().x + offset,
page->getPosition().y));
Vec2 oldPosition = page->getPosition();
page->setPosition(oldPosition + offset);
}
}
bool PageView::scrollPages(float touchOffset)
bool PageView::scrollPages(Vec2 touchOffset)
{
if (this->getPageCount() <= 0)
{
@ -430,29 +493,49 @@ bool PageView::scrollPages(float touchOffset)
return false;
}
float realOffset = touchOffset;
Vec2 realOffset = touchOffset;
switch (_touchMoveDirection)
{
case TouchDirection::LEFT: // left
if (_rightBoundaryChild->getRightBoundary() + touchOffset <= _rightBoundary)
if (_rightBoundaryChild->getRightBoundary() + touchOffset.x <= _rightBoundary)
{
realOffset = _rightBoundary - _rightBoundaryChild->getRightBoundary();
realOffset.x = _rightBoundary - _rightBoundaryChild->getRightBoundary();
realOffset.y = 0;
movePages(realOffset);
return false;
}
break;
case TouchDirection::RIGHT: // right
if (_leftBoundaryChild->getLeftBoundary() + touchOffset >= _leftBoundary)
if (_leftBoundaryChild->getLeftBoundary() + touchOffset.x >= _leftBoundary)
{
realOffset = _leftBoundary - _leftBoundaryChild->getLeftBoundary();
realOffset.x = _leftBoundary - _leftBoundaryChild->getLeftBoundary();
realOffset.y = 0;
movePages(realOffset);
return false;
}
break;
case TouchDirection::UP:
{
if (_leftBoundaryChild->getBottomBoundary() + touchOffset.y >= _leftBoundary)
{
realOffset.y = _leftBoundary - _leftBoundaryChild->getBottomBoundary();
realOffset.x = 0;
movePages(realOffset);
return false;
}
}break;
case TouchDirection::DOWN:
{
if (_rightBoundaryChild->getTopBoundary() + touchOffset.y <= _rightBoundary)
{
realOffset.y = _rightBoundary - _rightBoundaryChild->getTopBoundary();
realOffset.x = 0;
movePages(realOffset);
return false;
}
}break;
default:
break;
}
@ -466,17 +549,34 @@ void PageView::handleMoveLogic(Touch *touch)
{
Vec2 touchPoint = touch->getLocation();
float offset = 0.0;
offset = touchPoint.x - touch->getPreviousLocation().x;
Vec2 offset;
offset = touchPoint - touch->getPreviousLocation();
if (offset < 0)
if (_direction == Direction::HORIZONTAL)
{
if (offset.x < 0)
{
_touchMoveDirection = TouchDirection::LEFT;
}
else if (offset > 0)
else if (offset.x > 0)
{
_touchMoveDirection = TouchDirection::RIGHT;
}
offset.y = 0;
}
else
{
offset.x = 0;
if(offset.y < 0)
{
_touchMoveDirection = TouchDirection::DOWN;
}
else if(offset.y > 0)
{
_touchMoveDirection = TouchDirection::UP;
}
}
scrollPages(offset);
}
@ -513,28 +613,48 @@ void PageView::handleReleaseLogic(Touch *touch)
{
Vec2 curPagePos = curPage->getPosition();
ssize_t pageCount = this->getPageCount();
float curPageLocation = curPagePos.x;
float pageWidth = getContentSize().width;
if (!_usingCustomScrollThreshold) {
_customScrollThreshold = pageWidth / 2.0;
auto contentSize = getContentSize();
if (!_usingCustomScrollThreshold)
{
if (_direction == Direction::HORIZONTAL)
{
_customScrollThreshold = contentSize.width / 2.0;
}
else if(_direction == Direction::VERTICAL)
{
_customScrollThreshold = contentSize.height / 2.0;
}
}
float boundary = _customScrollThreshold;
if (curPageLocation <= -boundary)
float moveBoundray = 0.0f;
if (_direction == Direction::HORIZONTAL)
{
curPagePos.y = 0;
moveBoundray = curPagePos.x;
}
else
{
curPagePos.x = 0;
moveBoundray = curPagePos.y;
}
if (moveBoundray <= -boundary)
{
if (_curPageIdx >= pageCount-1)
{
scrollPages(-curPageLocation);
scrollPages(curPagePos);
}
else
{
scrollToPage(_curPageIdx+1);
}
}
else if (curPageLocation >= boundary)
else if (moveBoundray >= boundary)
{
if (_curPageIdx <= 0)
{
scrollPages(-curPageLocation);
scrollPages(curPagePos);
}
else
{
@ -564,7 +684,14 @@ void PageView::interceptTouchEvent(TouchEventType event, Widget *sender, Touch *
case TouchEventType::MOVED:
{
float offset = 0;
if (_direction == Direction::HORIZONTAL)
{
offset = fabs(sender->getTouchBeganPosition().x - touchPoint.x);
}
else if(_direction == Direction::VERTICAL)
{
offset = fabs(sender->getTouchBeganPosition().y - touchPoint.y);
}
_touchMovePosition = touch->getLocation();
if (offset > _childFocusCancelOffset)
{
@ -666,6 +793,7 @@ void PageView::copySpecialProperties(Widget *widget)
_pageViewEventSelector = pageView->_pageViewEventSelector;
_usingCustomScrollThreshold = pageView->_usingCustomScrollThreshold;
_customScrollThreshold = pageView->_customScrollThreshold;
_direction = pageView->_direction;
}
}

View File

@ -53,7 +53,7 @@ typedef void (Ref::*SEL_PageViewEvent)(Ref*, PageViewEventType);
#define pagevieweventselector(_SELECTOR)(SEL_PageViewEvent)(&_SELECTOR)
/**
*@brief Layout manager that allows the user to flip left and right through pages of data.
*@brief Layout manager that allows the user to flip left & right and up & down through pages of data.
*
*/
class CC_GUI_DLL PageView : public Layout
@ -76,7 +76,15 @@ public:
enum class TouchDirection
{
LEFT,
RIGHT
RIGHT,
UP,
DOWN
};
enum class Direction
{
HORIZONTAL,
VERTICAL
};
/**
@ -142,6 +150,23 @@ public:
*/
void removePageAtIndex(ssize_t index);
/**
* Changes scroll direction of PageView
*
* @see `Direction`
* @param direction Scroll direction enum.
* @since v3.8
*/
void setDirection(Direction direction);
/**
* Query scroll direction of PageView.
*
* @see `Direction`
* @since v3.8
* @return PageView scroll direction.
*/
Direction getDirection()const;
/**
* @brief Remove all pages of the PageView.
@ -247,11 +272,12 @@ protected:
Layout* createPage();
float getPositionXByIndex(ssize_t idx)const;
float getPositionYByIndex(ssize_t idx)const;
ssize_t getPageCount()const;
void updateBoundaryPages();
virtual bool scrollPages(float touchOffset);
void movePages(float offset);
virtual bool scrollPages(Vec2 touchOffset);
void movePages(Vec2 offset);
void pageTurningEvent();
void updateAllPagesSize();
void updateAllPagesPosition();
@ -273,12 +299,15 @@ protected:
enum class AutoScrollDirection
{
LEFT,
RIGHT
RIGHT,
UP,
DOWN
};
bool _isAutoScrolling;
float _autoScrollDistance;
float _autoScrollSpeed;
AutoScrollDirection _autoScrollDirection;
Direction _direction;
ssize_t _curPageIdx;
Vector<Layout*> _pages;

View File

@ -12,6 +12,7 @@ UIPageViewTests::UIPageViewTests()
ADD_TEST_CASE(UIPageViewTouchPropagationTest);
ADD_TEST_CASE(UIPageViewDynamicAddAndRemoveTest);
ADD_TEST_CASE(UIPageViewJumpToPageTest);
ADD_TEST_CASE(UIPageViewVerticalTest);
}
// UIPageViewTest
@ -808,3 +809,97 @@ bool UIPageViewJumpToPageTest::init()
}
return false;
}
// UIPageViewVerticalTest
UIPageViewVerticalTest::UIPageViewVerticalTest()
: _displayValueLabel(nullptr)
{
}
UIPageViewVerticalTest::~UIPageViewVerticalTest()
{
}
bool UIPageViewVerticalTest::init()
{
if (UIScene::init())
{
Size widgetSize = _widget->getContentSize();
// Add a label in which the dragpanel events will be displayed
_displayValueLabel = Text::create("Move by Vertical direction", "fonts/Marker Felt.ttf", 32);
_displayValueLabel->setAnchorPoint(Vec2(0.5f, -1.0f));
_displayValueLabel->setPosition(Vec2(widgetSize.width / 2.0f,
widgetSize.height / 2.0f +
_displayValueLabel->getContentSize().height * 1.5));
_uiLayer->addChild(_displayValueLabel);
// Add the black background
Text* alert = Text::create("PageView", "fonts/Marker Felt.ttf", 30);
alert->setColor(Color3B(159, 168, 176));
alert->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f - alert->getContentSize().height * 3.075f));
_uiLayer->addChild(alert);
Layout* root = static_cast<Layout*>(_uiLayer->getChildByTag(81));
Layout* background = dynamic_cast<Layout*>(root->getChildByName("background_Panel"));
// Create the page view
PageView* pageView = PageView::create();
pageView->setContentSize(Size(240.0f, 130.0f));
Size backgroundSize = background->getContentSize();
pageView->setPosition(Vec2((widgetSize.width - backgroundSize.width) / 2.0f +
(backgroundSize.width - pageView->getContentSize().width) / 2.0f,
(widgetSize.height - backgroundSize.height) / 2.0f +
(backgroundSize.height - pageView->getContentSize().height) / 2.0f));
pageView->setDirection(ui::PageView::Direction::VERTICAL);
pageView->removeAllPages();
int pageCount = 4;
for (int i = 0; i < pageCount; ++i)
{
Layout* layout = Layout::create();
layout->setContentSize(Size(240.0f, 130.0f));
ImageView* imageView = ImageView::create("cocosui/scrollviewbg.png");
imageView->setScale9Enabled(true);
imageView->setContentSize(Size(240, 130));
imageView->setPosition(Vec2(layout->getContentSize().width / 2.0f, layout->getContentSize().height / 2.0f));
layout->addChild(imageView);
Text* label = Text::create(StringUtils::format("page %d",(i+1)), "fonts/Marker Felt.ttf", 30);
label->setColor(Color3B(192, 192, 192));
label->setPosition(Vec2(layout->getContentSize().width / 2.0f, layout->getContentSize().height / 2.0f));
layout->addChild(label);
pageView->insertPage(layout,i);
}
pageView->addEventListener(CC_CALLBACK_2(UIPageViewVerticalTest::pageViewEvent, this));
_uiLayer->addChild(pageView);
return true;
}
return false;
}
void UIPageViewVerticalTest::pageViewEvent(Ref *pSender, PageView::EventType type)
{
switch (type)
{
case PageView::EventType::TURNING:
{
PageView* pageView = dynamic_cast<PageView*>(pSender);
_displayValueLabel->setString(StringUtils::format("page = %ld", pageView->getCurPageIndex() + 1));
}
break;
default:
break;
}
}

View File

@ -126,4 +126,20 @@ protected:
cocos2d::ui::Text* _displayValueLabel;
};
class UIPageViewVerticalTest : public UIScene
{
public:
CREATE_FUNC(UIPageViewVerticalTest);
UIPageViewVerticalTest();
~UIPageViewVerticalTest();
virtual bool init() override;
void pageViewEvent(cocos2d::Ref* sender, cocos2d::ui::PageView::EventType type);
protected:
cocos2d::ui::Text* _displayValueLabel;
};
#endif /* defined(__TestCpp__UIPageViewTest__) */