How do I style or skin the TabNavigator buttons? - apache-flex

I'd like to add an icon and a close button to the TabNavigator in Flex 4 but can't find any examples online (all are for Flex 3).
<mx:TabNavigator id="firstViewStack"
width="100%"
height="100%"
clipContent="true">
<s:NavigatorContent label="FIRST TAB" >
<s:Group width="100%" />
</s:NavigatorContent>
</mx:TabNavigator>

ZOMGWTH?!?!?! This took way too long to figure out. This is how you set the default Tab skin:
mx|Tab {
skin:ClassReference("mx.skins.spark.TabSkin");
}
You can copy that skin into your own project and make modifications as needed:
Here are some examples. This modifies all Tabs in all TabNavigators:
mx|Tab {
skin:ClassReference("mySkins.MyTabSkin");
}
To skin only one TabNavigator:
<mx:TabNavigator id="tabBarNavigator" styleName="myTabNavigator">
<s:NavigatorContent label="First Tab" >
<s:Group width="100%" />
</s:NavigatorContent>
<s:NavigatorContent label="Second Tab">
<s:Group height="100%" width="100%" />
</s:NavigatorContent>
</mx:TabNavigator>
<fx:Style>
#namespace s "library://ns.adobe.com/flex/spark";
#namespace utils "com.flexcapacitor.utils.*";
#namespace mx "library://ns.adobe.com/flex/mx";
.myTabNavigator {
tabStyleName: "myTabs";
}
.myTabs {
skin:ClassReference("mySkins.MyTabSkin");
}
</fx:Style>
This works with Flex 4.6 and the Spark theme.
Update 2:
Here are some more notable styles:
.myTabs {
skin:ClassReference("skins.SolidFillTabSkin");
fillAlpha:1;
borderAlpha:1;
cornerRadius:0;
/*color:#FF0000;
chromeColor: #00FF00;
textRollOverColor: #0000FF;
textSelectedColor: #00FF00;*/
textFieldClass: ClassReference("mx.core.UIFTETextField"); /* default is mx.core.UITextField*/
}
The textSelectedColor almost never fires. So there is never a selected text color. Also, the text is moved down when the tab is selected!
So below is a new skin where the text doesn't move down. You'll probably need to set the text and fill colors in the skin if you don't want to use the defaults although you can use chromeColor to set the fill color. This skin supports cornerRadius and borderAlpha,
<?xml version="1.0" encoding="utf-8"?>
<!--
Apache License 2.0.
-->
<!--- The Spark skin class for the tabs of the MX TabNavigator container.
How to use:
With a specific TabNavigator:
.myTabNavigator {
tabStyleName: "myTabs";
}
.myTabs {
skin:ClassReference("mySkins.MyTabSkin");
}
Applied to all Tabs in all TabNavigators:
mx|Tab {
skin:ClassReference("com.flexcapacitor.skins.SolidFillTabNavigatorButtonSkin");
fillAlpha:1;
borderAlpha:1;
cornerRadius:0;
/*color:#FF0000;
chromeColor: #00FF00;
textRollOverColor: #0000FF;
textSelectedColor: #00FF00;*/
textFieldClass: ClassReference("mx.core.UIFTETextField"); /* default is mx.core.UITextField*/
}
#see mx.containers.TabNavigator
#langversion 3.0
#playerversion Flash 10
#playerversion AIR 1.5
#productversion Flex 4
-->
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
minWidth="21" minHeight="21"
alpha.disabledStates="0.5">
<fx:Script>
<![CDATA[
import mx.controls.Button;
import mx.core.IUITextField;
import mx.core.mx_internal;
use namespace mx_internal;
private var cornerRadius:Number = 0;
/**
* #private
*/
override protected function initializationComplete():void
{
useChromeColor = true;
super.initializationComplete();
}
/**
* COPIED FROM TabBarButtonSkin.mxml
* #private
* The cornerRadius style is specified by the TabBar, not the button itself.
*
* Rather than bind the corner radius properties of the s:Rect's in the markup
* below to hostComponent.owner.getStyle("cornerRadius"), we reset them here,
* each time a change in the value of the style is detected. Note that each
* corner radius property is explicitly initialized to the default value of
* the style; the initial value of the private cornerRadius property.
*/
private function updateCornerRadius():void
{
var cr:Number = getStyle("cornerRadius");
if (cornerRadius != cr)
{
cornerRadius = cr;
fill.topLeftRadiusX = cornerRadius;
fill.topRightRadiusX = cornerRadius;
}
}
/**
* COPIED FROM TabBarButtonSkin.mxml
* #private
* This function creates the path data used by borderTop and selectedHighlight.
*/
private function createPathData(isBorder:Boolean):String
{
var left:Number = 0;
var right:Number = width;
var top:Number = 0.5;
var bottom:Number = height;
var a:Number = cornerRadius * 0.292893218813453;
var s:Number = cornerRadius * 0.585786437626905;
// If the path is for the highlight,
// Draw the vertical part of the selected tab highlight that's rendered
// with alpha=0.07. The s:Path is configured to include only the left and
// right edges of an s:Rect, along with the top left,right rounded corners.
// Otherwise, we draw a full path.
var path:String = "";
path += "M " + left + " " + bottom;
path += " L " + left + " " + (top + cornerRadius);
path += " Q " + left + " " + (top + s) + " " + (left + a) + " " + (top + a);
path += " Q " + (left + s) + " " + top + " " + (left + cornerRadius) + " " + top;
if (isBorder)
path += " L " + (right - cornerRadius) + " " + top;
else
path += " M " + (right - cornerRadius) + " " + top;
path += " Q " + (right - s) + " " + top + " " + (right - a) + " " + (top + a);
path += " Q " + right + " " + (top + s) + " " + right + " " + (top + cornerRadius);
path += " L " + right + " " + bottom;
return path;
}
/**
* COPIED FROM TabBarButtonSkin.mxml
* #private
* The borderTop s:Path is just a s:Rect with the bottom edge left out.
* Given the rounded corners per the cornerRadius style, the result is
* roughly an inverted U with the specified width, height, and cornerRadius.
*
* Circular arcs are drawn with two curves per flash.display.Graphics.GraphicsUtil.
*/
private function updateBorderTop(width:Number, height:Number):void
{
// Generate path data and lay it out. The path is not being layout by the default BasicLayout of this skin
// since we excluded it from the layout.
var path:String = createPathData(true);
borderTop.data = path;
borderTop.setLayoutBoundsSize(width, height, false);
borderTop.setLayoutBoundsPosition(0, 0, false);
}
/**
* #private
*/
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number) : void
{
updateCornerRadius();
updateBorderTop(unscaledWidth, unscaledHeight);
var button:Button = owner as Button;// is the Button
var textField:IUITextField = button.getTextField();
var label:String = button.label;
// if you want to use your own text field hide the other one here
if (textField) {
//textField.includeInLayout = false;
textField.visible = false;
}
if (labelDisplay) {
labelDisplay.text = label;
}
var borderAlpha:Number = button.getStyle("borderAlpha");
if (!isNaN(borderAlpha)) {
borderTop.alpha = borderAlpha;
if (lineAlongTheBottom) {
lineAlongTheBottom.alpha = borderAlpha;
}
}
var fillAlpha:Number = button.getStyle("fillAlpha");
if (!isNaN(fillAlpha)) {
fillColor.alpha = fillAlpha;
}
var fillColorValue:Number = button.getStyle("fillColor");
if (!isNaN(fillColorValue)) {
//fillColor.color = fillColorValue;
}
super.updateDisplayList(unscaledWidth, unscaledHeight);
}
]]>
</fx:Script>
<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" stateGroups="disabledStates"/>
<s:State name="selectedUp" stateGroups="selectedStates" />
<s:State name="selectedOver" stateGroups="selectedStates" />
<s:State name="selectedDown" stateGroups="selectedStates" />
<s:State name="selectedDisabled" stateGroups="disabledStates, selectedStates" />
</s:states>
<!-- layer 1: fill -->
<s:Rect id="fill" left="1" right="1" top="1" bottom="0" >
<s:fill>
<s:SolidColor id="fillColor"
color="0xFFFFFF"
color.selectedStates="0xECEEEE"
color.over="0xECEEEE"
alpha="1" />
<!-- <s:LinearGradient rotation="90">
<s:GradientEntry color="0xE4E4E4" color.over="0xCACACA"
color.selectedStates="0xFFFFFF"
alpha="1" />
<s:GradientEntry color="0xA1A1A1" color.over="0x878787"
color.selectedStates="0xE4E4E4"
alpha="1" />
</s:LinearGradient>-->
</s:fill>
</s:Rect>
<!-- layer 4: border - unselected only -->
<s:Line id="lineAlongTheBottom" left="0" right="0" bottom="0" excludeFrom="selectedStates" >
<s:stroke>
<s:SolidColorStroke color="0x696969" alpha="1" />
</s:stroke>
</s:Line>
<!--- Set includeInLayout="false" as we regenerate the path data and lay out the path in
the updateDisplayList() override and we don't want it to affect measurement. #private
-->
<s:Path id="borderTop" left="0" right="0" top="0" bottom="0" includeInLayout="false">
<s:stroke>
<s:LinearGradientStroke rotation="90" weight="1">
<s:GradientEntry color="0x000000"
alpha="0.5625"
alpha.down="0.6375"
alpha.selectedStates="0.6375" />
<s:GradientEntry color="0x000000"
alpha="0.75"
alpha.down="0.85"
alpha.selectedStates="0.85" />
</s:LinearGradientStroke>
</s:stroke>
</s:Path>
<!-- layer 8: text -->
<!--- #copy spark.components.supportClasses.ButtonBase#labelDisplay -->
<s:Label id="labelDisplay"
visible="true"
textAlign="center"
verticalAlign="middle"
maxDisplayedLines="1"
horizontalCenter="0" verticalCenter="2"
left="10" right="10" top="2" bottom="2">
</s:Label>
</s:SparkSkin>

