Using StageWebView within a UIComponent in Mobile

StageWebView is the name given to the class that displays the native browser of a mobile device in your mobile app. Since it’s not actually native to AIR it floats above your app. This is a nice gift from the AIR team but as it is you must manually size, position and control the visibility. Well not anymore!

The WebView class adds those features. It wraps the StageWebView up in a UIComponent wrapper. This allows it to be sized, positioned and so on like any other Flex component.

It also exposes the StageWebView snapshot feature. This is a flag that when set to true displays captures snapshot of the Stage Web View at the time the property is set. It then hides the actual StageWebView instance. Setting this property to false removes the snapshot and displays the live web view again. This allows you to display Flex components on top of the web view snapshot. It also helps you to integrate the web view into the display list for animations, transitions, etc.

All updates
• June 2011 – I’ve made a complete rewrite of it. This release exposes the rest of the StageWebView methods and properties and adds snapshot mode and HTML content wrapping.
• July 2011 – I’ve added a few bug fixes and implemented commit properties and measure. Added properties for keyCode for history back and forward. Webview maintains state. Key navigation can be disabled properly. This version is not as tested as much as the last. Let me know of any issues. July 28 release (early release)
• Nov 2011 – Feel free to modify and post this or derivatives on your own site.
• Dec 2011 – I’ve been working on an update. The first thing I’ve fixed is that webview visibility is bound to the UIComponent visible property instead of the developer manually hiding and showing it.
• Jan 2012 – Created a mobile example project showing loading a local URL, remote URL, HTML markup, HTML page markup and snapshot mode.
• Feb 2012 – I’ve uploaded the class and example to my Google Code mobile library.
• Jan 2012 – LATEST STABLE – This is the latest stable download for Jan 2012 Release and Example Project
• Feb 2013 – LATEST BETA – A new beta version that supports runtime DPI and adds more support for JavaScript is available in the GitHub repository here. I’ve added StyleableWebView that has some usage examples. I haven’t had time to create a zip or example project for the this version but it’s being used in production. To use this you can manually download the class files you need from GitHub or you will have to checkout the MainLibrary and MobileLibrary projects from GitHub and then import those into FlashBuilder to create the SWC. Once you’ve added the SWC to your own project you can then create instances of a WebView component.

To use:

<!-- StageWebView is only available for Flex SDK Mobile (Flex 4.5) -->
<?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:components="com.flexcapacitor.components.*">

	<fx:Script>
		<![CDATA[
			protected function button1_clickHandler(event:MouseEvent):void {
				event.currentTarget.selected ? webView.loadString("Hello world") : webView.load("http://google.com");
			}

			protected function togglebutton1_clickHandler(event:MouseEvent):void {
				webView.snapshotMode = event.currentTarget.selected;
			}

		]]>
	</fx:Script>

	<s:HGroup>
		<s:ToggleButton label="HTML/URL" click="button1_clickHandler(event)"
						width="150" height="64"/>
		<s:ToggleButton label="Snapshot" click="togglebutton1_clickHandler(event)"
						width="150" height="64"/>
		<s:ToggleButton label="Add/Remove" click="button2_clickHandler(event)"
				  width="150" height="64"/>
	</s:HGroup>

	<components:WebView id="webView" top="100" source="http://google.com" width="100%" height="100%"/>

	<s:Label top="100" width="100%"
			 text="This label is only visible when a non interactive snapshot is being displayed."
			 fontWeight="bold" fontSize="24"
			 backgroundColor="#ffffff" lineBreak="toFit" />
</s:Application>
Posted in AIR, Flash, Flex, Mobile, Tips | 161 Comments

Getting the Video Player to work with Audio

As you know, the Video Player in Flex 4 is capable of playing various types of media including audio. However there are a few issues that will wreck havoc on your progress if you’re not aware of them. There are two issues we’ll go over.

The first is when the audio automatically starts playing as soon as the source property is set. This happens even if autoPlay is set to false. This can be fixed by setting the autoDisplayFirstFrame to “false” which is set to true by default (for video content).

The second is forcing the Video Player to recognize a URL Resource as audio when there is no extension on the URL and no or incorrect mime type set. For example, “myAudio.mp3″ works while, “getAudio.php?id=1000″ does not. You can set the media type explicitly by setting the resource mediaType property like so:

// in the creation complete handler
var audioElement:AudioElement = new AudioElement();
audioElement.resource = new URLResource(path);
audioElement.resource.mediaType = MediaType.AUDIO;
videoPlayer.source = audioElement.resource;

