You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Cocos2d-x(C++)项目的ScrollView中实现类似Creator的网格布局?

Hey there! I totally get where you're coming from—Cocos Creator's Layout component makes grid layouts inside ScrollViews feel effortless, but it's a bummer that the C++ version of Cocos2d-x doesn't ship with a direct out-of-the-box equivalent. No worries though, we can replicate that functionality with a few straightforward approaches. Let's break them down:

Option 1: Manual Position Calculation (Simple & Flexible)

For smaller grids or one-off layouts, manually calculating each item's position is the quickest way. You just need to define your grid parameters (columns, item size, spacing) and loop through your items to place them correctly.

Here's a reusable code snippet to implement this:

void setupGridInScrollView(cocos2d::ui::ScrollView* scrollView, 
                           int columns, 
                           float itemWidth, float itemHeight,
                           float spacingX, float spacingY,
                           float paddingLeft, float paddingTop) {
    auto container = scrollView->getInnerContainer();
    container->removeAllChildren();

    // Replace this with your actual list of items (sprites, buttons, etc.)
    std::vector<cocos2d::Node*> gridItems;
    for (int i = 0; i < 20; ++i) {
        auto item = cocos2d::ui::Button::create("grid_item_bg.png");
        item->setContentSize(cocos2d::Size(itemWidth, itemHeight));
        gridItems.push_back(item);
    }

    // Calculate total rows and container size
    int totalRows = (gridItems.size() + columns - 1) / columns;
    float containerHeight = paddingTop + totalRows * itemHeight + (totalRows - 1) * spacingY;
    container->setContentSize(cocos2d::Size(scrollView->getContentSize().width, containerHeight));

    // Position each item
    for (int i = 0; i < gridItems.size(); ++i) {
        int col = i % columns;
        int row = i / columns;

        // Adjust based on your item's anchor point (this assumes anchor is (0.5, 0.5))
        float posX = paddingLeft + col * (itemWidth + spacingX) + itemWidth / 2;
        float posY = containerHeight - paddingTop - row * (itemHeight + spacingY) - itemHeight / 2;

        gridItems[i]->setPosition(cocos2d::Vec2(posX, posY));
        container->addChild(gridItems[i]);
    }

    scrollView->setInnerContainerSize(container->getContentSize());
}

Pro Tip:

If your items use an anchor point of (0,0) instead of the default (0.5,0.5), adjust the position calculation to:

float posX = paddingLeft + col * (itemWidth + spacingX);
float posY = containerHeight - paddingTop - row * (itemHeight + spacingY) - itemHeight;
Option 2: Use TableView (For Large/Scrollable Grids)

If you're dealing with a large number of items (and want cell reuse to save memory), TableView (a subclass of ScrollView) is your best bet. It's designed specifically for tabular layouts and handles scrolling efficiently.

First, create a custom TableViewCell:

class GridTableViewCell : public cocos2d::extension::TableViewCell {
public:
    static GridTableViewCell* create(const cocos2d::Size& cellSize) {
        auto cell = new GridTableViewCell();
        if (cell && cell->initWithSize(cellSize)) {
            cell->autorelease();
            return cell;
        }
        CC_SAFE_DELETE(cell);
        return nullptr;
    }

    bool initWithSize(const cocos2d::Size& cellSize) {
        if (!TableViewCell::init()) return false;
        this->setContentSize(cellSize);

        // Add your cell content here (e.g., a background sprite + label)
        auto bg = cocos2d::Sprite::create("grid_cell_bg.png");
        bg->setContentSize(cellSize);
        bg->setPosition(cellSize / 2);
        this->addChild(bg);

        return true;
    }
};

Then set up the TableView in your layer:

void setupGridTableView(cocos2d::Layer* parentLayer) {
    const cocos2d::Size viewSize = cocos2d::Size(400, 600); // Size of your scrollable area
    const int columns = 3;
    const cocos2d::Size cellSize = cocos2d::Size(120, 120);

    auto tableView = cocos2d::extension::TableView::create(this, viewSize);
    tableView->setDirection(cocos2d::extension::ScrollView::Direction::VERTICAL);
    tableView->setPosition(cocos2d::Vec2(50, 50));
    tableView->setDelegate(this);
    tableView->setVerticalFillOrder(cocos2d::extension::TableView::VerticalFillOrder::TOP_DOWN);
    parentLayer->addChild(tableView);
    tableView->reloadData();
}

// Implement TableViewDataSource methods
cocos2d::Size tableCellSizeForIndex(cocos2d::extension::TableView* table, ssize_t idx) {
    return cocos2d::Size(120, 120); // Match your cell size
}

cocos2d::extension::TableViewCell* tableCellAtIndex(cocos2d::extension::TableView* table, ssize_t idx) {
    auto cell = dynamic_cast<GridTableViewCell*>(table->dequeueCell());
    if (!cell) {
        cell = GridTableViewCell::create(cocos2d::Size(120, 120));
    }
    // Update cell content here (e.g., set a label text based on idx)
    return cell;
}

ssize_t numberOfCellsInTableView(cocos2d::extension::TableView* table) {
    return 30; // Total number of items in your grid
}
Option 3: Build a Reusable Layout Utility Class

If you find yourself needing grid layouts often, you can wrap the manual calculation logic into a reusable class (mimicking Cocos Creator's Layout component). This way, you can just call a method like layout->setLayoutType(LayoutType::GRID) and pass in parameters, instead of rewriting code every time.

Key Things to Keep in Mind:

  • Always set the ScrollView's inner container size correctly—otherwise, scrolling won't work as expected.
  • Test with different anchor points, as they'll affect your position calculations.
  • For horizontal grids, swap the logic to calculate container width instead of height, and adjust x/y positioning accordingly.

内容的提问来源于stack exchange,提问作者benifest

火山引擎 最新活动