Related

Draggable Drawer Adobe Flex Mobile

Could someone please assist me with a way to create a drag-able drawer that resides on the bottom of my mobile application? I am wanting to make it so there is a drag handle that is visible all the time (can be an image or whatever) and then allow you to slide the contents into view and slide them back out of view at the bottom of the screen. I am needing a direction to start in, I should be able to figure it out once I have that.
I originally had the sliding initiated on mouse down/move/up events, but have since changed it out for a tap affect (which also occurs when you slide up/down) on the handle image at the top of the dock, since I changed it this afternoon I haven't had a chance to clean it up yet but this is the start:
Drawer:
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" maxHeight="125" minHeight="30" height="30"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
private var dragging:Boolean = false;
protected function resize():void{
var h:int = this.height;
var i:int = 0;
if (h !== 125){
for(i=h;i<=125;i++){
this.height = i;
};
currentState='up';
return;
}else{
}
if(h >= 30){
for(i=h;i>=30;i--){
this.height = i;
};
currentState='down';
return;
}
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:states>
<s:State name="down"/>
<s:State name="up"/>
</s:states>
<s:Rect width="100%" height="100%" top="30">
<s:fill>
<s:SolidColor color="#333333"/>
</s:fill>
</s:Rect>
<s:Image scaleMode="zoom" source.down="#Embed('Images/down.png')" source.up="#Embed('Images/up.png')" mouseDown="resize()"/>
<s:HGroup width="100%" horizontalAlign="center" verticalAlign="bottom" top="30" gap="30">
<!--Buttons here-->
</s:HGroup>
</s:Group>

Can not move my custom component based on HGroup

I have created a custom component based on spark.components.HGroup and it works mostly as needed, but I have this minor problem: I can not move it.
Maybe someone will look at my simplified test case below and spot my error?
Here is the screenshot of my 3 custom components, representing chat bubbles:
Here my custom component Bubble.mxml drawing black text on green background:
<?xml version="1.0" encoding="utf-8"?>
<s:HGroup
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
gap="0"
creationComplete="init(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
private static const PAD:uint = 10;
private static const BGCOLOR:uint = 0xCCFFCC;
private static const BGALPHA:Number = 0.8;
private var _timer:Timer = new Timer(600, 20);
public function init(event:FlexEvent):void {
_timer.addEventListener(TimerEvent.TIMER, fadeBubble);
_timer.addEventListener(TimerEvent.TIMER_COMPLETE, hideBubble);
addEventListener(MouseEvent.CLICK, hideBubble);
}
public function set text(str:String):void {
_text.text = str;
if (x > 100 && x < 200) {
_left.visible = true;
_right.visible = false;
} else {
_left.visible = false;
_right.visible = true;
}
visible = true;
alpha = 1.0;
_timer.reset();
_timer.start();
}
public function get text():String {
return _text.text;
}
private function fadeBubble(event:TimerEvent):void {
if (_timer.currentCount * 2 > _timer.repeatCount)
alpha /= 2;
}
// the argument could be TimerEvent or MouseEvent
public function hideBubble(event:Event):void {
visible = false;
_timer.stop();
}
]]>
</fx:Script>
<s:Graphic id="_left" visible="false">
<s:Path data="M 20 10 L 0 20 L 20 30">
<s:fill>
<s:SolidColor color="{BGCOLOR}" alpha="{BGALPHA}" />
</s:fill>
</s:Path>
</s:Graphic>
<s:Label id="_text" width="100%"
paddingTop="{PAD}" paddingBottom="{PAD}"
paddingLeft="{PAD}" paddingRight="{PAD}"
fontSize="24" textAlign="center"
backgroundColor="{BGCOLOR}" backgroundAlpha="{BGALPHA}" />
<s:Graphic id="_right" visible="false">
<s:Path data="M 0 10 L 20 20 L 0 30">
<s:fill>
<s:SolidColor color="{BGCOLOR}" alpha="{BGALPHA}" />
</s:fill>
</s:Path>
</s:Graphic>
</s:HGroup>
Here is my text application Test.mxml which uses absolute positioning:
<?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">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
private static const AVATAR:String =
'http://preferans.de/images/70x90/male_happy_70x90.png';
public static function randRange(from:int, to:int):int {
return from + Math.round((to - from) * Math.random());
}
public function chat(event:FlexEvent):void {
_bubble0.y = 340 + randRange(-20, 20);
_bubble1.y = 4 + randRange(0, 40);
_bubble2.y = 4 + randRange(0, 40);
trace('_bubble0.y = ' + _bubble0.y);
trace('_bubble1.y = ' + _bubble1.y);
trace('_bubble2.y = ' + _bubble2.y);
_bubble0.text = _chat.text;
_bubble1.text = _chat.text;
_bubble2.text = _chat.text;
_chat.text = '';
}
]]>
</fx:Script>
<s:Image id="_user0" source="{AVATAR}" horizontalCenter="20" y="340" width="160" height="140" />
<s:Image id="_user1" source="{AVATAR}" left="4" top="4" width="160" height="140" />
<s:Image id="_user2" source="{AVATAR}" right="4" top="4" width="160" height="140" />
<comps:Bubble id="_bubble0" maxWidth="200" x="20" y="340" />
<comps:Bubble id="_bubble1" maxWidth="200" left="170" top="4" />
<comps:Bubble id="_bubble2" maxWidth="200" right="170" top="4" />
<s:TextInput id="_chat" bottom="4" right="4" enter="chat(event)" text="Hello!" />
</s:Application>
In the debug console I do see the varying y coordinates:
_bubble0.y = 350
_bubble1.y = 31
_bubble2.y = 36
_bubble0.y = 340
_bubble1.y = 43
_bubble2.y = 15
but at the screen they never change!
The problem is that _bubble1 and _bubble2 are positioned with constraints (left="170" top="4"). Flex ignores the x and y properties because the constraints have a higher priority than absolute positioning with x and y.
Try removing the left="170" top="4" from both components and you'll see they change positions as expected.
Hope this helps,
Blaze

