I have a custom Flex 4.5 component (to be used in a List) -
Game.mxml (represents a clickable playing table in a card game):
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:comps="*"
width="160" height="160"
autoDrawBackground="false"
creationComplete="init(event)">
<fx:Metadata>
[Event(name="pref_event", type="PrefEvent")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
private var _data:XML;
[Bindable("dataChange")]
public override function get data():Object {
return _data;
}
public override function set data(value:Object):void {
_data = value as XML;
if (null == _data)
return;
gameid = _data.#id;
for (var i:uint = 0; i < 3; i++) {
this['_user' + i].data = _data.elements('user')[i];
}
dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
}
public function init(event:FlexEvent):void {
_rect.filters = Util.SHADOW;
addEventListener(MouseEvent.CLICK, handleClick);
}
private function handleClick(event:MouseEvent):void {
trace("Clicked: " + gameid);
dispatchEvent(new PrefEvent(PrefEvent.GAME_CLICKED, gameid, true));
}
public function set gameid(str:String):void {
_gameid.text = '#' + str;
}
public function get gameid():String {
return _gameid.text.substring(1);
}
]]>
</fx:Script>
<s:Rect id="_rect" x="20" y="20" width="120" height="120" radiusX="16" radiusY="16">
<s:stroke>
<s:SolidColorStroke color="#4F69B5" weight="4"/>
</s:stroke>
<s:fill>
<s:SolidColor color="#CCDDEE" />
</s:fill>
</s:Rect>
<s:Label id="_gameid" x="0" y="75" width="{width}" fontSize="16" textAlign="center" color="#FFFFFF" />
<comps:User id="_user0" x="56" y="4" scaleX=".3" scaleY=".3" interactive="false" visible="false" />
<comps:User id="_user1" x="108" y="60" scaleX=".3" scaleY=".3" interactive="false" visible="false" />
<comps:User id="_user2" x="4" y="60" scaleX=".3" scaleY=".3" interactive="false" visible="false" />
</s:ItemRenderer>
and I'm trying to dispatch a custom event from it - PrefEvent.as:
package {
import flash.events.Event;
public class PrefEvent extends Event {
public var str:String;
public static const GAME_CLICKED:String = 'game_clicked';
public static const CARD_CLICKED:String = 'card_clicked';
public static const CARD_PLAYED:String = 'card_played';
public function PrefEvent(type:String, n:String, bubbles:Boolean = false, cancelable:Boolean = false){
super(type, bubbles,cancelable);
str = n;
}
public override function clone():Event {
return new PrefEvent(type, str, bubbles, cancelable);
}
public override function toString():String {
return str;
}
}
}
And here is finally my test code - GameTest.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:comps="*"
width="700" height="525"
creationComplete="init()">
<fx:Script>
<![CDATA[
public function init():void {
game.data = <game id="8946">
<user id="OK353118989212"/>
<user id="OK351923295875"/>
</game>;
}
private function gameClicked(event:PrefEvent):void {
trace("game clicked: " + event);
}
]]>
</fx:Script>
<comps:Game id="game" x="0" y="0" pref_event="gameClicked(event)" />
</s:Application>
But I never see the "game clicked: " trace. Does anybody please know why?
I'm probably missing something minor, because I can see the "Clicked: 8946" trace.
Problem:
In Game.mxml File has "pref_event" Event
[Event(name="pref_event", type="PrefEvent")]
but your dispatching PrefEvent.GAME_CLICKED ("game_clicked").
Solution:
You must dispatch the right event for this.
dispatchEvent( new PrefEvent("pref_event",gameid, true) );
[Event(name="pref_event", type="PrefEvent")] != new PrefEvent(PrefEvent.GAME_CLICKED, gameid, true)
The name of the events are not the same.
You should write this in your Game.mxml file :
<fx:Metadata>
[Event(name="game_clicked", type="PrefEvent")]
</fx:Metadata>
And this in your main file :
<comps:Game id="game" x="0" y="0" game_clicked="gameClicked(event)" />
See here for further informations...
Related
I have a datagrid with 2 columns. I need to access the item renderer of the second column whenever column-1 value changes. i.e if value of column 1 is A- need to display text field in column2 and if value is B, i need to show dropdown.
Col1----------Col2
A ---------- DropDown
B ---------- TextBox
A ---------- DropDown
Any Solutions???
public class ItemRendererfroDropTest extends GridItemRenderer
{
private var dropdown:DropDownList;
public function ItemRendererfroDropTest()
{
super();
dropdown=new DropDownList();
dropdown.dataProvider=new ArrayCollection(new Array("ABC","PQR"));
this.addElement(dropdown);
dropdown.addEventListener(FlexEvent.VALUE_COMMIT,dataChanged);
}
private function dataChanged(event:FlexEvent):void
{
owner.dispatchEvent(new CustomEvent(CustomEvent.DATA_CHANGED,true));
}
}
public class ItemRenderlabel extends GridItemRenderer
{
public var wlabel:Label=new Label();
public var checkbox:CheckBox=new CheckBox();
public function ItemRenderlabel()
{
super();
this.addEventListener(CustomEvent.DATA_CHANGED,mappingChanged,true);
this.addElement(wlabel);
}
private function mappingChanged(e:CustomEvent):void
{
Alert.show("asfAS");
}
}
You can get some idea from below code: - Event you can do it only for particular item by using dpHierarchy.itemUpdated() by updating individual row.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
creationComplete="init()">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
[Bindable]
private var dpHierarchy:ArrayCollection= new ArrayCollection([
{name:"A", region: "Arizona"},
{name:"B", region: "Arizona"},
{name:"C", region: "California"},
{name:"D", region: "California"}
]);
private function init():void
{
this.addEventListener(FlexEvent.DATA_CHANGE, changeDataHandler);
}
private function changeDataHandler(event:FlexEvent):void
{
dpHierarchy.refresh();
}
]]>
</fx:Script>
<mx:AdvancedDataGrid id="myADG"
width="100%" height="100%"
variableRowHeight="true" dataProvider="{dpHierarchy}">
<mx:columns>
<mx:AdvancedDataGridColumn dataField="name" headerText="Name" itemRenderer="AddComboboxADG"/>
<mx:AdvancedDataGridColumn dataField="region" headerText="Region" itemRenderer="SelectedCustomComponent"/>
</mx:columns>
</mx:AdvancedDataGrid>
</s:Application>
//AddComboboxADG custom item renderer
<?xml version="1.0" encoding="utf-8"?>
<s:MXAdvancedDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
focusEnabled="true">
<fx:Script>
<![CDATA[
import mx.controls.AdvancedDataGrid;
import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn;
import mx.controls.advancedDataGridClasses.AdvancedDataGridHeaderRenderer;
import mx.controls.advancedDataGridClasses.AdvancedDataGridListData;
import mx.events.AdvancedDataGridEvent;
import mx.events.DataGridEvent;
import mx.events.FlexEvent;
import mx.events.ItemClickEvent;
import spark.components.supportClasses.ItemRenderer;
import spark.events.IndexChangeEvent;
protected function comboBoxID_changeHandler(event:IndexChangeEvent):void
{
data.name = comboBoxID.selectedItem;
dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE, true));
}
override public function set data(value:Object):void
{
super.data = value;
if(data.name == "A")
{
comboBoxID.selectedIndex = 0;
}else if(data.name == "B")
{
comboBoxID.selectedIndex = 1;
}else if(data.name == "C")
{
comboBoxID.selectedIndex = 2;
}else
{
comboBoxID.selectedIndex = 3;
}
}
]]>
</fx:Script>
<s:DropDownList id="comboBoxID" change="comboBoxID_changeHandler(event)">
<s:ArrayCollection>
<fx:String>A</fx:String>
<fx:String>B</fx:String>
<fx:String>C</fx:String>
<fx:String>D</fx:String>
</s:ArrayCollection>
</s:DropDownList>
</s:MXAdvancedDataGridItemRenderer>
//SelectedCustomComponent custom item renderer
<?xml version="1.0" encoding="utf-8"?>
<s:MXAdvancedDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
focusEnabled="true">
<fx:Script>
<![CDATA[
override public function set data(value:Object):void
{
super.data = value;
customFirstDropDown.visible = customTextInput.visible = customSecondDropDown.visible = lblData.visible = false;
if(data.name == "A")
{
customFirstDropDown.visible = true;
}else if(data.name == "B")
{
customTextInput.visible = true;
}else if(data.name == "C")
{
customSecondDropDown.visible = true;
}else
{
lblData.visible = true;
}
}
]]>
</fx:Script>
<s:DropDownList id="customFirstDropDown" visible="false" selectedIndex="0">
<s:ArrayCollection>
<fx:String>First</fx:String>
<fx:String>Second</fx:String>
<fx:String>Third</fx:String>
</s:ArrayCollection>
</s:DropDownList>
<s:TextInput id="customTextInput" visible="false" text="Selected"/>
<s:DropDownList id="customSecondDropDown" visible="false" selectedIndex="0">
<s:ArrayCollection>
<fx:String>1</fx:String>
<fx:String>2</fx:String>
<fx:String>3</fx:String>
</s:ArrayCollection>
</s:DropDownList>
<s:Label id="lblData" visible="false" text="Selected"/>
</s:MXAdvancedDataGridItemRenderer>
Create Item renderer using ViewStack with views as required, and override data function as normally done for item renderer, to set active child of container base of field, If you wants to set Active child on fly see this post
Hopes that helps
I have an object in flex - which i want to appear upon a button clicked, disappear after 10 seconds or if the object is closed, and reappear if that same button pressed.
i've tried something like this:
public class my_obj
{
private var _myTimer: Timer;
public function my_obj()
{
_myTimer = new Timer(10000);
}
private function init(): void
{
_myTimer.addEventListener(TimerEvent.TIMER, onTimeout);
_myTimer.start();
}
private function onTimerTimeOut(event: TimerEvent): void
{
dispatchEvent(new Event(CLOSE_EVENT));
}
}
what am i missing?
Thanks!
Working fine. Here's the working code sample:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:Panel width="100%" height="400" creationComplete="my_obj()">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
private var _myTimer: Timer;
public function my_obj():void
{
_myTimer = new Timer(10000);
}
private function init(): void
{
toggleBtn.visible = true;
_myTimer.addEventListener(TimerEvent.TIMER, onTimeout);
_myTimer.start();
}
private function onTimeout(event: TimerEvent): void
{
toggleBtn.visible = false;
//dispatchEvent(new Event(CLOSE_EVENT));
}
private function hideIt(): void
{
toggleBtn.visible = false;
}
]]>
</fx:Script>
<s:Button label="Some Button" click="init()"/>
<s:Button id="toggleBtn" label="Appeared on 'Some Button' click. Click to close it." click="hideIt()" visible="false"/>
</s:Panel>
</s:WindowedApplication>
Please check the below code:
userinfo.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" creationComplete="init();">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
<!--Validation Start-->
<mx:StringValidator source="{userNameInput}" property="text"
requiredFieldError="Please enter only string"/>
<mx:StringValidator source="{locationInput}" property="text"
requiredFieldError="Please enter only string"/>
<mx:Validator source="{genderfield}" property="selectedValue"
triggerEvent="change"
requiredFieldError="One Option must be selected"
listener="{wrapper}"/>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.events.ItemClickEvent;
import mx.events.ListEvent;
import mx.utils.ObjectUtil;
private var mySO:SharedObject;
private var _objValidation:ValidationField;
[Bindable]public var dgItems:ArrayCollection = new ArrayCollection();
public function init():void{
_objValidation = new ValidationField();
mySO = SharedObject.getLocal("newData","/");
if(mySO.data.info != null){
dgItems = mySO.data.info;
}
addbtn.label = "Add";
addbtn.addEventListener(MouseEvent.CLICK, call);
}
public function resetForm():void{
userNameInput.text = "";
locationInput.text = "";
genderfield.selection = null;
userNameInput.errorString = "";
locationInput.errorString = "";
}
public function addItem():void{
if(userNameInput.text != "" && locationInput.text != "" && genderfield.selection != null){
dgItems.addItem({name:userNameInput.text,location:locationInput.text,gender:genderfield.selectedValue});
resetForm();
}
}
public function savaData():void{
mySO.data.info = dgItems;
mySO.flush();
}
public function deleteRow():void{
while(datagrid.selectedItem != null){
dgItems.removeItemAt(datagrid.selectedIndex);
}
addbtn.label = "Add";
resetForm();
}
public function dgChangeHandler():void{
addbtn.label = "Edit";
resetForm();
userNameInput.text = datagrid.selectedItem.name;
locationInput.text = datagrid.selectedItem.location;
genderfield.selectedValue = datagrid.selectedItem.gender;
}
public function call(event:Event):void{
if(event.currentTarget.label == "Add"){
addItem();
}
else if(event.currentTarget.label == "Edit"){
editRow();
}
addbtn.label = "Add";
resetForm();
}
public function editRow():void{
if(datagrid.selectedItem != null){
dgItems.setItemAt({name:userNameInput.text,location:locationInput.text,gender:genderfield.selectedValue},datagrid.selectedIndex);
resetForm();
}
}
]]>
</fx:Script>
<mx:Form x="250">
<mx:FormHeading label="User Information" fontWeight="bold"/>
<mx:FormItem required="true" label="UserName" fontWeight="bold">
<s:TextInput id="userNameInput" restrict="A-Z a-z"/>
</mx:FormItem>
<mx:FormItem required="true" label="Location" fontWeight="bold">
<s:TextInput id="locationInput" restrict="A-Z a-z"/>
</mx:FormItem>
<mx:FormItem required="true" label="Gender" fontWeight="bold" width="210">
<mx:HBox id="wrapper">
<s:RadioButtonGroup id="genderfield"/>
<s:RadioButton label="Male" groupName="genderfield"/>
<s:RadioButton label="Female" groupName="genderfield"/>
</mx:HBox>
</mx:FormItem>
<mx:FormItem>
<mx:HBox>
<mx:Button id="addbtn"/>
<mx:Button label="Reset" click="resetForm();"/>
</mx:HBox>
</mx:FormItem>
</mx:Form>
<mx:DataGrid id="datagrid" x="550" y="20" dataProvider="{dgItems}" change="dgChangeHandler();">
<mx:columns>
<mx:DataGridColumn headerText="Visible" dataField="shouldDelete" textAlign="center" itemRenderer="CheckBoxRenderer">
</mx:DataGridColumn>
<mx:DataGridColumn headerText="UserName" dataField="name" textAlign="center"/>
<mx:DataGridColumn headerText="Location" dataField="location" textAlign="center"/>
<mx:DataGridColumn headerText="Gender" dataField="gender" textAlign="center"/>
</mx:columns>
</mx:DataGrid>
<mx:HBox x="650" y="250" horizontalGap="30">
<s:Button label="Delete" click="deleteRow();"/>
<s:Button label="Save" click="savaData();"/>
</mx:HBox>
</s:Application>
and
checkboxRenderer.mxml
package
{
import flash.events.Event;
import flash.events.MouseEvent;
import mx.containers.HBox;
import mx.controls.Alert;
import mx.controls.CheckBox;
public class CheckBoxRenderer extends HBox
{
private var cb:CheckBox;
public function CheckBoxRenderer()
{
super();
cb.addEventListener(MouseEvent.CLICK, changeState);
}
public function changeState(event:Event):void{
}
override public function set data(value:Object):void{
if(value!=null){
super.data = value;
removeAllChildren();
cb = new CheckBox();
addChild(cb);
cb.visible = true;
if(false){
cb.selected = true;
Alert.show("checkbox selected");
}
else{
cb.selected = false;
Alert.show("Checkbox unselected");
}
setStyle("verticleAlign","middle");
setStyle("textAlign","center");
setStyle("horizontalCenter","center");
}
}
}
}
can anyone please tell me why i can't get the value of checkbox selected?
and when i select checkbox and then unselect the same checkbox i can't get back to Add button state.
Modifications:
Userinfo.mxml: changes in dgChangeHandler:
Added event, Check added:
CheckBoxRenderer.as:
checkbox creation logic written in constructor,
checkbox enable disable alert moved in changeState method
Check this updated code: [userinfo.mxml]
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="955" minHeight="600" creationComplete="init();">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
<!--Validation Start-->
<mx:StringValidator source="{userNameInput}" property="text" requiredFieldError="Please enter only string"/>
<mx:StringValidator source="{locationInput}" property="text"
requiredFieldError="Please enter only string"/>
<mx:Validator source="{genderfield}" property="selectedValue"
triggerEvent="change"
requiredFieldError="One Option must be selected"
listener="{wrapper}"/>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.events.ItemClickEvent;
import mx.events.ListEvent;
import mx.utils.ObjectUtil;
private var mySO:SharedObject;
[Bindable]
public var dgItems:ArrayCollection = new ArrayCollection();
public function init():void{
mySO = SharedObject.getLocal("newData","/");
if(mySO.data.info != null){
dgItems = mySO.data.info;
} addbtn.label = "Add";
addbtn.addEventListener(MouseEvent.CLICK, call);
}
public function resetForm():void
{
userNameInput.text = "";
locationInput.text = "";
genderfield.selection = null;
userNameInput.errorString = "";
locationInput.errorString = "";
}
public function addItem():void
{
if(userNameInput.text != "" && locationInput.text != "" && genderfield.selection != null)
{
dgItems.addItem({name:userNameInput.text,location:locationInput.text,gender:genderfield.selectedValue});
resetForm();
}
}
public function savaData():void
{
mySO.data.info = dgItems;
mySO.flush();
}
public function deleteRow():void
{
while(datagrid.selectedItem != null)
{
dgItems.removeItemAt(datagrid.selectedIndex);
}
addbtn.label = "Add";
resetForm();
}
public function dgChangeHandler(event:ListEvent):void
{
if(event.itemRenderer is CheckBoxRenderer)
{
addbtn.label = "Add";
resetForm();
return;
}
addbtn.label = "Edit";
resetForm();
userNameInput.text = datagrid.selectedItem.name;
locationInput.text = datagrid.selectedItem.location;
genderfield.selectedValue = datagrid.selectedItem.gender;
}
public function call(event:Event):void
{
if(event.currentTarget.label == "Add")
{
addItem();
}
else if(event.currentTarget.label == "Edit")
{
editRow();
}
addbtn.label = "Add";
resetForm();
}
public function editRow():void
{
if(datagrid.selectedItem != null)
{
dgItems.setItemAt({name:userNameInput.text,location:locationInput.text,gender:genderfield.selectedValue},datagrid.selectedIndex);
resetForm();
}
}
]]>
</fx:Script>
<mx:Form x="250">
<mx:FormHeading label="User Information" fontWeight="bold"/>
<mx:FormItem required="true" label="UserName" fontWeight="bold">
<s:TextInput id="userNameInput" restrict="A-Z a-z"/>
</mx:FormItem>
<mx:FormItem required="true" label="Location" fontWeight="bold">
<s:TextInput id="locationInput" restrict="A-Z a-z"/>
</mx:FormItem>
<mx:FormItem required="true" label="Gender" fontWeight="bold" width="210">
<mx:HBox id="wrapper">
<s:RadioButtonGroup id="genderfield"/>
<s:RadioButton label="Male" groupName="genderfield"/>
<s:RadioButton label="Female" groupName="genderfield"/>
</mx:HBox>
</mx:FormItem>
<mx:FormItem>
<mx:HBox>
<mx:Button id="addbtn"/>
<mx:Button label="Reset" click="resetForm();"/>
</mx:HBox>
</mx:FormItem>
</mx:Form>
<mx:DataGrid id="datagrid" x="550" y="20" dataProvider="{dgItems}" change="dgChangeHandler(event)">
<mx:columns>
<mx:DataGridColumn headerText="Visible" dataField="shouldDelete" textAlign="center" itemRenderer="CheckBoxRenderer">
</mx:DataGridColumn>
<mx:DataGridColumn headerText="UserName" dataField="name" textAlign="center"/>
<mx:DataGridColumn headerText="Location" dataField="location" textAlign="center"/>
<mx:DataGridColumn headerText="Gender" dataField="gender" textAlign="center"/>
</mx:columns>
</mx:DataGrid>
<mx:HBox x="650" y="250" horizontalGap="30">
<s:Button label="Delete" click="deleteRow();"/>
<s:Button label="Save" click="savaData();"/>
</mx:HBox>
</s:Application>
File: [CheckBoxRenderer.as]
package
{
import flash.events.Event;
import flash.events.MouseEvent;
import mx.containers.HBox;
import mx.controls.Alert;
import mx.controls.CheckBox;
public class CheckBoxRenderer extends HBox
{
private var cb:CheckBox;
public function CheckBoxRenderer()
{
super();
removeAllChildren();
cb = new CheckBox();
addChild(cb);
cb.visible = true;
cb.addEventListener(MouseEvent.CLICK, changeState);
setStyle("verticleAlign","middle");
setStyle("textAlign","center");
setStyle("horizontalCenter","center");
}
public function changeState(event:Event):void
{
if(cb.selected)
{
Alert.show("checkbox selected");
}
else
{
Alert.show("Checkbox unselected");
}
}
override public function set data(value:Object):void
{
if(value!=null)
{
super.data = value;
if(false)
{
cb.selected = true;
}
else
{
cb.selected = false;
}
}
}
}
}
Is there a direct way to get the item index of the data inside an itemRenderer? I need to display the item number against each item. I am currently doing a workaround and won't allow reuse of my itemRenderer component.
var index:int = model.dataColl.getItemIndex(data) + 1;
itemNo = index.toString();
This is what i am using now, it works, but the concepts of component reuse and data abstraction are compromised.
I am using Flex 3.
The first answer seems to be working, but slow. It takes O(n^2) time as it runs through dataProvider array to get item index each time.
We can access rowIndex from listData - it represents index of the current visible item. Vertical scroll position from parent List represents the amount of scrolled items:
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" implements="mx.controls.listClasses.IDropInListItemRenderer">
<mx:Script>
<![CDATA[
import mx.controls.listClasses.BaseListData;
import mx.controls.listClasses.ListBase;
[Bindable] private var index:int = 0;
private var _listData:BaseListData;
public function get listData():BaseListData
{
return _listData;
}
public function set listData(value:BaseListData):void
{
_listData = value;
}
override public function set data(value:Object):void
{
super.data = value;
if (data && listData)
index = _listData.rowIndex + ListBase(_listData.owner).verticalScrollPosition;
else
index = 0;
}
]]>
</mx:Script>
<mx:Label text="{index}"/>
<mx:Label text="{data.toString()}"/>
</mx:HBox>
You can use labelFunction to solve your problem. For the simple test application:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application creationComplete="init()" layout="absolute" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
private static const DATA_LENGTH:Number = 100;
[Bindable]
private var dp:ArrayCollection;
private function countFinction(item:Object):String
{
return (dp.getItemIndex(item) + 1).toString();
}
private function init():void
{
var dataArray:Array = [];
for (var i:int = 0; i < DATA_LENGTH; i++)
{
var item:Object = { firstName: "First" + (i + 1), lastName: "Last" + (i + 1) };
dataArray.push(item);
}
dp = new ArrayCollection(dataArray);
}
]]>
</mx:Script>
<mx:List dataProvider="{dp}" height="500" horizontalCenter="0" itemRenderer="TestRenderer"
labelFunction="countFinction" verticalCenter="0" width="500" />
</mx:Application>
You can use the following test renderer:
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox implements="mx.controls.listClasses.IDropInListItemRenderer" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.controls.listClasses.BaseListData;
private var _listData:BaseListData;
/**
* #inheritDoc
*/
public function get listData():BaseListData
{
return _listData;
}
[Bindable(event = "listDataChanged")]
/**
* #inheritDoc
*/
public function set listData(value:BaseListData):void
{
if (value == _listData)
return;
_listData = value;
dispatchEvent(new Event("listDataChanged"));
}
]]>
</mx:Script>
<mx:Label fontWeight="bold" text="{listData.label}" />
<mx:Label text="{data.firstName + ' ' + data.lastName}" />
</mx:HBox>
Item renderer has an item index property on it.
this.itemIndex
Sample:
<s:List>
<s:dataProvider>
<s:ArrayList>
<fx:String>Item 1</fx:String>
<fx:String>Item 2</fx:String>
<fx:String>Item 3</fx:String>
<fx:String>Item 4</fx:String>
<fx:String>Item 5</fx:String>
<fx:String>Item 6</fx:String>
</s:ArrayList>
</s:dataProvider>
<s:itemRenderer>
<fx:Component>
<s:ItemRenderer>
<s:HGroup>
<s:Label text="This index is: {this.itemIndex}" />
<s:Label text="{data}" />
</s:HGroup>
</s:ItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:List>
I would like to create a custom Button component with three labels: left-, center-, and right-justified. I can't just use the label justification property, because I want to use all 3 labels at the same time.
I'm familiar with creating custom components, but I've never tried to build one quite like this before...
Here's what I have so far:
<?xml version="1.0" encoding="utf-8"?>
<s:Button
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
private var labelContentL:String;
private var labelContentC:String;
private var labelContentR:String;
public function set labelL(value:String):void
{
labelContentL = value;
}
public function set labelC(value:String):void
{
labelContentC = value;
}
public function set labelR(value:String):void
{
labelContentR = value;
}
public function get labelL():String
{
return labelContentL;
}
public function get labelC():String
{
return labelContentC;
}
public function get labelR():String
{
return labelContentR;
}
]]>
</fx:Script>
<s:Label id="l" width="100%" text="{labelContentL}" textAlign="left" paddingLeft="10" />
<s:Label id="c" width="100%" text="{labelContentC}" textAlign="center" />
<s:Label id="r" width="100%" text="{labelContentR}" textAlign="right" paddingRight="10" />
</s:Button>
The labels won't change after the button is created, so I'm not worried about the missing [Bindable] metadata.
I'm stuck right now, getting the following compiler error:
Multiple initializer values for default property, 'label', of type 'String'.
...for each of the 3 <s:Label> lines.
Based on this answer to a similar question, I tried adding label="" to my <s:Button> declaration, but that just adds another error.
How do I fix this?
Your problem is that a tag named label under the button tag isn't an item of type label, it's the label used on the button, and is of type string.
Why not do it as a skin, rather than a custom component?
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<!-- host component -->
<fx:Metadata>
[HostComponent("ThreeLabelButton")]
</fx:Metadata>
<!-- states -->
<s:states>
<s:State name="disabled" />
<s:State name="down" />
<s:State name="over" />
<s:State name="up" />
</s:states>
<s:Rect bottomLeftRadiusX="5"
bottomRightRadiusX="5"
topLeftRadiusX="5"
topRightRadiusX="5"
top="0" left="0" right="0" bottom="0">
<s:fill>
<s:SolidColor color.up="#CCCCCC" color.over="#555555" color.down="#888888" />
</s:fill>
</s:Rect>
<mx:Label id="leftLabel" text="{hostComponent.leftText}" left="0" />
<mx:Label id="rightLabel" text="{hostComponent.rightText}" right="0" />
<mx:Label id="centerLabel" text="{hostComponent.centerText}" left="{(this.width - centerLabel.width) / 2}" />
</s:Skin>
This will work with this class:
import mx.controls.Label;
import spark.components.supportClasses.ButtonBase;
public class ThreeLabelButtonComponent extends ButtonBase
{
public function ThreeLabelButtonComponent()
{
super();
}
[SkinPart]
public var leftLabel:Label;
[SkinPart]
public var rightLabel:Label;
[SkinPart]
public var centerLabel:Label;
[Bindable]
public var leftText:String;
[Bindable]
public var rightText:String;
[Bindable]
public var centerText:String;
protected override function partAdded(partName:String, instance:Object):void
{
super.partAdded(partName, instance);
if(instance === leftLabel)
{
leftLabel.text = leftText;
}
if(instance === rightLabel)
{
rightLabel.text = rightText;
}
if(instance === centerLabel)
{
centerLabel.text = centerText;
}
}
}