参考:cocos2dx/extensions/GUI/CCScrollView/CCScrollView.cpp
具体CCScrollView::minContainerOffset
和CCScrollView::maxContainerOffset
CCScrollView
在OpenGL 坐标(相对于窗口坐标)中工作 - 值相对于(左、下),正 Y 轴向上。另外,请记住滚动视图的定位和容器被锚定(CCNode::setAnchorPoint
)到(左,下)。
当您向下滚动(向上移动/拉动内容以查看剪切/剪辑下方的内容)时,您会看到屏幕底部边缘下方的内容,但在您松开触摸/拖动时它会弹回,因为maxContainerOffset
返回(0, 0)
并且您'刚刚尝试移动到积极的内容偏移量。
该图显示了滚动视图和容器在创建/初始化时的状态。这是设置和定位子元素和容器时要“考虑”的状态或坐标。灰色矩形(左,下)显示滚动容器的有效区域。想象容器的锚点在其中移动。
要查看容器开始滚动到顶部(在窗口坐标中工作时您所期望的),请相应地设置内容偏移量(在设置后立即)。这将给出预期的结果/行为。
scrollView->setContentOffset(ccp(0.f, (scrollViewHeight-scrollContainerHeight)), false);
下面编辑的代码中有一个更完整的示例。
允许在窗口坐标中滚动(正 Y 轴向下)的“修复”可能是调整扩展,这将需要您重建 cocos2dx 库并影响所有项目(甚至您可以尝试的其他示例代码)。
/*
// (StackOverflow Post Edit: This hack is not required.)
CCPoint CCScrollView::maxContainerOffset()
{
// Default CCPointZero;
return ccp(0.0f, m_pContainer->getContentSize().height*m_pContainer->getScaleY() - m_tViewSize.height);
}
CCPoint CCScrollView::minContainerOffset()
{
// Default Y = m_tViewSize.height - m_pContainer->getContentSize().height*m_pContainer->getScaleY();
return ccp(m_tViewSize.width - m_pContainer->getContentSize().width*m_pContainer->getScaleX(),
0.f);
}
*/
一个不那么侵入性的 技巧是将ScrollView实例缩放到-1,并将容器节点的子节点也缩放到-1。您还必须考虑逆比例重新定位子节点。两个级别的缩放结果是内容(子节点)被直接查看(而不是翻转)。将ScrollView缩放到 -1 的结果是滚动发生在您预期的方向上。请注意,尽管此“修复”也会在 X 轴上翻转滚动,因此仅适用于您希望垂直滚动 ( ) 的情况。CCScrollViewDirectionVertical
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
CCLayer* scrollContainer = CCLayer::create(); // Container for the scroll view
scrollContainer->setAnchorPoint(CCPointZero); // CCScrollView does this too when it's set as the container.
// Content for the container
CCSprite *tallContentA = CCSprite::create("TallContentA.png");
tallContentA ->setPosition(ccp(winSize.width*0.5f, winSize.height*0.9f));
CCSprite *tallContentB = CCSprite::create("TallContentB.png");
tallContentB ->setPosition(ccp(winSize.width*0.5f, winSize.height*0.1f));
scrollContainer->addChild(tallContentA, 2);
scrollContainer->addChild(tallContentB, 2);
float scrollContainerHeight = tallContentA->getContentSize().height + tallContentB->getContentSize().height;
scrollContainer->setPosition(CCPointZero);
scrollContainer->setContentSize(CCSizeMake(winSize.width, scrollContainerHeight*1.05f));
// Set up scroll view
CCScrollView* scrollView = CCScrollView::create(winSize, scrollContainer);
scrollView->setPosition(CCPointZero);
scrollView->setDirection(CCScrollViewDirectionVertical);
// ScrollView initializes at the (left, bottom). The container also gets positioned relative to that and goes Y-up.
// Pre-set it to the value CCScrollView::minContainerOffset will return when it's scrolled to the top
// (note, this is a negative number, indicating the touch moving downwards, i.e. it's pre-scrolled such that the top of the content is visible when we begin)
scrollView->setContentOffset(ccp(0.f, (winSize.height-scrollContainerHeight*1.05f)), false);
/*
// (StackOverflow Post Edit: This hack is not required.)
// Hack: CCScrollView's maxContainerOffset is (0, 0) and minContainerOffset is (difference between view and content size which is negative)
// It's designed to be (left, bottom) based and positive scrolling means showing stuff above the top of the screen.
// Since we're using it in terms of Window coordinates ((left, top) based), we scale the scroll view
// and it's container's children by -1 and position the children differently
// (eg. Y position winSize.height*0.1f was changed to winSize.height*0.9f)
// We can't just set the scroll view's Y scale to -1 because CCNode::getScale asserts that X and Y scale must be the same.
scrollView->setScale(-1.f);
tallContentA->setScale(-1.f);
tallContentB->setScale(-1.f);
*/
addChild(scrollView);
还要注意上面提到的两个修复是互斥的,不要同时应用。
现在也在 cocos2d-x 论坛上回答。