You can use the list I've created with required functionality:
package
{
import flash.events.Event;
import mx.collections.IList;
import spark.components.List;
import spark.components.supportClasses.TextBase;
[SkinState("disabledEmpty")]
[SkinState("normalEmpty")]
public class ListWithMessage extends List
{
[SkinPart(required = "false")]
public var emptyMessageLabel:TextBase;
/**
* @inheritDoc
*/
override public function set dataProvider(value:IList):void
{
super.dataProvider = value;
invalidateSkinState();
}
//--------------------------------------
// emptyMessage
//--------------------------------------
private var _emptyMessage:String = "Empty";
public function get emptyMessage():String
{
return _emptyMessage;
}
public function set emptyMessage(value:String):void
{
if (_emptyMessage == value)
return;
_emptyMessage = value;
invalidateProperties();
}
/**
* @inheritDoc
*/
override protected function commitProperties():void
{
super.commitProperties();
if (emptyMessageLabel)
emptyMessageLabel.text = _emptyMessage;
}
/**
* @inheritDoc
*/
override protected function getCurrentSkinState():String
{
var state:String = super.getCurrentSkinState();
if (isListEmpty())
state += "Empty";
return state;
}
/**
* @inheritDoc
*/
override protected function partAdded(partName:String, instance:Object):void
{
super.partAdded(partName, instance);
if (instance == emptyMessageLabel)
emptyMessageLabel.text = _emptyMessage;
}
private function isListEmpty():Boolean
{
return !dataProvider || dataProvider.length == 0;
}
/**
* @inheritDoc
*/
override protected function dataProvider_collectionChangeHandler(event:Event):void
{
super.dataProvider_collectionChangeHandler(event);
invalidateSkinState();
}
}
}
The sample skin for this list:
<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009" minWidth="112"
alpha.disabledGroup="0.5" blendMode="normal">
<fx:Metadata>[HostComponent("ListWithMessage")]</fx:Metadata>
<fx:Script fb:purpose="styling">
/* Define the skin elements that should not be colorized.
For list, the skin itself is colorized but the individual parts are not. */
static private const exclusions:Array = ["scroller", "background"];
/**
* @private
*/
override public function get colorizeExclusions():Array {return exclusions;}
/* Define the content fill items that should be colored by the "contentBackgroundColor" style. */
static private const contentFill:Array = ["bgFill"];
/**
* @private
*/
override public function get contentItems():Array {return contentFill};
/**
* @private
*/
override protected function initializationComplete():void
{
useChromeColor = true;
super.initializationComplete();
}
/**
* @private
*/
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
if (getStyle("borderVisible") == true)
{
border.visible = true;
background.left = background.top = background.right = background.bottom = 1;
scroller.minViewportInset = 1;
}
else
{
border.visible = false;
background.left = background.top = background.right = background.bottom = 0;
scroller.minViewportInset = 0;
}
borderStroke.color = getStyle("borderColor");
borderStroke.alpha = getStyle("borderAlpha");
super.updateDisplayList(unscaledWidth, unscaledHeight);
}
</fx:Script>
<s:states>
<s:State name="normal" stateGroups="normalGroup" />
<s:State name="disabled" stateGroups="disabledGroup" />
<s:State name="normalEmpty" stateGroups="emptyGroup,normalGroup" />
<s:State name="disabledEmpty" stateGroups="emptyGroup,disabledGroup" />
</s:states>
<fx:Declarations>
<!---
Defines the appearance of the the List's drop indicator.
To customize the drop indicator appearance, create a custom ListSkin class.
The List's layout takes care to size and position the dropIndicator.
The size of the <code>dropIndicator</code> is typically set to the size of the gaps between the items.
The minimum and maximum settings are typically respected only in the direction
along the major axis (the gap axis). For example a VerticalLayout ignores the
<code>minWidth</code> and <code>maxWidth</code> settings,
but respect <code>minHeight</code> and <code>maxHeight</code>.
@copy spark.components.List#dropIndicator
-->
<fx:Component id="dropIndicator">
<s:Group minWidth="3" minHeight="3" maxWidth="3" maxHeight="3">
<s:Rect left="0" right="0" top="0" bottom="0">
<s:fill>
<!--- Defines the color of the background. -->
<s:SolidColor color="0xBBBBBB" />
</s:fill>
<s:stroke>
<s:SolidColorStroke color="0x868686" weight="1"/>
</s:stroke>
</s:Rect>
</s:Group>
</fx:Component>
</fx:Declarations>
<!-- border -->
<!--- @private -->
<s:Rect left="0" right="0" top="0" bottom="0" id="border">
<s:stroke>
<!--- @private -->
<s:SolidColorStroke id="borderStroke" weight="1"/>
</s:stroke>
</s:Rect>
<!-- fill -->
<!--- Defines the background appearance of the list-based component. -->
<s:Rect id="background" left="1" right="1" top="1" bottom="1" >
<s:fill>
<!--- Defines the color of the background. The default color is 0xFFFFFF. -->
<s:SolidColor id="bgFill" color="0xFFFFFF" />
</s:fill>
</s:Rect>
<!--- The Scroller component to add scroll bars to the list. -->
<s:Scroller left="0" top="0" right="0" bottom="0" id="scroller" minViewportInset="1" hasFocusableChildren="false">
<!--- @copy spark.components.SkinnableDataContainer#dataGroup -->
<s:DataGroup id="dataGroup" itemRenderer="spark.skins.spark.DefaultItemRenderer">
<s:layout>
<!--- The default layout is vertical and measures at least for 5 rows.
When switching to a different layout, HorizontalLayout for example,
make sure to adjust the minWidth, minHeihgt sizes of the skin -->
<s:VerticalLayout gap="0" horizontalAlign="contentJustify" requestedMinRowCount="5" />
</s:layout>
</s:DataGroup>
</s:Scroller>
<s:Label id="emptyMessageLabel" fontSize="16" fontWeight="bold" color="#333333" verticalCenter="0"
horizontalCenter="0" width="100%" textAlign="center" includeIn="emptyGroup" />
</s:SparkSkin>
Usage sample:
<?xml version="1.0" encoding="utf-8"?>
<s:Application minHeight="600" minWidth="955" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:local="*"
xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
protected function button1_clickHandler(event:MouseEvent):void
{
var item:Object = { label: Math.random() };
if (list.dataProvider)
list.dataProvider.addItem(item);
else
{
var dp:ArrayCollection = new ArrayCollection();
dp.addItem(item);
list.dataProvider = dp;
}
}
]]>
</fx:Script>
<s:VGroup horizontalCenter="0" verticalCenter="0">
<local:ListWithMessage allowMultipleSelection="false" emptyMessage="Empty List" enabled="{listEnabled.selected}"
height="400" id="list" skinClass="ListWithMessageSkin" width="400" />
<s:CheckBox id="listEnabled" selected="true" label="List enabled" />
<s:Button click="button1_clickHandler(event)" label="Add Item" />
<s:Button click="list.dataProvider.removeItemAt(list.selectedIndex)" enabled="{list.selectedItem}"
label="Remove Item" />
</s:VGroup>
</s:Application>
Hope this helps!