If you were using OSMF directly it would be similar:

// taken from OSMF Release Samples project

		public function WT03_HandlingDifferentMedia()
		{
			initPlayer();
		}
		
		protected function initPlayer():void
		{
			//the pointer to the media
			var resource:URLResource = new URLResource( PATH_TO_AUDIO );

			//we set the media type explicitly to handle audio
			resource.mediaType = MediaType.AUDIO;

			// Create a mediafactory instance
			mediaFactory = new DefaultMediaFactory();
			
			//creates and sets the MediaElement (generic) with a resource and path
			var element:MediaElement = mediaFactory.createMediaElement( resource );
			
			//the simplified api controller for media
			player = new MediaPlayer( element );
			
			//the container (sprite) for managing display and layout
			container = new MediaContainer();
			container.addMediaElement( element );
			
			//Adds the container to the stage
			this.addChild( container );
		}

In the resource set the mediaType to MediaType.AUDIO. At this time there are 4 types of media the OSMF Framework* supports. These are “swf”, “audio”, “video” and “image”.

*The Flex 4 Spark Video Player is based on the OSMF framework.

Posted in AIR, Bugs, Flash, Flash Catalyst, Flex, Technology, Tips | Leave a comment

FXG for an arrow (chevron) and triangle

FXG for a right arrow (or chevron rotated to the right):

Ridght side decorator arrow

<s:Graphic width="100" height="100" >
	<s:Group width="100" height="100" >
		<s:Path data="M 0 0 L 50 50 L 0 100 L 50 50 L 0 0 z">
			<s:fill>
				<s:SolidColor color="#FF0000" />
			</s:fill>
			<s:stroke>
				<s:SolidColorStroke weight="10" color="#FFFFFF" joints="round"/>
			</s:stroke>
		</s:Path>
	</s:Group>
</s:Graphic>

At a smaller size:

    <s:Graphic width="24" height="24">
       <s:Group width="100" height="100" >
          <s:Path data="M 0 0 L 50 50 L 0 100 L 50 50 L 0 0 z">
             <s:fill>
                <s:SolidColor color="#FF0000" />
             </s:fill>
             <s:stroke>
                <s:SolidColorStroke weight="10" color="#CCCCCC" joints="round"/>
             </s:stroke>
          </s:Path>
       </s:Group>
    </s:Graphic>

In an ItemRenderer that shows when the row is selected:

Item Renderer

	<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
					xmlns:s="library://ns.adobe.com/flex/spark"  
					width="100%"
					>
		<fx:Script>
			<![CDATA[
				override public function set selected(value:Boolean):void {
					super.selected = value;

					chevron.visible = value;
				}
			]]>
		</fx:Script>

			<s:Label id="labelDisplay" 
					 paddingBottom="10" paddingRight="10"
					 paddingLeft="20" paddingTop="10"
					 left="1" right="1"
					 top="1" bottom="1"
					 verticalAlign="middle" 
					 textAlign="left"
					 >

			</s:Label>

			<s:Graphic id="chevron" width="24" height="24" verticalCenter="0" right="5">
			   <s:Group width="100" height="100" >
			      <s:Path data="M 0 0 L 50 50 L 0 100 L 50 50 L 0 0 z">
			         <s:fill>
			            <s:SolidColor color="#FF0000" />
			         </s:fill>
			         <s:stroke>
			            <s:SolidColorStroke weight="10" color="#FFFFFF" joints="round"/>
			         </s:stroke>
			      </s:Path>
			   </s:Group>
			</s:Graphic>
	</s:ItemRenderer>

A triangle facing right:

Triangle

<s:Graphic id="triangle" width="50" height="50" >
	<s:Group width="100" height="100" >
		<s:Path data="M 0 0 L 50 50 L 0 100 z">
			<s:fill>
	  			<s:SolidColor color="#FF0000" />
			</s:fill>
			<s:stroke>
				<s:SolidColorStroke weight="10" color="#FFFFFF" joints="round"/>
			</s:stroke>
		</s:Path>
	</s:Group>
</s:Graphic>

Triangle facing left:

Triangle

<s:Graphic id="triangle" width="50" height="50" >
	<s:Group width="100" height="100" >
		<s:Path data="M 0 50 L 50 100 L 50 0 z">
			<s:fill>
	  			<s:SolidColor color="#FF0000" />
			</s:fill>
			<s:stroke>
				<s:SolidColorStroke weight="10" color="#FFFFFF" joints="round"/>
			</s:stroke>
		</s:Path>
	</s:Group>