Scale a Spark DataGrid with Fixed rowCount & No Scollers

I am trying to find a way to Scale (either font or scaleX&Y) a DataGrid (with requestedMinRowCount = requestedMaxRowCount = requestedRowCount = dataProviderLength), so that it would Always show all the Rows (so no scrollers).
A Solution I came up with for Scaling is:
protected function thisDatagrid_resizeHandler(event:ResizeEvent):void
{
if (event.oldWidth < this.width) {
this.setStyle('fontSize', this.getStyle('fontSize') + 0.5);
} else if (event.oldWidth > this.width) {
this.setStyle('fontSize', this.getStyle('fontSize') - 0.5);
}
this.minWidth = this.measuredMinWidth;
}
While the code above actually does resize the text (hence the cell, column and grid) on Resize, the problem I am getting is when the rescale happens vertically.
For the requestedRowCount to work, there should not be a fixed height set on the Datagrid.
So I am wondering what is the way to get the grid to constantly show all it's rows & columns as it scales (even if resized vertically)?
Another Option would be overriding updateDisplayList, though not straight forward for resizing.
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
//super.updateDisplayList(unscaledWidth, unscaledHeight);
trace('oldWidth: ' + oldWidth + ' | unscaledWidth: ' + unscaledWidth + ' | parentWidth: ' + this.parent.width);
trace('oldHeight: ' + oldHeight + ' | unscaledHeight: ' + unscaledHeight + ' | parentHeight: ' + this.parent.height);
trace('Potential ScaleX: ' + (unscaledWidth - oldWidth)/unscaledWidth);
trace('Potential ScaleY: ' + (unscaledHeight - oldHeight)/unscaledHeight);
trace('----------------------------------------------------');
/* scaleX = (unscaledWidth - oldWidth)/unscaledWidth;
scaleY = (unscaledHeight - oldHeight)/unscaledHeight; */
//super.updateDisplayList(unscaledWidth, unscaledHeight);
}
The problem with this if I uncomment scaleX & scaleY, it'll loop forever...
I might be misunderstanding you but couldn't you just use:
<?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">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:DataGrid
id="grid"
width="100%"
requestedRowCount="{grid.dataProvider.length}"
rowHeight="24"
fontSize="12"
horizontalScrollPolicy="off"
verticalScrollPolicy="off">
<s:dataProvider>
<s:ArrayCollection>
<s:source>
<fx:Object id="one" label="One" value="1" />
<fx:Object id="two" label="Two" value="2" />
<fx:Object id="three" label="Three" value="3" />
</s:source>
</s:ArrayCollection>
</s:dataProvider>
<s:columns>
<s:ArrayCollection>
<s:GridColumn dataField="label" headerText="Label" />
<s:GridColumn dataField="value" headerText="Value" />
</s:ArrayCollection>
</s:columns>
</s:DataGrid>
</s:Application>
The best (and most performant way is to use the layout of a group where the Datagrids would be located, and apply a layout like the one below:
ex: ScaleOneLayout.as
import mx.core.UIComponent;
import spark.layouts.BasicLayout;
public class ScaleOneLayout extends BasicLayout
{
public function ScaleOneLayout()
{
super();
}
override public function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
var child:UIComponent;
child = target.getElementAt(0) as UIComponent;
child.setLayoutBoundsSize(child.getPreferredBoundsWidth(), child.getPreferredBoundsHeight());
child.scaleX = unscaledWidth / child.width;
child.scaleY = unscaledHeight / child.height;
}
}

