eclipse Cocos2d-x CCScrollview 正在上下滚动

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14693302/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-19 19:56:48  来源:igfitidea点击:

Cocos2d-x CCScrollview is scrolling upside down

androidc++iphoneeclipsecocos2d-x

提问by Prince John

Greetings Stackoverflow,

问候 Stackoverflow,

I am currently trying to implement a scrolling menu into a cocos2d-x game that I am developing. The problem is that the items are scrolling in the opposite direction that I want. For example, if I drag my finger from the bottom of the screen, to the top, the sprite will bounce back to its original position.

我目前正在尝试将滚动菜单实现到我正在开发的 cocos2d-x 游戏中。问题是这些项目正在向我想要的相反方向滚动。例如,如果我将手指从屏幕底部拖动​​到顶部,精灵将弹回其原始位置。

And if I drag my finger from the top to the the bottom, the sprite will follow my finger (until it reaches the boundary).

如果我将手指从顶部拖到底部,精灵将跟随我的手指(直到它到达边界)。

This is my code:

这是我的代码:

    /////////////////////
    //SCROLL VIEW + LAYER
    CCLayer *layer = CCLayer::create();
    layer->setContentSize( CCSizeMake( winSize.width, winSize.height ) );
    layer->addChild( menu );

    scrollView = CCScrollView::create();
    scrollView->retain();
    scrollView->setContentSize( CCSizeMake ( layer->getContentSize().width,  layer->getContentSize().height ) );
    scrollView->setDirection( CCScrollViewDirectionVertical );
    scrollView->setPosition( ccp( 0,0 ) );
    scrollView->setContainer( layer );

    this->addChild(scrollView);

    scrollView->setContentOffset( CCPointZero );

Any suggestions or help is highly appreciated. If you have any other work around for creating a scrolling menu with another approach, I would love to hear.

任何建议或帮助表示高度赞赏。如果您有任何其他方法可以使用另一种方法创建滚动菜单,我很想听听。

Thank you!

谢谢!

Best regards Andreas

最好的问候安德烈亚斯

回答by PAT

Refer: cocos2dx/extensions/GUI/CCScrollView/CCScrollView.cpp

参考:cocos2dx/extensions/GUI/CCScrollView/CCScrollView.cpp

Specifically CCScrollView::minContainerOffsetand CCScrollView::maxContainerOffset

具体CCScrollView::minContainerOffsetCCScrollView::maxContainerOffset

CCScrollViewworks in OpenGL coordinates(as opposed window coordinates) - values are relative to (left, bottom) with positive Y axis going upwards. Also, keep in mind the scroll view's positioning and the containerare anchored (CCNode::setAnchorPoint) to (left, bottom).

CCScrollView适用于OpenGL 坐标(与窗口坐标相反) - 值相对于(左、下),正 Y 轴向上。另外,请记住滚动视图的定位和容器锚定 ( CCNode::setAnchorPoint) 到(左,下)。

When you scroll down (move/pull the content upwards to see content below the cut/clip), you see the content below the bottom edge of the screen but it bounces back the moment you let go of the touch/drag because maxContainerOffsetreturns (0, 0)and you've just tried to move to a positive content offset.

当你向下滚动(移动/拉内容向上,看切/夹下面的内容),你看到屏幕底部边缘下面的内容,但反弹你放手触摸/拖动,因为瞬间maxContainerOffset回报(0, 0)你' 刚刚尝试转向积极的内容偏移。

Coordinates of CCScrollView and the container

CCScrollView 和容器的坐标

The diagram shows the state of the scrollviewand the containerwhen they're created/initialized. This is the state or the coordinates to "think in" when setting up and positioning the child elementsand container. The gray rectangle (left, bottom) shows the valid region for scrolling the container. Imagine the container's anchor point moves inside it.

该图显示了滚动视图容器在创建/初始化时的状态。这是设置和定位子元素容器时要“考虑”的状态或坐标。灰色矩形(左、下)显示滚动容器的有效区域。想象一下容器的锚点在其中移动。

