Tutorial 1: FB 4.5 Hello World – done the MadComponents way
MadComponents. Easier than Flash Builder 4.5?
In my previous post, I made comparisons between Flash Builder 4.5 and MadComponents for mobile applications. Inevitably, the ActionScript + MadComponents app was much smaller than the same app written using Flash Builder.
App size is a big deal for mobile apps. It’s a big deal for Adobe, who are already battling negative perceptions about the performance of the Flash Platform on mobile. Particularly on the iPhone.
So does Flash Builder make up for it in other ways? Does it simplify the development process?
I don’t believe it does. But obviously I’m biased, as I created MadComponents. So don’t take my word for it. Take a look at my MadComponents examples at http://code.google.com/p/mad-components/source/browse/ . Or try these tutorials, that guide you though using MadComponents from first principles – and judge for yourself.
Even though MadComponents doesn’t have a visual drag-and-drop UI builder (I don’t have time to write one) – expressing something in MadComponents XML markup language is often equivalent to significant fiddly coding in Flex. MadComponents is more than just lightweight mobile components, it simplifies communication with the server too. ( More about that in later tutorials. )
These tutorials are based on Adobe’s “Getting Started With Flex On Mobile” tutorials at:- http://www.adobe.com/devnet/flex.html. I’ll be describing about how to do each of the mobile exercises using MadComponents. So if you like, you could work through both tutorials, and decide which suits you best. MadComponents or Flash Builder.
MadComponents is IDE agnostic. You can use Flash Builder (Flex), or Flash, or a third-party IDE such as AXDT, or Flash develop. I deliberately restricted myself to SDK4.0 capabilities. And I didn’t use any AIR-only classes. This means that MadComponents is incredibly portable. You don’t need the latest IDE, or the latest SDK, or AIR runtime. You can test or deploy a MadComponents application to the browser if you wish. I tend to work this way – restricting myself to core flash platform features to develop a ubiquitous application that will run “anywhere”. Only adding specific AIR functionality, as a separate, and optional extensions – for desktop, or mobile deployment, at the end.
MadComponents Layouts
MadComponents has its own XML layout language. A layout will be a familiar concept to anyone who has used HTML, MXML, native Android development, or Java Swing. The advantage of an XML layout is that it expresses how the UI is arranged irrespective of screen size, orientation and pixel density. MadComponents deals with this nitty gritty – you don’t have to.
This is how you express a label, and a button, arranged vertically:-
<vertical> <label>Hello, World!</label> <button>Continue</button> </vertical>
Suppose you wanted to arrange things horizontally. You’d write:-
<horizontal> <label>Hello, World!</label> <button>Continue</button> </horizontal>
Let’s take this one step further, and improve the formatting.
<columns alignH=”fill”> <label>Hello, World!</label> <button>Continue</button> </columns>
Now the label, and the button, are each allocated half of the screen width. But let’s change the components, so we can see their widths more clearly, and also change the ratios of the columns:-
<columns alignH=”fill” widths=”30%,30%,40%”> <input/> <button/> <slider/> </columns>
Now we have three columns, and a custom ratio of widths. Widths can also be specified in absolute pixels. For example, widths=”90,40%,60%”. Absolute pixel measurements are allocated first. The input field will be 90 pixels wide. Note there is no “%” sign after 90 – so it means 90 pixels. Not 90 percent. After all the pixel measurements are allocated, then the relative, percentage widths are allocated. The button will take up 40% of the remaining width, and the slider will take up the last 60%.
If you wish to change the spacing between columns, you can use the gapH attribute. (Or gapV attribute vertically).
<columns alignH=”fill” widths=”30%,30%,40%” gapH=”20″> <input/> <button/> <slider/> </columns>
There is no padding attribute in MadComponents Layout. If you wish to insert padding, you can use an <image/> component within the layout, and specify its size. for example:-
<image>30,40</image>
Where 30 is the width, and 40 is the height.
The Hello World Example
So let’s get started with “Build a mobile app in five minutes“. The following instructions are appropriate whether you’re using Flash or Flex. What the tutorial demonstrates is how to make an application with two pages, where you can click on buttons to switch between the pages.
Downloads
If you need to peek at the answers at the back of the book, go ahead.
Flash users can download the project from http://code.google.com/p/mad-components/downloads/list . To run this Hello World example, just follow steps (2A) and (7) below. Changing the call from “MadComponents” to “MadHelloWorld”.
Flex (Flash Builder) users can check-out the MadComponents demos from the Subversion repository at: http://code.google.com/p/mad-components/source/checkout . MadHelloWorld.as is the example for this tutorial.
Hello World Step by Step
Whether or not you’ve jumped ahead to see the final result – here are the step by step instructions:
1. If you don’t have the latest version of MadComponents, you can download it from http://code.google.com/p/mad-components/downloads/list
You’ll need MadComponentsLib0_5.swc (or a newer version when available).
2A. If you’re using Flash. You need to find your libs folder. For Flash CS5, you’ll find this directory at the following path, from your Flash application folder:-
Adobe_Flash_CS5/Common/Configuration/ActionScript_3.0/libs
Once you’ve found this folder, put MadComponentsLib into it:-
2B. If you’re using Flash Builder (Flex), just include the .swc into the project in the usual way.
( Project -> Properties -> ActionScript Build Path -> Library Path -> Add SWC Folder… lib )
3. Create a new ActionScript application. Call it “MadHelloWorld”. Either Adobe AIR ActionScript applications, or a browser based application.
4. For an Adobe AIR application, set your window size to 300 x 454. (not applicable to a browser application). In Flash, you’ll see this in the properties panel:-
( On a real device, it will adapt to the screen size, but in simulation – it assumes 300 x 454 pixels )
5. Now save your application. In Flash, make sure you’ve made a new folder for it.
6. In Flex, you’ll already have a top ActionScript class. In Flash you’ll need to create one. File->New->ActionScript File. Call it “MadHelloWorld.as”. Save it in the same folder as MadHelloWorld.fla .
7. In Flash, create a link between the timeline project, and the ActionScript file. (No need to do anything in Flex). Click on the first cell on the timeline, and in the Actions Panel, type:
new MadHelloWorld(this);
8. Now you’re ready to write some code. Let’s start with the first layout example, and generate the UI for this XML using the UI.create() method.
package { import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import com.danielfreeman.madcomponents.*; public class MadHelloWorld extends Sprite { protected static const HOME_VIEW:XML = <vertical> <label>Hello, World!</label> <button>Continue</button> </vertical>; public function MadHelloWorld(screen:Sprite = null) { if (screen) screen.addChild(this); stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; UI.create(this, HOME_VIEW); } } }
Note the code setting stage.align and stage.scaleMode. This isn’t a MadComponents thing, just a standard pure ActionScript thing to ensure no scaling, and aligning the corner of the app to the corner of the screen.
This example creates a label and a button. But we want to put them in the centre of the screen.
9. Add alignH and alignV attributes to the layout. Note the British spelling “centre”.
<vertical alignV=”centre”> <label alignH=”centre”>Hello, World!</label> <button alignH=”centre”>Continue</button> </vertical>
10. That’s better, and we can create the second page in a similar way. For now, just replace the layout, for the layout of the second page, to see what it will look like:-
<vertical alignV=”centre”> <label alignH=”centre”> Success!</label> <button alignH=”centre”>Back</button> </vertical>
11. Now we need to make a layout that includes both pages. Because the Flash Builder has a title bar at the top, we’re going to use a Navigation container. We call it a “container” because it contains one or more pages.
<navigation title=”HomeView”> {HOME_VIEW} {MY_NEW_VIEW} </navigation>
The curly braces {} provide a convenient way to split up the layout definition into manageable, readable, small chunks of XML. So with both pages inside a Navigation container our code looks like this:-
package { import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import com.danielfreeman.madcomponents.*; public class MadHelloWorld extends Sprite { protected static const HOME_VIEW:XML = <vertical alignH="centre" alignV="centre" width="100"> <label alignH="centre">Hello, World!</label> <button id="forward" alignH="fill">Continue</button> </vertical>; protected static const MY_NEW_VIEW:XML = <vertical alignH="centre" alignV="centre" width="100"> <label alignH="centre">Success!</label> <button id="back" alignH="fill">Back</button> </vertical>; protected static const NAVIGATOR:XML = <navigation title="HomeView"> {HOME_VIEW} {MY_NEW_VIEW} </navigation>; public function MadHelloWorld(screen:Sprite = null) { if (screen) screen.addChild(this); stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; UI.create(this, NAVIGATOR); } } }
I’ve made a small change to the way things are placed in the centre of the screen. This was to make buttons the same size.
12. When we run the above example, we see the first page. But clicking on the button has no effect. We need to set up a listener, and a handler that tells the navigation container to display the second page.
package { import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import com.danielfreeman.madcomponents.*; public class MadHelloWorld extends Sprite { protected static const HOME_VIEW:XML = <vertical alignH="centre" alignV="centre" width="100"> <label alignH="centre">Hello, World!</label> <button id="forward" alignH="fill">Continue</button> </vertical>; protected static const MY_NEW_VIEW:XML = <vertical alignH="centre" alignV="centre" width="100"> <label alignH="centre">Success!</label> <button alignH="fill">Back</button> </vertical>; protected static const NAVIGATOR:XML = <navigation id="navigation" title="HomeView" leftArrow=""> {HOME_VIEW} {MY_NEW_VIEW} </navigation>; protected var _navigation:UINavigation; public function MadHelloWorld(screen:Sprite = null) { if (screen) screen.addChild(this); stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; UI.create(this, NAVIGATOR); _navigation = UINavigation(UI.findViewById("navigation")); var forward:UIButton = UIButton(UI.findViewById("forward")); forward.addEventListener(UIButton.CLICKED, goForward); } protected function goForward(event:Event):void { _navigation.goToPage(1); } } }
In the example above, we set up a reference to objects in the user interface. Notice that in the layout, we’ve given the navigation, and the button ‘ids’. id=”navigator” and id=”forward”. In the ActionScript, we can refer to these ids, using UI.findViewById(). Now we can set up listeners, or refer to their methods or properties.
We set up a listener to detect clicks on the button:-
forward.addEventListener(UIButton.CLICKED, goForward);
And within the goForward handler, we tell the navigator to display the second page (we start counting pages at 0, so the second page is page 1).
_navigation.goToPage(1);
The navigation container automatically gives you a back button on the title bar. So we can switch back to the first page. So now we have a two page example. But it’s not quite like the one in the FB4.5 tutorial.
13. We want to add three more features to complete the example above.
We want the back button in the centre of the screen to work. We set up a listener and a handler just like we did before. But this time, we’ve added transition to the page change. UIPage.SLIDE_LEFT and UIPage.SLIDE_RIGHT
We want to get rid of the back button on the title bar. By setting the text of this button to the empty string, leftArrow=”” ,it disappears.
And we want to change the, depending which page we’re on. So within the handlers, we set _navigation.title.
Here is the updated code:-
package { import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import com.danielfreeman.madcomponents.*; public class MadHelloWorld extends Sprite { protected static const HOME_VIEW:XML = <vertical alignH="centre" alignV="centre" width="100"> <label alignH="centre">Hello, World!</label> <button id="forward" alignH="fill">Continue</button> </vertical>; protected static const MY_NEW_VIEW:XML = <vertical alignH="centre" alignV="centre" width="100"> <label alignH="centre">Success!</label> <button id="back" alignH="fill">Back</button> </vertical>; protected static const NAVIGATOR:XML = <navigation id="navigation" leftArrow="" title="HomeView"> {HOME_VIEW} {MY_NEW_VIEW} </navigation>; protected var _navigation:UINavigation; public function MadHelloWorld(screen:Sprite = null) { if (screen) screen.addChild(this); stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; UI.create(this, NAVIGATOR); _navigation = UINavigation(UI.findViewById("navigation")); var forward:UIButton = UIButton(UI.findViewById("forward")); forward.addEventListener(UIButton.CLICKED, goForward); var back:UIButton = UIButton(UI.findViewById("back")); back.addEventListener(UIButton.CLICKED, goBack); } protected function goForward(event:Event):void { _navigation.goToPage(1,UIPages.SLIDE_LEFT); _navigation.title = "MyNewView"; } protected function goBack(event:Event):void { _navigation.goToPage(0,UIPages.SLIDE_RIGHT); _navigation.title = "HomeView"; } } }
So that’s it. An application with two pages, where clicking on buttons causes the page to change.
14. Finally, let’s just play around with colour. We can specify the colour of the application, using the colour attribute. For example, make the following change:-
<navigation id=”navigation” leftArrow=”” title=”HomeView” colour=”#334433″>
This colour setting will actually cascade through the XML description, and the buttons will inherit this colour from the navigation controller. If you want to make a button a different colour, you can so this:-
<button id=”forward” alignH=”fill” colour=”#CC9933“>Continue</button>
If you want to change the background colour, you can use the stageColour attribute:-
<navigation id=”navigation” leftArrow=”” title=”HomeView” colour=”#334433″ stageColour=”#EEFFEE”>
But the Flash Builder tutorial, goes one step further than just changing the colour of components. It shows you how to skin the buttons. MadComponents can do this too. But we’ll talk about how to do that in the next tutorial.
Further reading
To find out more about MadComponents, you can read the other related threads on this blog, or download the documentation at http://code.google.com/p/mad-components/downloads/list
Please subscribe to this blog if you want to catch subsequent tutorials.
Awesome Work Daniel!!! Thank you soooooo much for for this and sharing it. I’m working on a project now and was banging my head with Flex’s MXML. Love this!!!
Your components are awesome, much much faster than the mobile.swc that Adobe provides, either on compile time, deployment time or startup time. I used version 0.6.
Few suggestions:
1- A TextArea component (mainly for input, but with height enabled)
2- “enabled” property for buttons;
3- An Alert replacement
Note:
The buttons rounded borders are not sharp on the default size.
Thank you
1. TextArea. There is a workaround. You can turn a label into a textArea.
<label id=”textInput” alignH=”fill” height=”200″/>
var textInput:UILabel = UILabel(UI.findViewById(“textInput”));
textInput.mouseEnabled=textInput.multiline=textInput.selectable=true;
textInput.type=TextFieldType.INPUT;
textInput.borderColor = 0xCCCCCC; //These lines optional and aesthetic
textInput.border = true;
2. MadComponents enabled is called clickable. You can set the “clickable” property of the button to false.
var button:UButton = UIButton(UI.findViewById(“button”));
button.mouseEnabled = button.clickable = false; // will cover all bases.
If you want to make the button LOOK disabled, you may want to change its colour too.
3. By Alert, you mean a pop-up window? MadComponents has one of those. See the MadComponents.as example, to see how it works.
_popUp = UI.createPopUp(POPUP_LAYOUT, 180.0, 200.0);
When you say “not sharp, you mean out of focus? Or curve is wrong? Does <button alt=”true”/> help?
Many thanks for clarifying about the workarounds! They worked!
By “not sharp” I mean the curve is wrong, corners are pixeled, and alt didn’t help.
Great component set, Dan — one question:
I set the button’s clickable property to false, and it still generates events and shows the cursor. I set the mouseEnabled property to false, and it does not do those things. So why do we need clickable?
“clickable” is used inside a scrolling container. Like a scrollVertical, or a list. The mouse events are apprehended by the framework while scrolling because you first, you need to determine whether something was a scroll, or a swipe.