Flex 4 Move Effect only animating last target in array of multiple items

I am animating a number of items using the Move effect. I am adding each item to an array after it has been added to the display list and once all items are added calling the play method, passing an array of the items to it.
Only the last item plays in my animation.
Here is my code:
MXML: s:Move id="coinFall" yFrom="-400" duration="2000" />
public function showCoins(n:Number):void{
holder.removeAllElements();
var targets:Array = [];
if (n>=2.5){
var coins:uint = Math.round(n/2.5);
for (var i:uint = 0; i<coins; i++){
var c:Coin = new Coin();
c.y = 0 - (i*15);
holder.addElement(c);
targets.push(c);
}
coinFall.play(targets);
}
}
Any help much appreciated.
Thanks
It's hard to tell without more complete code, but this sample works for me:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Declarations>
<s:Move id="coinFall" yBy="100" duration="2000" />
<fx:Component className="Coin">
<s:Ellipse width="50" height="50">
<s:fill>
<s:SolidColor color="red" />
</s:fill>
</s:Ellipse>
</fx:Component>
</fx:Declarations>
<fx:Script>
<![CDATA[
public function showCoins(n:Number):void{
holder.removeAllElements();
var targets:Array = [];
for (var i:uint = 0; i<n; i++){
var c:Coin = new Coin();
c.x = i*50;
c.y = 0 - i*10;
holder.addElement(c);
targets.push(c);
}
coinFall.play(targets);
}
]]>
</fx:Script>
<s:controlBarContent>
<s:Button label="play" click="showCoins(5)" />
</s:controlBarContent>
<s:Group id="holder" />
</s:Application>
I would suggest looking into using yBy/yTo on the Move effect.

