What is the hostComponent? - actionscript-3

Im skinning a progressBar in Flex, and after reading a bit about it, I see that there is something called hostComponent.
Adobe site says:
"The host component is the component that uses the skin. By specifying the host component, Spark skins can gain a reference to the component instance that uses the skin by using the hostComponent property."
But, I still dont understand how this exactly works.
Any quick and practical explanation?
Thanks!

When you create custom components in the Spark architecture, you usually split them up into two parts:
an ActionScript class that contains the core functionality of the custom component. This class will usually extend SkinnableComponent or SkinnableContainer
an MXML skin class which is loosely associated with that ActionScript class and contains only the visual presentation of the component. This class should contain no real functionality and it should be trivial to substitute it with another skin.
The first of these two classes is referred to as the host component from the skin's point of view.
A simple example
Let's create a very simple panel by extending SkinnableContainer:
public class MyPanel extends SkinnableContainer {
[Bindable]
public var title:String;
}
As you can see, I made a property 'title' which we want to use to display a title in the Panel. Now let's create a skin that uses this property:
<?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">
<fx:Metadata>
[HostComponent("path.to.MyPanel")]
</fx:Metadata>
<!-- graphics for title bar go here -->
<s:Label text="{hostComponent.title}" top="5" left="5" />
<!-- graphics for panel content go here -->
<s:Group id="contentGroup" top="30" bottom="0" left="0" right="0" />
</s:Skin>
The hostcomponent is defined in the 'metadata' block and you see that we can use it to bind its properties into our visual representation. The 'contentGroup' is there because it is required by SkinnableContainer; this is were all the elements will go that you put inside the custom panel. So here's how to use it:
<myComps:MyPanel title="Panel title" skinClass="path.to.skins.MyPanelSkin">
<s:Label text="Hello Panel" />
<!--everything in here goes into the 'contentGroup'-->
</myComps:MyPanel>

Related

Referring .mxml tag from (not included) actionscript file

I have a Home.mxml file with home_src.as included in a fx:Script tag. Now suppose that I want to retrieve the value of a <mx:TextInput.../> tag located in Home.mxml, from another .as file (for example login_src.as).
I tried mx.core.Application.application.[file.mxml].[property] but doesn't work (I obtain an error like this: property not found on ).
I don't know if it is possible without including the .as file who wants access to the .mxml property, but I want to find out because I have a canvas.mxml page (with some text and combo tag) that contains a tabNavigator with two other .mxml pages; in the actionscript of these two tabs I need the value of canvas.mxml input and combo tag.
Is there a way to do this without including tab1 or tab2.as into my canvas.mxml?
A button click opens a popup for data insertion:
home.as
..
var insertPop:InsertPopUp = InsertPopUp(PopUpManager.createPopUp((this.parentApplication as DisplayObject), InsertPopUp, true));
PopUpManager.centerPopUp(insertPop);
..
InsertPopUp.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" initialize="init()" close="close()">
<mx:Script source="InsertPopUp_src.as"/>
<mx:Label id="lblage" text="Age:"/>
<mx:TextInput id="txtAge" editable="true"/> // I want this data
<mx:TabNavigator id="insertTab" width="100%" height="85%">
<mx:VBox id="vbx1" width="100%" height="100%" label="Car Data">
<mx:ModuleLoader id="mdlCatData" url="modules/Cat.swf" height="100%" width="100%" />
</mx:VBox>
<mx:VBox id="vbx2" width="100%" height="100%" label="Van Data">
<mx:ModuleLoader id="mdlDogData" url="modules/Dog.swf" height="100%" width="100%"/>
</mx:VBox>
</mx:TabNavigator>
</mx:TitleWindow>
Then I have:
Cat.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" initialize="init();">
<mx:Script source="CatData_src.as" />
// other forms..
</mx:Module>
and:
Dog.mxml
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" initialize="init();">
<mx:Script source="DogData_src.as" />
// other forms..
</mx:Module>
I want to retrieve data of the txtAge textInput and use it in both CatData_src.as and DogData_src.as; how can I get that data without resorting to a script include?
I made this "graphic configuration" because some data are common to Cat and Dog.. (obviously is just an example).
mxml is not anything special in the world of AS3, it seems different but it's really not as it is compiled later into AS3 code. Any object declared in mxml tag with an id is just a property of the as3 class that will be generated (using the same name as the mxml file).
If that mxml class is supposed to be unique (not 2 instances of it) you can access your property using static methods.
Example:
mxml main class named: MyMain.mxml
declare static variable (in fx:script) of type MyMain: static public var instance:MyMain;
in addedToStage listener (or similar) set your variable: instance = this
from anywhere access your instance and property: MyMain.instance.mytextimput
If working with multiple instances of mxml class then get reference of the instance and use it just like any other AS3 object.

Spark TabBar unique tabs

