In this example I’ll show you how to create a useful component for social networking websites: a Link to a user’s page with the user’s photo, name or both. Then in part 2 I’ll show you how to organize them into a list and connect them with Cairngorm. The OpenFlux framework is somewhat different to vanilla Flex - forget everything you already know for now - later things will start to reconnect.
These tutorials requires active participation, try writing the code as you read the samples. I recommend you type everything in as FlexBuilder will autocomplete a lot of imports and assign namespaces. Even if you just cut and paste a bit, it’s good practice to make the individual file. The really fascinating thing about OpenFlux is seeing how all the different classes work together - the architecture. After the next release of OpenFlux I’ll post a video version too.
These are 'my' methods of using OpenFlux not 'the' method and certainly not the only one. In particular it is common to use public variables on Component, rather than a VO, as the data model. I prefer this approach as it works smoothly with Cairngorm, as we shall see in part 2... but I'm getting ahead of myself.
The first step is to identify how the component will be used in an application, it’s ’use cases’. There are two kinds of use case for a visual component. They display dynamic information and respond to certain user gestures (i.e. mouse or keyboard events). So we ask ourselves:
- what does it show?
- what does it do?
Then we write a Value Object (VO) that provides the information necessary for the component to do and show what it will. A VO is simply an actionscript class that has only public properties or getter/setters. A VO will act as Data Model for our component. Link shows a photo and the user’s name. Therefore our component’s VO requires a string for the name and another string for the URL where the image will be found:
public var photoUrl:String;
public var name:String;
We want to show the user’s page when the Link is clicked, so the component also needs to know the user’s ID:
public var userID:uint;
So we create a class called LinkVO that has nothing but these 3 public variables. Eventually this class will hold information received from our server, mapped with remote class metadata to a java equivalent.
Next we need to make a few more files. First the component itself, Link, which holds all the other parts together. Then we will make a two views; one with the user’s name the other with their photo. Being able to readily change the apparence of components is a major strength of OpenFlux, and is far easier to use than messing around with Flex borderSkin assignments etc. etc. Finally we’ll write a simple controller that will subscribe responses to mouse clicks on the view.
role | name | extends |
component | Link.as | ListItem |
view | TextLinkView.mxml | FluxView |
view | ImageLinkView.mxml | FluxView |
controller | LinkController.as | FluxController |
The view is displays information. The controller responds to user gestures. The component stores the VO and sets the default view and controller. I recommend the pictured folder structure. In the downloadable files these are at.newbe.model etc.
Link - component
First override the getter and setter functions for data from the parent class (ListItem). I’ll talk more about data when we put our Link in List. We’ll runtime type check that a LinkVO has been assigned to this property:
private var _linkVO:LinkVO;override public function get data():Object { return _linkVO; }override public function set data(value:Object):void {
if (value is LinkVO) _linkVO = value as LinkVO;
}
ListItem implements IFactory with its newInstance():* method. We must override this so it returns a Link, rather than a ListItem. Implementing IFactory allows a component be a List’s item renderer.
override public function newInstance():* {
var instance:Link = new Link();
return instance;}
Finally we’ll set the default view and controller. We do this by overriding the protected createChildren() method. If the view or controller are undefined, set values as new instances of the defaults. Mark the class as [Bindable] And that’s it! Check the class you have written is the same as the downloaded file.
override protected function createChildren():void {
if(!controller) controller = new LinkController();
if(!view) view = new TextLinkView();
super.createChildren();
}
TextLinkView - view showing user’s name
Now we’ll make a very simple view that will display the user’s name. Open tags for the property +content, within them place a label with text bound to {component.data.name}:
<flux:content>
<mx:Label text="{component.data.name}"/>
</flux:content>
All visual components that will be displayed by the view are placed within the FluxView’s content variable. Anything else, like degrafa fills/strokes and states go outside. Note that you can access the component with the eponymous variable, and thus we bind the view directly to the VO. I love <10 line classes!
PhotoLinkView - view showing user’s profile photo
Next a more interesting view that shows the user’s profile photo. There are lots of ways to do this, but this is by far the best I have found. We’ll display the photo using a Degrapha image fill, with an image loaded from the photoUrl property of LinkVO:
<paint:BitmapFill id="photo" source="{component.data.photoUrl}" smooth="true" repeatX="{BitmapFill.STRETCH}" repeatY="{BitmapFill.STRETCH}" />
One advantage of this method over the default Flex Image component is advanced anti-aliasing, set by smooth="true". This fill will scale to the size of the shape it’s applied to. Next we’ll make a solid-stroke outline for the photo, and a rectangle for fill
and stroke to be applied to:
<degrafa:SolidStroke id="edge" color="#FF9900" weight="2" caps="round" joints="round" pixelHinting="true" /><degrafa:GeometryComposition graphicsTarget="{[image]}"><degrafa:RoundedRectangle width="{width}" height="{height}" fill="{photo}" stroke="{edge}" cornerRadius="2.5" /></degrafa:GeometryComposition>
<flux:content><flux:FluxView id="image" width="{width ? width : 54}" height="{height ? height : 54}" /></flux:content>
LinkController - controller
This controller is very simple, in part because of some of OpenFlux’s fantastic custom metadata tags. Create a private variable with the same and type as our component, Link. Now add the [ModelAlias] tag before it, and this variable will represent a typed reference to the component at runtime.
[ModelAlias] private var link:Link;
[ViewHandler(event="mouseUp", handler="mouseUpHandler")]public class LinkController extends FluxController
metadata function mouseUpHandler(event:MouseEvent):void {trace( "please show me the user’s page" );}
Testing our new component
Open up Main.mxml and create a LinkVO with some dummy information. Then make a PhotoLinkView. Then create a 2 Links in an HBox, and bind it’s data property to the LinkVO:
<vo:LinkVO id="user1" photoUrl="assets/images/01.jpg" name="Flexy Frederick" userID="1" /><views:PhotoLinkView id="photo" visible="false" />
<mx:VBox><view:Link data="{user1}" view="{photo}" /><view:Link data="{user1}" /></mx:VBox>