Both types of containers are in the spark.components.* package.
Most Spark containers are skinnable. For example, the SkinnableContainer,
Panel, and TitleWindow containers are skinnable. Skinnable containers
subclass the SkinnableContainer class.
Spark groups are examples of containers that are not skinnable.
They provide a lightweight mechanism that you use to perform layout.
However, Spark groups do not support skinning to ensure that they
add minimal overhead to your application. To modify the visual appearance
of a Spark group, you can use the corresponding Spark container,
which is skinnable. By contrast, all MX containers are skinnable.
Skinnable container skins are just like other component skins.
They define a group that defines where the content children are
laid out. This element has an ID of contentGroup.
All skinnable containers have a content group. All visual children
of a container are pushed into the content group and laid out using
that group’s layout rules.
For a list of which containers are skinnable and/or scrollable,
see About Spark containers.
Sizing Spark container skins
A common reason to skin a Spark container is to add a graphic
element, such as a rectangle, to be the background of the container.
You typically set its size by using the constraint properties or
the percent size properties by using one of the following methods:
When the components are first drawn, constraint properties take
precedence (so if you set them, then the dimensional properties
are ignored). However, if you set the value of the constraint properties,
but then later explicitly set the value of the percent size properties
at runtime (for example, by setting the percentHeight property
to 100), Flex honors the new settings.
Using constraint or percent size properties depends on the use
case. In general, a skin resizes when the host component resizes.
The choice of percent or constraint sizing is based on the resizing
scenario. For example, if you want a label element to be always
half as wide as the skin, then set the width property to
50%. If you want a label element to be always inset by 5 pixels,
set the left and right properties
to 5.
The resizable skin elements in the default Spark skins usually
set the left and right properties.
To specify their default size, they also set the width property. As
a result, if the component size is not set in the application, the
element’s width sets the default size of the skin and the component.
The following example from the ButtonSkin.mxml class shows that
the default size of the Button control is the default size of its
skin. This is calculated from the rectangle in the skin, and is
69 pixels wide and 20 pixels high:
Another technique for designing resizable skins is to specify
a minimum size for the skin. For more information, see Setting minimum sizes of a skin.
Adding borders to Spark containers
One common use of a custom Spark skin is to add a borders
to a container. Borders can be simple boxes around the perimeter
of a container, or they can define drop shadows, line styles, corner
radii, and other properties of a border.
To add a simple rectangular border to a container’s skin, you
add a Rect object. You
can set the height and width of the Rect to 100% so that the skin
sizes itself to the size of the container automatically, or you
can set the offsets to 0.
The following example adds a simple 1-point, black line as a
border around the container:
The executing SWF file for the previous example is shown below:
The contentGroup container has left, right,
top, and bottom offsets of 1. This lets the border display outside
the content instead of sitting directly on top of the outside edges
of container children. The custom skin class for this example is
as follows:
The container’s skin sets its constraint properties (top, bottom, left,
and right) to 0, so the Rect object is set to the
same size as the container.
To create a border with rounded corners in a skin, you set the
values of the radiusX and radiusY properties
of the Rect object. These properties define the number of pixels
for the corners on the x and y axes of the Rect. The following example
sets the radiusX and radiusY properties
to 10 to round the corners of the container’s skin:
You can add a border to a container by using the BorderContainer class.
The BorderContainer class is a subclass of the SkinnableContainer class.
Because you use CSS styles and class properties to control the appearance
of the BorderContainer class, you typically do not create a custom
skin for it.
The following example shows that the BorderContainer class takes
the cornerRadius, borderColor, borderVisible,
and borderAlpha style properties in addition to
layout properties, which let you define a border similar to that
shown in the previous example without skinning:
The executing SWF file for the previous example is shown below:
Because the border-related properties are styles, you can use
CSS to define a consistent border across all instances of the BorderContainer
class; for example:
The executing SWF file for the previous example is shown below:
To add a border to a single instance of a container or group,
you are not required to create a custom skin for the container.
You can instead add a Rect graphic in the application itself. This
is a process known as composition, where you are adding graphical
elements to the application that change the appearance of controls
in the application. Sometimes skinning gives a better abstraction because
it distinguishes between visual children and content children.
For example, you can define MXML graphic tags fragment that draws
the graphic elements that make up the border. These graphic elements
are typically a stroke or fill (or both).
The following example draws a border around a VGroup that contains
Button controls without using a custom skin class:
The executing SWF file for the previous example is shown below:
Adding drop shadows to Spark containers
To add a drop shadow to a Spark container, you use the DropShadowFilter class. You
add the filter to one of the graphic elements defined on that container’s
skin class. The DropShadowFilter class supports the alpha, angle, distance,
and other properties that let you customize the appearance of the
drop shadow. In addition, you add a fill to the graphic element.
The fill defines the color of the drop shadow. These settings are
all in the custom skin class and not in the main application.
The following example defines a drop shadow on the container’s
skin:
In this example, the drop shadow is the first element on the
skin. You can use the depth property to change
the ordering of the elements. This property determines the order
in which items inside of containers are rendered. Spark containers
order their items based on their depth property,
with the lowest depth in the back, and the higher in the front.
Items with the same depth value appear in the order
they are added to the container.
A more efficient alternative to the DropShadowFilter class is
to use the dropShadowEnabled property to add a
drop shadow. For more information, see Using the dropShadowEnabled property
You can also add a drop shadow to any individual container in
the application itself through composition. The downside to doing
it this way is that the drop shadow is applied to a single instance
of the container, and not all containers. It also removes the benefits
of abstraction that skins provide.
Adding padding to Spark containers
Another common use of Spark skins is modify the padding
of Spark containers.
To add padding, you can set the offset properties of the container’s
content group. These properties are top, bottom, left,
and right.
The following example sets the offsets of the contentGroup to
10 so that the contents of the container are padded by 10 pixels
in all directions:
You can also add padding to the layout object. For example, the
VerticalLayout object takes paddingLeft, paddingRight, paddingBottom,
and paddingTop properties.
Specifying the layout in the skin changes the default layout
for this container. However, you can set it on the container instance
itself to override the default layout that you set in the skin.
Adding scroll bars to Spark containers
Spark containers do not have scroll bars by default. To
add scroll bars to a Spark container, use the Scroller class.
To add scroll bars to a container’s skin class, you wrap the
content group or other element in a Scroller tag. The child of a
Scroller tag must implement the IViewport interface. This interface
is implemented by Group and DataGroup, and some components such
as the RichEditableText control.
To ensure that scroll bars appear, do not set explicit sizes
on the group. If you set the size of the group explicitly, then
that size becomes the size of the Group and no scroll bars will
be shown.
The following example defines the size of the application, and
sizes the container to a percent of the overall height and width.
The scroller is constrained to the size of the viewport (in this
case, the content group). Because the image is larger than the size
of its parent, Flex displays scroll bars.
The Scroller layout does not support the left/right/top/bottom
constraints on the content group of the container. And in general,
you should not explicitly set the height and width properties
of the Scroller’s content group. Instead, you should let the content
group size naturally.
You can use the minViewportInset property on
the Scroller class to inset the viewport relative to its Scroller
along the edges where a scroll bar does not already keep the viewport
away from the edge. For example, if you set the minViewportInset property
to 10, then the right edge of the viewport would be 10 pixels from
the right edge of its scroller, unless the vertical scroll bar was
visible. When a scroll bar is visible, the viewport and the scroll
bar would not have any space between them.
Adding background fills and images to Spark containers
To add background fills and background images to a Spark
container’s skin, you add a Rect or other graphic element and add
the fill to that element.
To add a color fill, you add a graphic element that is a subclass
of FilledElement and
define a child fill tag. Subclasses of FilledElement include Rect,
Ellipse, and Path. The fill must implement the IFill interface,
which includes the BitmapFill, LinearGradient, RadialGradient, or
SolidColor classes.
The following example defines three containers with three different
fills:
You can also add a background fill to a content group, although
the content group often defines an offset or padding properties.
These constraints are applied to the background in addition to the
content. As a result, you typically add the background fill to a
graphic element that is set to the entire height and width of the
container.
To add a background image, you can use the BitmapFill class
or a BitmapImage fill.
The following example adds a background with a BitmapFill object:
In this example, the container is perfectly sized to fit the
bitmap background plus the width of the border. In many cases, though,
you will have to set properties on the fill to avoid tiling or apply
clipping. For more information, see the BitmapFill class in the ActionScript 3.0 Reference for the Adobe
Flash Platform.
The content group of the container’s skin is typically the last
element defined in the skin class. This is because the skin’s layers
are applied in the order in which they appear in the skin class.
When a skin class has a background fill in a skin class, you add
the content layer after it so that the content is not covered by
the fill.
You can use the depth property, which gives
you more control over the z-index. This lets you rearrange the appearance
of the skin’s elements so that it is not determined by the child
order.