I currently have the following setup (abstracted for simplicity):
<s:TabBar id="extentTypeTabBar" dataProvider="{vs}"/>
<mx:ViewStack id="vs">
<s:NavigatorContent id="firstTab" label="Action">
<!--content-->
</s:NavigatorContent>
<s:NavigatorContent id="secondTab" label="Adventure">
<!--content-->
</s:NavigatorContent>
<s:NavigatorContent id="thirdTab" label="Favorites">
<!--content-->
</s:NavigatorContent>
</mx:ViewStack>
I want thirdTab to have an image rather than a label (i.e. an image of a star or heart, instead of the word 'Favorites'). I've tried using the 'icon' property on the NavigatorContent, to no avail.
I believe to achieve this I'm going to have to create a custom skin with logic behind it for the Spark TabBar since I only want to uniquely skin one tab, not all tabs. Does anyone have an example of how to accomplish this?
Thanks!
jp
This should work just fine if you use the icon property of the NavigatorContent object. The icon property is typed as Class, so you have to provide it with the class that represents an embedded image or a FXG object.
Here is an example of both methods:
<s:NavigatorContent icon="#Embed('favorite_icon.png')" /> <!-- embedded icon -->
<s:NavigatorContent icon="{FxgAsset}" /> <!-- fxg asset -->
For convenience, I put the icon in the "default package" of my project, just change the path to the icon to match the location of your icon. The FXG asset I'm using in the second example can be a located anywhere in your project. FXG assets are classes by nature, so you don't need to specify a path (your IDE should find it like any other class).
Note there are a few other ways to embed images, all of them should work ... the example I've shown here is the simplest :)

process facebook feeds dynamically in adobe flash builder