</s:Graphic>

Triangle facing up:

Triangle

<s:Graphic id="triangle" width="50" height="50" >
	<s:Group width="100" height="100" >
		<s:Path data="M 0 50 L 100 50 L 50 0 z">
			<s:fill>
	  			<s:SolidColor color="#FF0000" />
			</s:fill>
			<s:stroke>
				<s:SolidColorStroke weight="10" color="#FFFFFF" joints="round"/>
			</s:stroke>
		</s:Path>
	</s:Group>
</s:Graphic>

Triangle facing down:

Triangle

<s:Graphic id="triangle" width="50" height="50" >
	<s:Group width="100" height="100" >
		<s:Path data="M 0 0 L 50 50 L 100 0 z">
			<s:fill>
	  			<s:SolidColor color="#FF0000" />
			</s:fill>
			<s:stroke>
				<s:SolidColorStroke weight="10" color="#FFFFFF" joints="round"/>
			</s:stroke>
		</s:Path>
	</s:Group>
</s:Graphic>
Posted in AIR, Flash, Flash Catalyst, Flex, FXG | 3 Comments

Flash Catalyst Jailbreak for Flex Developers

UPDATE: MANY of these issues I had have been addressed in the new Flash Catalyst CS5. You may find it unnecessary to modify it. BTW if you are a designer this software is the best choice in maintaining your high fidelity designs online. It’s much more than they advertise it to be. There is a trial version so you can see for yourself. But dude, being able to copy your assets from Illustrator and paste them into Flash Catalyst maintain your vector format and animate them is just wild. Dig in. This is just the beginning. :)

As a Flex developer you’ve heard about Flash Catalyst and you’ve probably determined if it will or will not help you. Not so fast chachke. I’ve completely streamlined my workflow, fitting in the design requirements has become much easier and enabled round-trip editing and Flex project integration. Flash Catalyst can help you develop your Flex applications especially if it’s jail broken.

Benefits
• Maintain high fidelity design from design tools
• Reduce download size of your app
• Easier to make changes in code
• Easier to work with designer and design
• Round-trip skins
• Integrate your Catalyst project with Flash Builder, etc
• Real world learning aid
• – Spark Skinning
• – Spark Transitions
• – Spark Filters
• – the new Text Layout Framework
• Using custom components in Catalyst
• Using additional Flex Spark components (not all are supported)
• Providing ID’s to components and skins

Note: You may (translate will) spend more time in Flash Catalyst than the designer and oddly enough the designer may never use it. FYI This is my unofficial approach based on actual product experience.

Flash Catalyst

Workflow:
• Create Flash Builder project
• Open Flash Catalyst
• Copy artwork layer by layer or at most layer group by layer group from your design tool (PS, AI, FW, etc) and paste into Catalyst (CMD + C and CMD + V).
• Import the default settings except keep nearly everything editable. You can optimize it later.
• Modify and edit the FXG, layers, groups, transitions, names, etc to create Skins and reusable vector art for your projects.
• Copy and paste the skin into your Flash Builder project and assign to your components.

The goal of FC was for the designer to import the design, convert art to components or component skins, create transitions and then package it up and hand it off to the developer to add coding logic. This approach is obvious in theory but it hasn’t been the case. In reality, on Flex projects it’s the developer NOT the designer who is using Flash Catalyst to integrate the artwork correctly into the project.

For example, some text inputs that were in the design next to each other were in the code in completely separate Groups. So what, you say, just copy and paste them into the right Groups in the code. This had disastrous results. Since FC doesn’t yet support positioning using constraints or automatic layout containers every element in the design is hard coded to relative x and y positions often from different Groups. BTW PS and AI Layers = Flex SDK Spark Groups.

Flash Builder could not open the design so I was stuck in code. Many buttons and inputs had no name or id so there was no way to tell what is what and where is what. The automatic tab order was also out of order because of this issue. So anyway, the quickest solution was to go back into FC move all the form controls or graphics of form controls into and under the same group layer. Then add names in the layers which will add corresponding names in the code. And then set the tab order in the Catalyst properties panel because some controls that were in sub groups of the main group would not focus correctly.

