graphic element - A graphical element like a Rectangle, Path, or Bitmap. This element is not a subclass of DisplayObject; however, it does need a DisplayObject to render on to.
visual element - A visual element (a.k.a. - "element"). This can be a halo component, a gumbo component, or a graphic element. Visual elements implement IVisualElement
.
data item (a.k.a. - "item") - Basically anything is considered a data item. Mostly it refers to a non-visual item like a String, Number, XMLNode, etc. A visual element can also be a data item--it just depends on how it's treated.
DataGroup is the simple container class in Gumbo for holding data items and item rendering. DataGroup does NOT extend Group, which is the simple container class in Gumbo for holding visual elements. DataGroup takes data items and converts them to visual elements. DataGroup extends GroupBase, which extends UIComponent and is designed to be both flexible and lightweight.
In the future (and not mentioned in this spec), DataGroup will support virtualization. Layout is handled by a separate layout object, so that the DataGroup just delegates measure()
and updateDisplayList()
calls to this layout object. This is different from Halo where containment and layout were baked into the Container, List, and other individual components.
There are several key differences between the DataGroup class and the Group class:
addElement(), removeElement(), swapElements(), etc…
). For a DataGroup, dataProvider
is a read-write property typed as an IList
. To manipulate the items, you should use the IList
APIs defined on the dataProvider
. There are several key differences between the DataGroup class and the Halo List class:
<!-- This is the item renderer definition. The datagroup data item
is bound into the renderer. -->
MyItemRenderer.mxml
<s:ItemRenderer>
<s:states>
<s:State name="normal"/>
<s:State name="hovered"/>
<s:State name="selected"/>
</s:states>
<s:layout><s:HorizontalLayout /></s:layout>
<mx:Label text="{data.lastName}, {data.firstName}" />
<mx:Image source="{data.imageURL}" />
</s:ItemRenderer>
<!-- The ArrayCollection defines the DataGroup's dataProvider. Each
dataProvider element is converted to a visual element with the the
item renderer. -->
<s:DataGroup itemRenderer="MyItemRenderer">
<mx:ArrayCollection>
<fx:Object firstName="Chet" lastName="Haase" imageUrl="http://..." />
<fx:Object firstName="Corey" lastName="Lucier" imageUrl="http://..." />
<fx:Object firstName="Ely" lastName="Greenfield" imageUrl="http://..." />
<fx:Object firstName="Evtim" lastName="Georgiev" imageUrl="http://..." />
<fx:Object firstName="Glenn" lastName="Ruehle" imageUrl="http://..." />
</mx:ArrayCollection>
</s:DataGroup>
<s:Skin xmlns...>
<!-- fill -->
<s:Rect id="backgroundRect" left="0" right="0" top="0" bottom="0">
<s:fill>
<s:SolidColor color="0xCCCCCC" />
</s:fill>
</s:Rect>
<!-- This datagroup is the main dataGroup for the panel. The
Panel will push its content into this datagroup -->
<s:DataGroup id="dataGroup" left="5" top="5" right="5" bottom="35">
<s:layout><s:VerticalLayout /></s:layout>
</s:DataGroup>
</s:Skin>
A DataGroup represents a mutable ordered list of data items. Items are managed through the IList
methods on the dataProvider
directly. The dataProvider
property is the default property of DataGroup
. Because you are using the APIs on the dataProvider
directly, there is a public getter and setter for this property. The DataGroup takes the data items in the list and creates visual elements to layout and display, using the follow presentation rules:
Note that in the above steps, an item renderer may be created, even for visual elements.
You can access the item renderers (the visual elements created to represent the data) directly by using [[ numElements ]], [[ getElementAt() ]], and [[ getVirtualElementAt() ]]. The Flash DisplayObjectContainer numChildren and getChildAt() APIs can also be used to iterate the visual children on-screen; however, the APIs that add, remove or shuffle children should not be called, and will throw an RTE if they are called.
An item renderer may be created for each data element in a DataGroup's dataProvider. This renderer is the visual representation of the data element.
The itemRenderer
property specifies an IFactory
that is used to instantiate an instance of a renderer. The renderer should implement the IDataRenderer
interface. The item is assigned to the data
property of the renderer. If it doesn't implement IDataRenderer
, the data property is not set, and your renderer doesn't really do much of rendering data.
The itemRendererFunction
property is used to specify a callback function that returns an item renderer for a specific dataProvider data element. The function is passed an item and returns an IFactory that is used to create the renderer. It takes precedence over the itemRenderer
property.
Example: itemRendererFunction
private function myItemRendererFunction(item:*):IFactory
{
// "employee" and "contractor" get special renderers.
if (item.status == "employee")
return employeeItemRenderer;
else if (item.status == "contractor")
return contractorItemRenderer;
// everyone else gets the default renderer.
return defaultItemRenderer;
}
The way to control whether an item renderer gets created for an individual visual element is through itemRendererFunction
. If it returns null (and there's no itemRenderer specified), DataGroup will use the visual element directly (this doesn't work for data items because there needs to be a visual representation).
DataGroup's primary use-case is for dealing with data items--creating a visual representation of the data through item renderers and laying out the item renderers appropriately. However, sometimes you may want a visual element to go inside of the DataGroup directly, like a List of images. If there is no itemRenderer
or itemRendererFunction
specified (or if the itemRendererFunction
returns null for this particular data item), DataGroup will use the data item directly as long as it implements IVisualElement
and is a DisplayObject
. However, doing this will just display the item directly in the DataGroup with no hovering or selection indicators. That is because, unlike Halo, the item renderer itself is responsible for these visual aspects (the List does set the selected
property on the item renderer, but the item renderer figures out how to display that visually). If you want to wrap a visual element in an item renderer to get the selection or hovering visuals, you can use spark.skins.default.DefaultComplexItemRenderer
, which has a Rect for the visuals and will throw the data into a Group for rendering. You can also create your own item renderer that does something similar and knows how to handle visual element data items.
The DataGroup does not support graphic elements directly. Group has code to deal with graphic elements and minimizing the number of display objects needed for graphic elements through display object sharing, but DataGroup does not. All item renderers (or data items that aren't wrapped in item renderers) must implement IVisualElement and be a DisplayObject. The primary use-case for DataGroup is for rendering data on-screen, not for displaying graphical elements directly. If you must have GraphicElements in your dataProvider, the DataGroup can render them as long as it is put in to a valid item renderer. You can use spark.skins.default.DefaultComplexItemRenderer
, or a similar item renderer that puts the graphic element inside of a Group for rendering.
Layout and measurement are handled by a separate object, which can be changed dynamically at runtime. Details about layout management are in the layout spec. The important parts to know are:
measure()
and updateDisplayList()
to this layout object.Clipping and scrolling are supported by the clipAndEnableForScrolling
, horizontalScrollPosition
, verticalScrollPosition
, contentWidth
, and contentHeight
properties. Display and management of scrollbars will be done by FxScroller
. See the Spark Viewport spec for more info.
Masking is supported by the DisplayObject mask
property.
For implementation purposes, GroupBase
is a base class for Group
and DataGroup
so that code isn't duplicated across both classes. It's essentially an abstract base class with some implementations for common methods. GroupBase isn't documented here, but you can find more info about the API in the Spark Group spec.
package mx.events
{
/**
* Represents events that are dispatched when a renderer of a DataGroup
* is added or removed.
*/
public class RendererExistenceEvent extends Event
{
//--------------------------------------------------------------------------
//
// Class constants
//
//--------------------------------------------------------------------------
/**
* The <code>RendererExistenceEvent.Renderer_ADD</code> constant
* defines the value of the <code>type</code> property of the event
* object for an <code>rendererAdd</code> event.
*
* <p>The properties of the event object have the following values:</p>
* <table class="innertable">
* <tr><th>Property</th><th>Value</th></tr>
* <tr><td><code>bubbles</code></td><td>false</td></tr>
* <tr><td><code>cancelable</code></td><td>false</td></tr>
* <tr><td><code>currentTarget</code></td><td>The Object that defines the
* event listener that handles the event. For example, if you use
* <code>myButton.addEventListener()</code> to register an event listener,
* myButton is the value of the <code>currentTarget</code>. </td></tr>
* <tr><td><code>data</code></td><td>The data object that the renderer
* is visualizing.</td></tr>
* <tr><td><code>index</code></td><td>The dataProvider index for the
* renderer that was added.</td></tr>
* <tr><td><code>renderer</code></td><td>Contains a reference
* to the renderer that was added</td></tr>
* <tr><td><code>target</code></td><td>The Object that dispatched the event;
* it is not always the Object listening for the event.
* Use the <code>currentTarget</code> property to always access the
* Object listening for the event.</td></tr>
* </table>
*
* @eventType rendererAdd
*/
public static const RENDERER_ADD:String = "rendererAdd";
/**
* The <code>RendererExistenceEvent.RENDERER_REMOVE</code> constant
* defines the value of the <code>type</code> property of the event
* object for an <code>rendererRemove</code> event.
*
* <p>The properties of the event object have the following values:</p>
* <table class="innertable">
* <tr><th>Property</th><th>Value</th></tr>
* <tr><td><code>bubbles</code></td><td>false</td></tr>
* <tr><td><code>cancelable</code></td><td>false</td></tr>
* <tr><td><code>currentTarget</code></td><td>The Object that defines the
* event listener that handles the event. For example, if you use
* <code>myButton.addEventListener()</code> to register an event listener,
* myButton is the value of the <code>currentTarget</code>. </td></tr>
* <tr><td><code>data</code></td><td>The data object that the renderer
* was visualizing.</td></tr>
* <tr><td><code>index</code></td><td>The dataProvider index for the
* renderer that is being removed.</td></tr>
* <tr><td><code>renderer</code></td><td>Contains a reference
* to the renderer that is about to be removed.</td></tr>
* <tr><td><code>target</code></td><td>The Object that dispatched the event;
* it is not always the Object listening for the event.
* Use the <code>currentTarget</code> property to always access the
* Object listening for the event.</td></tr>
* </table>
*
* @eventType rendererRemove
*/
public static const RENDERER_REMOVE:String = "rendererRemove";
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*
* @param type The event type; indicates the action that caused the event.
*
* @param bubbles Specifies whether the event can bubble up the display list hierarchy.
*
* @param cancelable Specifies whether the behavior associated with the event can be prevented.
*
* @param renderer Reference to the renderer that was added or removed.
*
* @param index The index in the dataprovider where the renderer was added or removed
*
* @param data The data object that the renderer is visualizing
*/
public function RendererExistenceEvent(
type:String, bubbles:Boolean = false,
cancelable:Boolean = false,
renderer:IVisualElement = null,
index:int = -1, data:Object = null);
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// data
//----------------------------------
/**
* The data object that the renderer is visualizing
*/
public var data:Object;
//----------------------------------
// index
//----------------------------------
/**
* The index where the renderer was added or removed
*/
public var index:int;
//----------------------------------
// renderer
//----------------------------------
/**
* Reference to the render that was added or removed.
*/
public var renderer:IVisualElement;
}
}
//
//
package mx.components
{
/**
* Dispatched when a renderer is added to the content holder.
* <code>event.renderer</code> is the renderer that was added.
*
* @eventType mx.events.RendererExistenceEvent.RENDERER_ADD
*/
<a href="Event%28name%3D%26quot%3BrendererAdd%26quot%3B%2C%20type%3D%26quot%3Bmx.events.RendererExistenceEvent%26quot%3B%29">Event(name="rendererAdd", type="mx.events.RendererExistenceEvent")</a>
/**
* Dispatched when a renderer is removed from the content holder.
* <code>event.renderer</code> is the renderer that was removed.
*
* @eventType mx.events.RendererExistenceEvent.ITEM_REMOVE
*/
<a href="Event%28name%3D%26quot%3BrendererRemove%26quot%3B%2C%20type%3D%26quot%3Bmx.events.RendererExistenceEvent%26quot%3B%29">Event(name="rendererRemove", type="mx.events.RendererExistenceEvent")</a>
<a href="DefaultProperty%28%26quot%3BdataProvider%26quot%3B%29">DefaultProperty("dataProvider")</a>
class DataGroup extends GroupBase
{
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
/**
* DataProvider for this DataGroup. It must be an IList.
*
* <p>There are several IList implementations included in the
* XMLListCollection.</p>
*
* @default null
*
* @see #itemRenderer
* @see #itemRendererFunction
*/
public function get dataProvider():IList;
public function set dataProvider(value:IList):void;
/**
* Renderer to use for data items. The class should
* implement the IDataRendererinterface.
* The itemRendererFunction property,
* if defined, takes precedence over this property.
*
* @default null
*/
public function get itemRenderer():IFactory;
public function set itemRenderer(value:IFactory):void;
/**
* Function that returns an item renderer for a specific item.
* The signature of the function is:
*
* function itemRendererFunction(item:Object):IFactory
*
* @default null
*/
public function get itemRendererFunction():Function;
public function set itemRendererFunction(value:Function):void;
//--------------------------------------------------------------------------
//
// Protected methods
//
//--------------------------------------------------------------------------
/**
* Called when contents within the dataProvider changes. We will catch certain
* events and update our children based on that.
*
* @param event The collection change event
*/
protected function dataProvider_collectionChangeHandler(event:CollectionEvent):void;
}
}
None at this time.
None planned.
Not Applicable.
Spark Group - Group is for holding visual elements. DataGroup is for holding data items.
Layout - There is obviously a tight relationship between layout elements and DataGroup. Refer to the Layout specification for more information.
Focus - DataGroup is not focusable, but items within the datagroup must be able to receive focus.
Styles - DataGroup does not have styles, but can be a style parent (either direct or proxy) for the items within the datagroup.
Spark Virtualization - This is mostly baked into DataGroup and layouts, but specced separately.
Spark Viewport - Containers need the ability to scroll. This will be done through the Scroller
class.
Spark SkinnableDataContainer - The skinnable version of DataGroup.
List - The list component, which wraps a DataGroup and provides selection support.
ItemRenderer - Item Renderers are how data items are visualized.
None. This is a new class.
None, for existing content. For new content, there are some fundamental differences between DataGroup and the old mx:List class that need to be understood.
None.
None, directly. The DataGroup class itself does not have any accessibility features, but it does need to support accessibility of its children.
Size and speed are both critical elements of the DataGroup class. A typical application may end up with hundreds of DataGroup objects at runtime, so performance testing must be done early and often.
None. Right to left or vertical orientation is handled by the various layout classes, and does not require any specific functionality from DataGroup.
Not applicable.
List the RTE message strings that will require localization. (They must all come from .properties files.)
RTE messages are displayed when calling the Flash DisplayObjectContainer children APIs directly - addChild()/removeChild()/etc.
List all UI text that will require localization, such as the month and day names in a DateChooser. (All such text must all come from .properties files.)
None.
List all UI images, skins, sounds, etc. that will require localization.
None.
Discuss any locale-specific formatting requirements for numbers, dates, currency, etc.
None.
Discuss any locale-specific sorting requirements.
None.
Extensible data support. DataGroup has basic support for IList, but does not directly support paging data sets. Ideally, this could be layered on with either a subclass or an intermediate proxy object that implements IList.
[[ /getVirtualElementAt() ]][[ /getElementAt() ]][[ /numElements ]]
Wiki: Flex 4
Wiki: Gumbo Component Architecture
Wiki: Spark DataGrid
Wiki: Spark Group
Wiki: Spark List
Wiki: Spark Scroller
Wiki: Spark SkinnableDataContainer
Wiki: Spark Viewport
Wiki: Spark Virtualization