I am trying to process the user feeds retrieved from facebook by dynamically adding them to the flash app, and i need the feed to be displayed in a box with its publisher name and picture beside it (as normal)..
the question is how could i display them aligned under each other if i don't know their heights? is there a way to just add them under each other without specifying the height?
like in html adding divs under each other?
and other question how to add a scroll bar if the content exceeds the flash window?
iam new to as3 & flash so any advice will help.. thanks..
my code:
protected function getFeedsHandler(result:Object,fail:Object):void
{
if(result)
{
var i:Number;
for(i=0;i<10;i++)
if(result[i])
{
var fdLbl= new Label();
addElementAt(fdLbl,1);
fdLbl.text=result[i].message;
fdLbl.x=20;
fdLbl.y=(i+2)*100;
fdLbl.width=400;
var fdImg= new Image();
addElementAt(fdImg,1);
fdImg.source=FacebookDesktop.getImageUrl(result[i].from.id,"small");
fdImg.x=20;
fdImg.y=(i+2)*80;
fdImg.width=400;
var nameLbl= new Label();
addElementAt(nameLbl,1);
nameLbl.text=result[i].from.name;
nameLbl.x=20;
nameLbl.y=(i+2)*90;
}
}
the interface:
<s:Button id="loginoutBtn" right="10" top="10" label="Log out"
click.loggedin="logout(event)"
label.loggedout="Log in" click.loggedout="login(event)"/>
<s:Form includeIn="loggedin" left="70" top="10">
<s:FormItem label="User">
<s:Label id="nameLbl" text=""/>
</s:FormItem>
<s:FormItem label="birthday">
<s:Label id="brthday"/>
</s:FormItem>
<s:FormItem label="feeds">
<s:Image id="feedImg"/>
<s:Label id="feedLbl" x="0"/>
<s:Label id="statusLbl" width="405"/>
</s:FormItem>
</s:Form>
<s:Image id="userImg" includeIn="loggedin" left="10" top="10" width="50"/>
So it looks like you're using Flex and specifically you're using the spark components. In using Spark there's a couple of options on how you would achieve this, one option is to put the component you made above into a VGroup. The VGroup vertically stacks visual components, it has a property called gap you can set to add or remove spacing between the components (number of pixels between each object nested into the VGroup). The addition of a s:Scroller component wrapping the VGroup will give you the scroll bars, essentially the way this works is you set the size on the s:Scroller to the size you want to visible (can be a percentage like 100% width/height of the view/container), then you set no explicit size on the VGroup, the VGroup will expand to have a height equal to the height of all the components nested in it plus any padding plus the gap space, the scroller will take care of figuring out how big the scroll tab button should be and adjust the scrollRect on the VGroup for you, essentially it's going to work like magic :). This would look something like the following:
<s:Scroller width="100%" height="100%">
<s:VGroup id="loadedContentVGroup">
<yourpackage:YourCustomComponent/>
</s:VGroup>
</s:Scroller>
If you don't constrain the scroller's height and width it will not work as it doesn't have a defined region to draw in and will just become as large as it's children (the nested components). In all likelihood you would add elements to the VGroup in AS3 so you'd probably want to give it an ID.
Your other option is to use a spark List and then set your visual component as the itemRenderer. For each data element in the data provider for the list (some sort of collection class, ArrayCollection, XMLCollection etc.) it will set an element of the array as the "data" property on your visual component. You would then use bindings to the data property in your visual component to make sure if the renderer is re-used/recycled the elements within it update automatically. Here's an example of that:
<s:List dataProvider="{new ArrayCollection([{name:'Shaun', birthday:'04-28-1983', imageSource:'someImage.png'}])}"
itemRenderer="views.YourCustomComponent"
width="100%"/>
In your case the dataProvider for the list could be assigned in the result handler code you have above, it appears result is an array so you can just wrap it in an ArrayCollection like myList.dataProvider = new ArrayCollection(result);
Here's a potential view definition for a single entry in the list (the itemRenderer class used above)
[views.YourCustomComponent]
<?xml version="1.0" encoding="utf-8"?>
<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
implements="mx.core.IDataRenderer">
<fx:Script>
<![CDATA[
private var _data:Object;
[Bindable(eventName="dataChanged")]
public function get data():Object
{
return _data;
}
public function set data(value:Object):void
{
if(_data == value)
return;
_data = value;
dispatchEvent(new Event("dataChanged"));
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Label text="{data.name}"/>
<s:Label text="{data.birthday}"/>
<s:Image source="{data.imageSource}"/>
</s:VGroup>
There are certainly caveats and alternatives to these answers but this will hopefully get you going in the right direction, if you're doing this for mobile development be sure to check out the recommendations with regard to creating renderers for mobile, the idea here is to reduce the processing needed for creating and re-using renderers on mobile as much as possible to lighten the load on the CPU and memory.
One other thing to note it appears your mixing defining the view in AS3 and MXML, while this is technically okay I find it to be a bit confusing myself. I would normally define the entire layout in MXML, or if need be entirely in AS3. If defined in MXML and a component needs to be conditionally hidden by code I would just toggle the visible/includeInLayout properties. I suppose this is just a preference but it seems it could get hairy determining what is causing particular layouts to occur when you have to look between the two to piece it together.
References to the AS3 reference for classes used:
http://help.adobe.com/en_US/FlashPlatform/beta/reference/actionscript/3/spark/components/VGroup.html
http://help.adobe.com/en_US/FlashPlatform/beta/reference/actionscript/3/spark/components/Scroller.html
http://help.adobe.com/en_US/FlashPlatform/beta/reference/actionscript/3/spark/components/List.html
Details on custom item renderers http://help.adobe.com/en_US/flex/using/WS03d33b8076db57b9-23c04461124bbeca597-8000.html <-- references Jeffry Houser a regular on SO with the name www.flextras.com

How to set DefaultComplexItemRenderer background alpha to 0

I have a simple list with a tileLayout of images. From the examples I've looked at it looks like i'm supposed to use the DefaultComplexItemRenderer. It works, and my array of images loads fine, but each item has a solid background. I need the background behind each image to have an alpha of 0. How Can I set that?
In the past i've just made a custom itemRenderer, and overrided the drawBackground function on itemRenderers, but DefaultComplexRenderer doesn't have a drawBackground function to override.
Is there another simple solution in the flex code? OR it would be awesome if someone could show me how to make a custom DefaultComplexRenderer.
NOTE:
This is a Flex MOBILE project. I know some itemRenderer's aren't friendly with mobile. Adobe says to "always do item renderers in AS3 rather than mxml" so, keep that in mind.
Thanks!
Here's my code:
<fx:Declarations>
<s:ArrayList id="arrList">
<s:BitmapImage source="assets/images/one.png" scaleMode="letterbox" smooth="true" width="100%" height="100%"/>
<s:BitmapImage source="assets/images/two.png" scaleMode="letterbox" smooth="true" width="100%" height="100%"/>
<s:BitmapImage source="assets/images/three.png" scaleMode="letterbox" smooth="true" width="100%" height="100%"/>
<s:BitmapImage source="assets/images/four.png" scaleMode="letterbox" smooth="true" width="100%" height="100%"/>
</s:ArrayList>
</fx:Declarations>
<s:List id="extrasList_list" width="100%" height="100%"
dataProvider="{arrList}"
itemRenderer="spark.skins.spark.DefaultComplexItemRenderer"
horizontalCenter="0"
verticalCenter="0">
<s:layout>
<s:TileLayout requestedColumnCount="-1"
requestedRowCount="-1"
horizontalGap="10"
verticalGap="10"
orientation="rows"
columnAlign="justifyUsingWidth"
/>
</s:layout>
</s:List>
Things I've tried:
this in my main css file...
s|DefaultComplexItemRenderer {
contentBackgroundAlpha:0;
}
but i get this warning, and it doesn't work...
-Cannot resolve namespace qualified type 'DefaultComplexItemRenderer' in CSS selector 'DefaultComplexItemRenderer'
[Edit]
The contentBackgroundAlpha and contentBackgroundColor styles for a Flex List are somewhat misleading! You generally want to style the item renderers. In the context of a list, these styles only affect a tiny bit of "chrome" that can appear around the list. See below for details on styling the renderers.
If you just want to show an image, the IconItemRenderer is the way to go. It extends LabelItemRenderer so it's optimized for mobile and also has two text fields as well.
Flex List components recycle item renderers to be efficient, and only create as many renderers as needed to display what is currently visible. To do this, the list populates the renderer's data property. So you want to configure your item renderer using this data property.
An efficient way to do that is to override the setter function for data. Create a new Actionscript class that extends IconItemRenderer add this to it:
override public function set data(value:Object):void
{
super.data = value;
// IconItemRenderer already has a BitmapImage component, it's property name is iconDisplay
// your ArrayList should therefore only contain Strings representing the image sources
// note how I've changed your ArrayList in the declarations tag below
iconDisplay.source = data.imageSource;
}
You'll likely want to configure that iconDisplay BitmapImage to look how you want it. The method above may get called frequently, so you can put code that only needs to happen once somewhere else... by overriding a Flex component lifecycle method like createChildren():
override protected function createChildren():void
{
super.createChildren();
iconDisplay.scaleMode="letterbox";
iconDisplay.smooth=true;
}
Now tell the List to use your renderer w/syntax like this:
<s:List itemRenderer="com.yourdomain.or.whatever.MyIconItemRendererClass" />
Styling the renderer:
<s:List alternatingItemColors="[0xFFFFFF, 0xFFFFFF]" selectionColor="#FF0000" />
Another way is to override the mobile item renderer's drawBackground() and/or drawBorder() protected methods and draw your own stuff w/the graphics api (or nothing at all).
Supplying the data:
Instead of giving the list an array of BitmapImage components, you give it an array of objects that contain your data. It's better to use strongly typed objects, but this works too:
<fx:Declarations>
<s:ArrayList id="arrList">
<fx:Object imageSource="assets/images/one.png" />
<fx:Object imageSource="assets/images/two.png" />
<fx:Object imageSource="assets/images/three.png" />
</s:ArrayList>
</fx:Declarations>
I like writing renderers in Actionscript... But there is also an MXML example in the link to IconItemRenderer docs at the top. It also shows how you to set the values of the two text areas in this renderer (with labelField and messageField). You can also specify a function that returns the label/message/icon values (with labelFunction, messageFunction, and iconFunction).
Looks like you should be able to use setStyle('contentBackgroundAlpha', 0); on your DefaultComplexItemRenderer.
Not 100% this is what you're looking for, not really familiar with this class. Any reason you're using this over extending LabelItemRenderer?
edit
I believe you may want to extend IconItemRenderer
Check out this tutorial
http://www.youtube.com/watch?v=EOpsDZaQrOI
Thanks for trying to help guys, but I found the quickest/simple solution to be be just as simple as copying the DefaultComplexItemRender from the SDK into a custom one, and then changing this one line of code
autoDrawBackground="false"
It's simple and it worked.

How come you can change the id of an object in Actionscript but still refer to it with its old id?

For instance in Flex 4
?xml version="1.0"?>
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
private function setLabel():void {
trace ("the id is "+myButton.id);
myButton.id = "yourButton";
}
]]>
</fx:Script>
<s:Button id="myButton" label="Click Me" click="setLabel();"/>
the traces when the button is clicked twice are
'the id is myButton' followed by
'the id is yourButton'
Not just an idle query. I was hoping to change the id of custom components when populating a main app with them
I would assume that the id of the when set in mxml is the variable name which also sets the internal id (myButton.id = "myButton") Therefore you're able to change myButton.id to "yourButton" because id and variable name are different properties.
Weird one though I'll admit.
If you were to want to create custom components when populating your main app I would look in to a different approach than laying them all out in mxml. Perhaps creating the components in actionscript and setting them in mxml would be best? ( eg your main class is the mxml app and then you have a class behind that does the heavy lifting of creating the view, with all your custom named components )
Remember that MXML is parsed to ActionScript by mxmlc. mxmlc uses the ID attribute of the mxml tags to map to a public class member at compile time. Changing the runtime value of the ID field would have no change to the class structure.
Example:
<MyComponent>
<Button id="myButton" />
&lt/MyComponent>
When compiled, mxmlc transforms it roughly to:
package {
class MyComponent {
[Bindable]
public var myButton:Button;
// Other junk for class init, etc would show here...
}
}
And is then compiled to SWF byte code. At which point the ID attribute is just an attribute and would have no bearing on the class's functionality. You'd have to actually assign a new Button instance to this.myButton to get it to change.