Another example, when the skins were created for Buttons or TextInputs there was a lot of redundancy. So what, you say, it works right? Yes and no. So lets say your designer created a Glow filter on a Button or Image in this case. After importing you’ll see this on the same image:

 <s:GlowFilter color="#FFFFFF" alpha="1.0" blurX="10" blurY="10" includeIn="upAndSelected" inner="false" knockout="false" quality="2" strength="1"/> 
 <s:GlowFilter color="#FFFFFF" alpha="1.0" blurX="10" blurY="10" includeIn="overAndSelected" inner="false" knockout="false" quality="2" strength="1"/>
 <s:GlowFilter color="#FFFFFF" alpha="1.0" blurX="10" blurY="10" includeIn="down" inner="false" knockout="false" quality="2" strength="1"/>

When it could have been rewritten like so:

<s:GlowFilter color="#FFFFFF" alpha="1.0" blurX="10" blurY="10" includeIn="upAndSelected,overAndSelected,down" inner="false" knockout="false" quality="2" strength="1"/>

Multiple instances can affect performance and in some cases file size. This redundancy was evident when multiple image files were created for the same graphic. So going into FC code was the only way to consolidate them.

An important note: There isn’t a place to set the ID on Flash Catalyst components. When a designer converts artwork to a component and then exports a custom component with multiple text inputs, say a registration form, none of those text inputs contain ID’s. The ID is important for validation, formatting and form submission. So what, just add it in in Flash Builder.

Ok so we do that but then when the design changes and it does, the one way Flash Catalyst generated code has no knowledge of your so called ID’s. The design has changed and all or nearly all the components are anonymous again. So the developer has to manually find and add the ID to each text input, radio button, button, each time the design is updated etc. So what you say, how long can that take? The design was modified maybe 40 times (adding in minor updates). Each time each component had to be “wired” up again to the focusIn, focusOut, change, keyDown and keyUp handlers. They also had to place the controls back into the correct Groups etc. Having ID’s solves this.

FC allows you to swap out or replace images with other images or symbols. So lets say your designer has a specific graphic used throughout the design. Instead of having 10 identical images of the same image you can reference one instance of the graphic from the library and delete the 9 extra images.

Display Object Properties Panel

Another reason you need to edit the MXML is so you can swap out skins for the components in FC. So say the designer creates one button skin and has 20 graphics of buttons total. You can’t reuse that same button skin in your 20 other button instances. You can’t replace a graphic with a component. You cannot reuse a skin.

Editing MXML Documents
To edit your projects MXML documents we first need to find the path to the Flash Catalyst workspace. To do this publish your Flash Catalyst project (CMD / CTRL + ENTER). Now, the browsers URL shows the path to the project workspace. So in this URL, “file:///Users/judah/Library/Application Support/Adobe/Flash Catalyst/workspace/Project/bin-debug/Main.html”, the project MXML documents are located at, “file:///Users/monkeypunch/Library/Application Support/Adobe/Flash Catalyst/workspace/Project/” when on a Mac.

Flash Catalyst project files

Flash Catalyst project files

Project Files Description
/src – location of the application source files
/bin – the location of any additional flex libraries
/bin-debug – location of testing swf
/html-template – location of the html template that wraps around your application
/src/Main.mxml – the main application file. make your application changes here
/src/Main.css – the css stylesheet of the main application
/src/components – the location of custom components and component skins
/src/assets/graphics – location of optimized FXG graphic symbols
/src/assets/images – location of images

You can edit these XML documents in any text editor. To apply the changes you need to save the file and refresh the Flash Catalyst project. You can do this by opening the changed document in Flash Catalyst code view. When we do this it will recognize the document has changed and prompt you to use the newer version of the file. Select Yes. If the project does not rebuild immediately publish it using CMD + Enter.

Although you can use any text editor you will want to use an editor that supports the Flex SDK. I recommend you use Flash Builder 4 or FDT. Both have debuggers, code completion and more.

Using Flash Builder to modify, run or debug the Flash Catalyst Project
Open Flash Builder and go to File > Import > Flash Builder Project > Project Folder and select the Flash Catalyst “Project” folder that is located in the FC workspace. On Mac it is located here:
/Users/[USERNAME_HERE]/Library/Application Support/Adobe/Flash Catalyst/workspace/Project/

Once you’ve imported it you can run and debug it like any other Flex 4 project. You can update the component skin code and consolidate skins and graphics.

You can even round trip the changes back into FC. The important thing to remember is you must convince FC to notice and reload the updated documents to see the changes reflected in the Design View.

Making the first change – Converting Group to Vertical Group
The first thing we’ll do is modify a layer folder or “Group” as it’s called in code so that it stacks its sub layer contents equally spaced apart from each other in a vertical or horizontal fashion instead of the current method where the contents of the group position themselves using absolute x and y positioning. To do this we only need to modify a few lines of code. If you’re starting with a new FC project drag 3 different components or shapes to the Design View, select them all and select Group.