To see the container scrolled to the top to begin with (what you'd expect when working in window coordinates), set the content offset accordingly (immediately after setting it up). This will give the expected results/behavior.

要查看容器滚动到顶部开始(您在窗口坐标中工作时所期望的),请相应地设置内容偏移量(设置后立即)。这将给出预期的结果/行为。

scrollView->setContentOffset(ccp(0.f, (scrollViewHeight-scrollContainerHeight)), false);

A more complete example is in the edited code below.

更完整的示例在下面编辑过的代码中。

  1. A "fix" to allow scrolling in the window coordinate (positive Y axis downwards) may be to adjust the extension, this would require you to rebuild the cocos2dx library and will affect all projects (even other sample code you may try).

    /*
    // (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);
    }
    */
    
  2. A less intrusivehack, is to scale the ScrollViewinstance to -1 and the childrenof the container nodealso to -1. You also have to reposition the child nodestaking into account the inverse scale. The result of the scaling at both levels is the content (child nodes) are viewed straight (not flipped). The result of scaling the ScrollViewto -1 is that the scroll happens for you in the expected direction. Note though this "fix" will flip scrolling in the X axis as well and hence is onlysuitable if you wish to scroll vertically (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);
    
  1. 允许滚动窗口坐标(正 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);
    }
    */
    
  2. 一个侵入性较小的hack是将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);
    

Also note that the two fixes mentioned above are mutually exclusive, do notapply both.

还要注意的是,两个定位上面提到的是相互排斥的,也不能适用两种

Answernow on the cocos2d-x forum too.

现在也在 cocos2d-x 论坛上回答

回答by Hakim Hauston

@Zennichimaro,

@Zennichimaro,

@PAT's answer is correct and is essentially a simplified version

@PAT 的回答是正确的,本质上是简化版

With that in mind, note that 3 things are important:

考虑到这一点,请注意 3 件事很重要:

  1. CCScrollView::setViewSize()- you clearly missed out this one, it has to be the width and height of your viewable space (the blue box, I think it is your entire windowSize if you want it fullscreen)

  2. CCScrollView::setContentSize()- this is different from setContentOffset, looks like you've mistaken this to setContentOffset, anyway, this should be set to the size of the entire container (the red box, yours will probably be ccp(windowSize.width,2496.0f))

  3. CCScrollView::setContentOffset()- if you want to position it so that the topmost is visible initially, the minimum and maximum is specified by the small grey rectangle box in the answer (the grey box, yours will probably be ccp(0.0f, windowSize.height-2496.0f))

  1. CCScrollView::setViewSize()- 你显然错过了这个,它必须是你的可视空间的宽度和高度(蓝色框,如果你想要全屏显示,我认为它是你的整个 windowSize)

  2. CCScrollView::setContentSize()- 这与setContentOffset不同,看起来你把它误认为是setContentOffset,无论如何,这应该设置为整个容器的大小(红色框,你的可能是ccp(windowSize.width,2496.0f)

  3. CCScrollView::setContentOffset()- 如果您想放置它以便最上面最初是可见的,最小值和最大值由答案中的小灰色矩形框指定(灰色框,你的可能是ccp(0.0f, windowSize.height-2496.0f)

回答by mtet88

A shorter answer would be:

更简短的答案是:

scrollView->setContentOffset(scrollView->minContainerOffset());

Since the anchor point is in the lower-left corner, the initial offset is not zero, but a negative number.

由于锚点在左下角,所以初始偏移量不是零,而是一个负数。

回答by Dainius Kreivys

If someone wants to make a scrollview like in mmo games chat tables (adds messages to bottom and auto scrolls to bottom of it) then maybe someone will find this useful:

如果有人想像 mmo 游戏聊天表中那样制作滚动视图(将消息添加到底部并自动滚动到底部),那么也许有人会发现这很有用:

part of the code of my ChatTableView.h

我的 ChatTableView.h 的部分代码

//tableView dataSource is vector of strings
class ChatTableView :public Layer, public TableViewDataSource, public TableViewDelegate
{
public:
    vector<string> n_msglist;
    TableView* pTableView;
    void addMsg(string text);
private:

};

//part of the code of my ChatTableView.cpp
void Init(){
    pTableView = TableView::create(this, VisibleRect::getVisibleRect().size, NULL);
    pTableView->setDirection(ScrollView::Direction::VERTICAL);
    pTableView->setVerticalFillOrder(TableView::VerticalFillOrder::TOP_DOWN);
    pTableView->setDelegate(this);
    pTableView->setBounceable(false);

} 
void ChatTableView::addMsg(string text){

    n_msglist.push_back(text); //adds string to vector
    pTableView->reloadData(); //reloads data with newly updated vector and scroll back to top
    pTableView->setContentOffset(pTableView->maxContainerOffset()); //scrolls to bottom
}