Flex 4 fileReference selected image file dimmensions (width and height)

I use a fileReference.browse() to select an image file from the harddrive.
How can I check the Width and Height of the selected image file please?
Thank you!
Load the fileReference.data into a Loader using loadBytes(). Then you'll have: sourceBMP:Bitmap = loader.content as Bitmap;
Here is a sample code:
MXML part:
<fx:Declarations>
<net:FileReference id="fileReference"
select="fileReference_select(event);"
complete="fileReference_complete(event);" />
</fx:Declarations>
<s:Button id="uplaodImageBtn"
label="Upload Image"
click="uplaodImageBtn_clickHandler()"/>
AS3 part:
private function uplaodImageBtn_clickHandler() : void {
var arr:Array = [];
arr.push(new FileFilter("Images", ".gif;*.jpeg;*.jpg;*.png"));
fileReference.browse(arr);
}
private function fileReference_select(evt:Event):void {
fileReference.load();
}
private function fileReference_complete(event:Event):void {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loader_complete);
loader.loadBytes(fileReference.data);
}
public function loader_complete (event:Event) : void {
var sourceBMP:Bitmap = event.currentTarget.loader.content as Bitmap;
Alert.show(sourceBMP.width + ', ' +sourceBMP.height);
}
From the context of Flex, I'm pretty sure that onc you get the results back from a browserr, it is only a byteArray. In theory if you use that byteArray as the source for an image tag you'll be able to get the height and width that way, once you add that image to a container.
Otherwise, I do not believe there is an easy way to get such metadata info from local files using Flex.
You should be able to read the image.sourceWidth and image.sourceHeight if you wait for the image source property to update. This will give you the unscaled original values.
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
private function browseImage(event:MouseEvent):void {
var arr:Array = [];
arr.push(new FileFilter("Images", ".gif;*.jpeg;*.jpg;*.png"));
imageFileReference.browse(arr);
}
private function imageSelect(evt:Event):void {
imageFileReference.load();
}
private function imageComplete(evt:Event):void {
image.source = smallImageFileReference.data;
image.addEventListener(FlexEvent.UPDATE_COMPLETE, getImageSize);
}
private function getImageSize(evt:FlexEvent):void {
image.removeEventListener(FlexEvent.UPDATE_COMPLETE, getImageSize);
imageWidth.text = image.sourceWidth + "px";
imageHeight.text = image.sourceHeight + "px";
}
]]>
</fx:Script>
<fx:Declarations>
<net:FileReference id="imageFileReference"
select="imageSelect(event)"
complete="imageComplete(event)"/>
</fx:Declarations>
<s:VGroup width="100%" height="100%">
<s:HGroup width="100%" verticalAlign="middle">
<s:Label fontWeight="bold" text="Width:" />
<mx:Text id="imageWidth" />
</s:HGroup>
<s:HGroup width="100%" verticalAlign="middle">
<s:Label fontWeight="bold" text="Height:" />
<mx:Text id="imageHeight" />
</s:HGroup>
<s:Image id="image" maxHeight="200" maxWidth="200" />
<s:Button label="Browse for Image" click="browseImage(event)" />
</s:VGroup>

Resources