Now open the MXML document that contains that Group. You can find the document and location of the Group by selecting it in FC Design View and then switching to code view. It will be selected. In your Flex editor replace the text “Group” with “VGroup” or “HGroup”. Add the property gap to the tag to set the space between each item. For example,

<s:VGroup  gap="18" >
...your content here...
</s:VGroup>

Save the file. Now run the application in Flash Builder or switch back to Flash Catalyst and check for newer files (using the method described above). The content inside that Group should now be stacked horizontally or vertically one after another. You can rearrange their order by moving their position above or below the other layers in the FC Layers panel.

Copy and paste documents to & from Flash Catalyst Code View
You also can copy and paste documents between your editor and Flash Catalyst, thus enabling round tripping. To do this create a separate Flex project instance. Go into FC code view. In the Package Explorer you can select files and directories and then copy them via CMD + C or Edit > Copy from the title menu. You can go back to Flash Builder and paste these files into your separate project folder. After you have modified or upgraded them you can reverse the procedure and copy back to FC. Select the files in Flash Builder Package Explorer and copy them. In FC Code View select the directory where you want to copy the files to and paste them into that directory using CMD + V or Edit > Paste from the title menu. You know where the MXML documents are.

Note: If you use the first method of importing the Flash Catalyst project into Flash Builder the copying and pasting method above won’t allow it. It will say that you are trying to paste the same file to the location it is already at.

Note: Save in Flash Catalyst often. When you close FC it will remove the project directory. It will recreate it when you open the FC project again. Keep that in mind.

Oh and one more thing…
You can gain a couple of rich features such as deep linking, image viewer, context menus and more using another simple modification. Stay tuned…

Enjoy and post your questions here…

Posted in AIR, Flash, Flash Catalyst, Flex | 3 Comments

Converting XML to object tip

When you are retrieving XML from the server and you ask Flex to convert it to an Object, by setting the resultFormat to “object”, Flex provides you with an object proxy representing the original XML. However, when Flex encounters a node with only one item it can’t tell if it’s an Array or a String. So by default it converts the node into a String.

In this example accessing root.people.person is typed as an instance of ArrayCollection:

<root>
   <people>
      <person name="Mikal"/>
      <person name="Nikola"/>
      <person name="Yuliya"/>
      <person name="Katya"/>
      <person name="Peter"/>
   </people>
</root>

But let’s say only one item is returned. Because there is only one item root.people.person is typed as a String:

<root>
   <people>
      <person name="Yuliya"/>
   </people>
</root>

Accessing the first and second example in ActionScript:

// using the first example with multiple nodes this statement 
var value:Object = root.people.person; // returns an array

// using the second example with a single node the same statement
var value:Object = root.people.person; // returns an string

To handle this situation I see the following a lot:

					// if multiple items then property is an array collection 
					if (root.people.person is ArrayCollection) {
						var person:ArrayCollection = root.people.person;
						var personsLength:int = person.length;
						
						// do things
						for (var i:int=0;i<personsLength;i++) {
							var person:PersonVO = PersonVO(person.getItemAt(i));
							// do more things
						}
					}
					
					// if only one item then the date property is a string
					else if (root.people.person is String) {						
						var person:PersonVO = PersonVO(root.people.person);
						// do the same thing as above again
					}

Save yourself repetition and time and convert the single item to an array.

			// content can be object proxy, string or array collection
			var peoples:ArrayCollection = ArrayUtils.getArrayCollection(root.people.person);

						var peoplesLength:int = peoples.length;
						
						// do things
						for (var i:int=0;i<peoplesLength;i++) {
							var person:PersonVO = PersonVO(peoples.getItemAt(i));
							// do what you need to only once
						}
					}
		/**
		 * Converts object to array collection if not array collection
		 * */
		public static function getArrayCollection(object:Object):ArrayCollection {
			// if only one item it is a string add it as a single item to an array
			if (!(object is ArrayCollection)) {
				return new ArrayCollection([object]);
			}
			else {
				return ArrayCollection(object);
			}
		}

What we’re doing is adding the single item to an ArrayCollection so it can use the same code as when the item is an ArrayCollection.

The following HTTPService call that results in this scenario is shown below:

<mx:HTTPService resultFormat="object" />
Posted in Flex, Tips | Leave a comment