One of the foundational concepts of Corona SDK is display groups. These allow developers to organize different display objects like images, vector shapes, and text into groups and then manipulate the group as a whole.
Objects in the group are layered similar to the way layers are stacked in image editing tools like Photoshop. That is, the first object inserted in the group resides on the bottom. As new objects are added, they stack on top, obscuring objects underneath. This is known as the painter’s method.
In Corona, display groups are “boundless” with nearly infinite capacity, yet they do have one limitation. If you want a group to span just a 200×200 pixel region, the typical solution is to mask the entire group. However, this requires that you to create a separate mask image for each size and purpose. In essence, this is a challenge for developers who want to implement dynamically-sized masked regions.
To help address this challenge, Corona’s Graphics 2.0 engine introduces a new and powerful feature: containers. Basically, containers can be considered self-masking groups. That is, you can set a width/height for the container and only child display objects (or any portion of those objects) inside the container bounds will be visible. In addition, the width and height can be changed dynamically, allowing you to expand or shrink the bounding box of the container.
To create a container, simply call display.newContainer() passing it the width and height:
local myContainer = display.newContainer( 300, 200 )
myContainer.x = display.contentCenterX
myContainer.y = display.contentCenterY
Once created, adding display objects to a container is identical to adding objects to groups:
local gradient = type="gradient", color1=1,0,0, color2=0.2,0,0, direction="down" }
local bg = display.newRect( 0, 0, 1000, 1000 )
bg.fill = gradient
myContainer:insert( bg )
local myText = display.newText( "Hello World!", 0, 0, native.systemFont, 20 )
myContainer:insert( myText )
In this example, we first create a big rectangle and fill it with a gradient. This exhibits how the gradient rectangle, larger than the container, is “clipped” by the container bounds.
Next we add a text object. If you run this code, you may be surprised to notice that myText appears centered in the screen, even though it was created at the coordinates 0,0. This is because of a few important differences in Graphics 2.0.
Center Anchor Default
In Graphics 2.0, all display objects are now drawn, by default, relative to their center, even when you specify an x and y coordinate in the function call. For comparison, examine this code:
display.newText( "Some string", 0, 0, native.systemFont, 24 )
In the previous graphics engine, this would have drawn the text “Hello World!” with its top-left corner at the top-left point of the screen (0,0). In Graphics 2.0, the center of the text object will be drawn at 0,0.
Containers and Anchor Points
When inserting objects into a standard display group, the group’s origin is at 0,0. Then, if you move the group, the text moves relative to the group’s new origin.
A container also has an origin point which lies at its anchor point (if you missed the tutorial on anchor points, please access it here). By default, the anchor point is the center of the container’s bounding box. Thus, when you insert a display object into the container, it’s relative to the container’s anchor point. In our example above, we don’t change the anchor point, so the text is centered in the container. With this in mind, if you want to position the text above or left of center, you must position it at negative x and y locations.
Unlike groups, containers have the .anchorChildren property set to true. If you change the container’s anchor point, the children move as well. However, if you want containers to behave more like groups in this respect, set .anchorChildren to false. For more information, see the anchor points tutorial.
Internally, containers use masks. Be careful in this regard, because devices have a limited number of masks that can be “stacked” together (nested). The maximum is 3 but may be less. Thus, you should avoid putting containers inside other containers, because if the limit is exceeded, container clipping will fail.
This limit does not apply to the basic number of containers/masks used, but rather the nested number of items that occupy a texture unit.
If you’ve ever used a rectangular mask to constrain a group’s content, containers are a powerful and flexible alternative. To get started, please read the documentation and download one of the sample projects: Container, ContainerAlignment, and ContainerAnchorChildren.