Space of Flex/AIR technologies

Beyond Plain Old Html Objects

Archive for the ‘Examples’ Category

Swiz 1.0 Chaining API explained

with 7 comments

Yesterday I was tasked to find the best way to bootstrap a Flex application that uses Swiz 1.0 RC1. The challenge was to initialize application controllers and data model in the right sequence. This is an AIR application so it had to initialize data from an SQLite database, make few calls to remote services to check for data updates and do couple of other things before user could actually see first screen. My initial thought was to create a StartupController that would invoke the proper functions in a right order. That was a good initial direction but things started to get more difficult when I had to deal with async remote calls and local async APIs such as the one from the SQLite database.

So my next thought was, why not to try the new Chaining API that comes with Swiz? After my first look at the documentation I wasn’t really sure how I should approach it but after more digging I managed to figure it out ;) Here is what I did. I kept my StartupController with its init function that gets called after the controller is constructed and all its dependencies are injected. This was ensured by the [PostConstruct] metadata that comes with latest version of Swiz. Next that function creates a chains of function calls, remote invocations and events that bootstrap my application.

This is my StartupController where everything starts:

package controllers
{
	import delegates.RemoteServiceDelegate;
 
	import flash.events.IEventDispatcher;
 
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
 
	import org.swizframework.events.ChainEvent;
	import org.swizframework.utils.chain.AsyncCommandChainStep;
	import org.swizframework.utils.chain.ChainType;
	import org.swizframework.utils.chain.CommandChain;
	import org.swizframework.utils.chain.EventChain;
	import org.swizframework.utils.chain.EventChainStep;
	import org.swizframework.utils.chain.FunctionChainStep;
 
	public class StartupController
	{
		[Dispatcher]
		public var dispatcher:IEventDispatcher;
 
		[Inject]
		public var remoteServiceDelegate:RemoteServiceDelegate;
 
		[PostConstruct]
		public function init():void
		{
			// Initializing sequential CommandChain, that will stop on errors
			var commandChain:CommandChain = new CommandChain(ChainType.SEQUENCE, true);
			// Registering event listener when chain execution is complete
			commandChain.addEventListener(ChainEvent.CHAIN_COMPLETE, commandChainComplete);
			// Registering event listener in case chain execution fails
			commandChain.addEventListener(ChainEvent.CHAIN_FAIL, commandChainFail);
 
			// Adding async chain step that invokes remote AMF service
			commandChain.addStep(
				new AsyncCommandChainStep(
					remoteServiceDelegate.ping,
					["ping param value"],
					pingResultHandler,
					pingFaultHandler));
			// Adding function step that calls local function
			commandChain.addStep(new FunctionChainStep(this.localFunction));
 
			// Initializing parallel event chain that will be nested in command chain
			var eventChain:EventChain = new EventChain(dispatcher, ChainType.PARALLEL, true);
			// Registering event listener when event chain execution is complete
			eventChain.addEventListener(ChainEvent.CHAIN_COMPLETE, eventChainComplete);
			// Registering event listener in case chain execution fails
			eventChain.addEventListener(ChainEvent.CHAIN_FAIL, eventChainFail);
 
			// Adding event chain step that will dispatch INIT_PERSISTENCE event,
			// this event is mediated in PersistenceController
			eventChain.addEvent(new EventChainStep("INIT_PERSISTENCE"));
			// Adding event chain step that will dispatch INIT_SOMETHING_ELSE event,
			// this event is NOT mediated anywhere, this just for example and better understanding
			// eventChain.addEvent(new EventChainStep("INIT_SOMETHING_ELSE"));
 
			// Nesting event chain in parent command chain
			commandChain.addStep(eventChain);
			// Starting whole command chain
			commandChain.start();
		}
 
		private function localFunction():void
		{
			trace("Running localFunction");
		}
 
		public function pingResultHandler(event:ResultEvent):void
		{
			trace("Received result from remote ping call:", event.result);
		}
 
		public function pingFaultHandler(event:FaultEvent):void
		{
			trace(event.fault.faultDetail);
		}
 
		private function commandChainComplete(event:ChainEvent):void
		{
			trace("CommandChain complete");
		}
 
		private function eventChainComplete(event:ChainEvent):void
		{
			trace("EventChain complete");
		}
 
		private function commandChainFail(event:ChainEvent):void
		{
			trace("CommandChain failed");
		}
 
		private function eventChainFail(event:ChainEvent):void
		{
			trace("EventChain failed");
		}
	}
}

Below is my PersistenceController that will initialize the local database; its init function is called when the INIT_PERSISTENCE event is dispatched. When the database initialization is finished event.complete(); has to be called in order to proceed with chain execution:

package controllers
{
	import flash.events.IEventDispatcher;
 
	import org.swizframework.utils.chain.EventChainStep;
 
	public class PersistenceController
	{
		[Dispatcher]
		public var dispatcher:IEventDispatcher;
 
		[Mediate("INIT_PERSISTENCE")]
		public function init(event:EventChainStep):void
		{
			trace("Initializing PersistenceController...");
			event.complete();
		}
 
	}
}

This last snippet demonstrates the RemoteServiceDelegate class, which can be used to invoke remote services. It works with AsyncCommandChainStep:

package delegates
{
	import mx.rpc.AsyncToken;
	import mx.rpc.remoting.RemoteObject;
 
	public class RemoteServiceDelegate
	{
		[Inject]
		public var remoteObject:RemoteObject;
 
		public function ping(param:String):AsyncToken
		{
			return remoteObject.ping(param);
		}
	}
}

You can download my demo project source code from here; note that it doesn’t do anything except print out traces to the console. This zip contains a build of latest Swiz source code from GitHub that has some FunctionChainStep fixes.

Written by Piotr Walczyszyn

August 11th, 2010 at 3:51 pm

Posted in Examples

Tagged with ,

Designer-Developer workflow before Flash Catalyst times

with one comment

Yesterday I was presenting during CS5 Launch event. My session was about new workflow between designers and developers using Flash Catalyst. In my presentation I used cartoon below to describe how this workflow looked before Flash Catalyst era. This cartoon is usually shown during project management courses but I think it also applies very well in this case ;)

I used http://www.projectcartoon.com service to define my perspective on this, if you have yours go ahead and define it and share it here. There are other really cool cartoons that you can use.

Here is the link to my cartoon: http://www.projectcartoon.com/cartoon/76265

Patricia Clausnitzer transleted this post to Belarusian: http://pc.de/pages/designer-developer-be

Written by Piotr Walczyszyn

May 19th, 2010 at 3:41 pm

Posted in Examples

Tagged with

My presentation slides from 1st European Augmented Reality Business Conference

with 2 comments

Below I have embedded slides from my presentation that I did last Friday in Berlin during the 1st European Augmented Reality Business Conference.

A PDF document with links to Flash based AR examples is here. The working demo application that I coded during my session is here with it’s source code and AR marker to print out.



Written by Piotr Walczyszyn

April 26th, 2010 at 10:28 am

Posted in Events,Examples

Tagged with ,

Adobe resources to start learning Flex

with 2 comments

During the last few events that I presented at I got asked questions about links to resources that can help beginners start learning Flex. I quickly compiled the list below. I really like Tour De Flex the most; this is actually a resources that I still use myself ;)

Written by Piotr Walczyszyn

March 15th, 2010 at 11:44 am

Posted in Examples

Tagged with

Java-AS3 serialization with AMF

with 6 comments

A few weeks ago I published Flerry project a Flex-Java bridge for AIR 2.0. In this post I wanted to explain how it works and what I used on the Java side to do AS3/Java AMF de/serialization. First of all Flerry uses the new NativeProcess API that comes with AIR 2.0. This new API allows communication between AIR application and any native application running on a user’s machine with standard input, output or error streams. Almost any type of data can be transferred over those streams, ranging from simple strings, numbers, Booleans, bytes and byte arrays to AMF serialized AS3 objects. Of course if AMF serialized AS3 objects are streamed then receiving side of the communication needs to understand this format. In the case of Flerry, the receiving side is Java and obviously it doesn’t have a built-in AMF deserializer. In order to enable AMF on the Java side I decided to investigate Adobe’s Open Source BlazeDS project (BlazeDS is the server-based Java remoting and web messaging technology that enables developers to easily connect to back-end distributed data and push data in real-time to Adobe® Flex® and Adobe AIR™ applications for more responsive rich Internet application (RIA) experiences). As BlazeDS is designed to work by default inside of JEE containers it must have had it already implemented.

After a short investigation it turned out that I was right and BlazeDS comes with very simple to use AMF de/serializer. What you actually need to make it work are two jar files: flex-messaging-common.jar and flex-messaging-core.jar, which are in the BlazeDS package available for download from here. In those jars I found two classes Amf3Input and Am3Output that allowed me to send and receive AMF serialized AS3/Java objects over input/output/error streams.

So how does it all work?

On the AS3 side I used the NativeProcess.standardInput.writeObject(message) function where the message object is of the type flex.messaging.messages.RemotingMessage that maps to equivalent flex.messaging.messages.RemotingMessage on the Java side with the proper RemoteClass metadata. Of course any POAO (Plain Old ActionScript Object) could be used instead of RemotingMessage. In my case I just wanted to reuse standard classes out of the Flex SDK that wrap transferred content and add properties required for asynchronous communication.

Below is actual code from Flerry that writes AMF serialized AS3 objects to the standard input stream (source code of NativeObject.as class is available here):

protected function call(method:NativeMethod, ... args):AsyncToken
{
	if (!nativeProcess)
		initialize();
 
	var message:RemotingMessage = new RemotingMessage();
	message.operation = method.name;
	message.source = source;
	message.headers = {SINGLETON_HEADER:singleton};
 
	if (args.length == 1)
		message.body = args[0];
 
	nativeProcess.standardInput.writeObject(message);
 
	var token:AsyncToken = new AsyncToken(message);
	tokens[message.messageId] = token;
 
	return token;
}

On the Java side I used the Amf3Input class to deserialize received data from the input stream (System.in) into proper Java objects (source code of NativeObject.java class is available here):

public void init()
{
	Amf3Input amf3Input = new Amf3Input(SerializationContext.getSerializationContext());
	amf3Input.setInputStream(System.in);
	try
	{
		Object object;
		while ((object = amf3Input.readObject()) != null)
		{
			if (object instanceof RemotingMessage)
			{
				RemotingMessage message = (RemotingMessage) object;
				try
				{
					if (message.getSource() != null)
					{
						Object sourceObject = null;
						if (singleton)
							sourceObject = singletonObject;
						if (sourceObject == null)
						{
							sourceObject = sourceClass.newInstance();
							if (singleton)
								singletonObject = sourceObject;
						}
 
						Object[] params = (Object[]) message.getBody();
						Class[] paramsTypes = new Class[params.length];
						for (int i = 0; i < paramsTypes.length; i++)
						{
							paramsTypes[i] = params[i].getClass();
						}
 
						Object result = sourceObject.getClass().getMethod(message.getOperation(), paramsTypes).invoke(sourceObject, params);
						respond(result, message.getMessageId());
					}
					else
					{
						Boolean stopProcess = (Boolean) message.getHeader(NativeObject.STOP_PROCESS_HEADER);
						if (stopProcess != null && stopProcess)
						{
							break;
						}
					}
				}
				catch(Exception e)
				{
					handleException(e, message.getMessageId());
				}
			}
			else
			{
				handleException(new Exception(
						"Received object is not RemotingMessage type!"), null);
			}
		}
	}
	catch (Exception e)
	{
		handleException(e, null);
	}
	finally
	{
		try
		{
			amf3Input.close();
		}
		catch (IOException e)
		{
			handleException(e, null);
		}
	}
}

To send data back to AIR I used the Amf3Output class. With a little help from ByteArrayOutputStream Java objects are serialized to AMF format and written back to System.out.

protected void respond(Object object, String correlationId)
{
	try
	{
		Amf3Output amf3Output = new Amf3Output(SerializationContext.getSerializationContext());
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		amf3Output.setOutputStream(baos);
 
		AcknowledgeMessage message = new AcknowledgeMessage();
		message.setBody(object);
 
		message.setCorrelationId(correlationId);
		amf3Output.writeObject(message);
		System.out.write(baos.toByteArray());
 
		amf3Output.close();
	}
	catch (Exception e)
	{
		handleException(e, correlationId);
	}
}

Written by Piotr Walczyszyn

February 1st, 2010 at 5:11 pm

Posted in Examples

Tagged with , ,

Secure sockets with Adobe AIR 2.0

without comments

During my journey of discovering the goodness of AIR 2.0 I wanted to try the new secure sockets functionality. AIR 2 comes with a new class, SecureSocket, which actually extends the standard Socket class. The easiest way for me to test it was to try to connect to GMail’s IMAP server. I was actually inspired by very cool example built by Christian Cantrell called MenuMail available here to download from Adobe Labs. I think the code below is self explaining; when you click Connect button you should see following trace output in the console:
onConnect [Event type="connect" bubbles=false cancelable=false eventPhase=2]
onSocketData [ProgressEvent type="socketData" bubbles=false cancelable=false eventPhase=2 bytesLoaded=66 bytesTotal=0]
* OK Gimap ready for requests from x.x.x.x n12if410166gve.29

Below is the source code:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication 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:halo="library://ns.adobe.com/flex/halo">
 
	<fx:Script>
		<![CDATA[
			import flash.events.Event;
			import flash.events.IOErrorEvent;
			import flash.events.MouseEvent;
			import flash.events.ProgressEvent;
			import flash.events.SecurityErrorEvent;
			import flash.net.SecureSocket;
			import flash.net.Socket;
 
			protected var secureSocket:SecureSocket;
 
			protected function btnConnect_clickHandler(event:MouseEvent):void
			{
				secureSocket = new SecureSocket();
				secureSocket.addEventListener(Event.CONNECT, onConnect);
				secureSocket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
				secureSocket.addEventListener(IOErrorEvent.IO_ERROR, onIoError);
				secureSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
				secureSocket.connect(txtServerAdress.text, parseInt(txtServerPort.text));
			}
 
			/**
			 * Handles Event.CONNECT event when successful connection is established
			 */
			protected function onConnect(event:Event):void 
			{
				trace("onConnect", event);
			}
 
			/**
			 * Handles ProgressEvent.SOCKET_DATA when data is received through the SecureSocket
			 */
			protected function onSocketData(event:ProgressEvent):void 
			{
				trace("onSocketData", event);
 
				var socket:Socket = event.target as Socket;
				trace(socket.readUTFBytes(event.bytesLoaded));
			}
 
			/**
			 * Handles IOErrorEvent.IO_ERROR when IO error happens during the connection
			 */
			protected function onIoError(event:IOErrorEvent):void 
			{
				trace("onIoError", event);
			}
 
			/**
			 * Handles SecurityErrorEvent.SECURITY_ERROR event on any security errors
			 */
			protected function onSecurityError(event:SecurityErrorEvent):void 
			{
				trace("onSecurityError", event);
			}
 
		]]>
	</fx:Script>
 
	<halo:Form horizontalCenter="0" verticalCenter="0">
		<halo:FormHeading label="Connection info"/>
		<halo:FormItem label="Server adress:">
			<s:TextInput id="txtServerAdress" text="imap.gmail.com" />
		</halo:FormItem>
		<halo:FormItem label="Server port:">
			<s:TextInput id="txtServerPort" text="993"/>
		</halo:FormItem>
		<halo:FormItem>
			<s:Button id="btnConnect" label="Connect" click="btnConnect_clickHandler(event)" />
		</halo:FormItem>
	</halo:Form>
 
</s:WindowedApplication>

Written by Piotr Walczyszyn

January 29th, 2010 at 4:06 pm

Posted in Examples

Tagged with

File promises with Adobe AIR 2.0

with one comment

File promises is one of the new AIR 2.0 features already available in beta on Adobe Labs. “A file promise is a drag-and-drop clipboard format that allows a user to drag a file that does not yet exist out of an AIR application. AIR uses the methods and properties defined by the IFilePromise interface to access the data to be written when the file promise is dropped.” To check out how it works, I built a sample application that allows you drag an AIR icon out of the app and drop it somewhere in your system (e.g. on your desktop). Dropping it will initiate a download of the current stable AIR runtime installer (at this point in time it is AIR 1.5.3). The downloaded file containing the runtime will be appropriate for your operating system. This logic is implemented in the fileUrl function and it uses the Capablities.os property with a simple regexp search for “win”, “lin”, or “mac” patterns.

Here is how the application looks:

Below is the source code:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication 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:halo="library://ns.adobe.com/flex/halo"
					   currentState="START_STATE" height="200" width="300" viewSourceURL="srcview/index.html">
 
	<s:layout>
		<s:VerticalLayout horizontalAlign="center" gap="15"/>
	</s:layout>
 
	<fx:Script>
		<![CDATA[
			import flash.events.Event;
			import flash.events.MouseEvent;
			import flash.system.Capabilities;
 
			protected var filePromise:URLFilePromise;
 
			protected function imgAirIcon_mouseDownHandler(event:MouseEvent):void
			{
				// Instantiating new file promise
				filePromise = new URLFilePromise();
				// Registering OPEN event listener, to switch to 
				// DOWNLOAD_STATE when downloading starts
				filePromise.addEventListener(Event.OPEN, onOpen);
 
				// Setting URLRequest pointing to remote file
				filePromise.request = new URLRequest(fileUrl);
				// Setting relativePath with fileName to be saved locally
				filePromise.relativePath = fileName;
 
				// Array of promises with single promise in this case
				var promises:Array = new Array();
				promises.push(filePromise);
 
				// Instantiating clipboard object pointing to the promise
				var clipboard:Clipboard = new Clipboard();
				clipboard.setData(ClipboardFormats.FILE_PROMISE_LIST_FORMAT, promises);
 
				// Dragging with NativeDragManager
				NativeDragManager.doDrag(imgAirIcon, clipboard);
			}
 
			protected function onOpen(event:Event):void
			{
				currentState = "DOWNLOAD_STATE";
				prgBar.source = filePromise;
			}
 
			protected function get fileUrl():String
			{
				// Returns remote file URL based on current operating system
				if (Capabilities.os.search(/mac/i) > -1)
					return "http://airdownload.adobe.com/air/mac/download/latest/AdobeAIR.dmg";
				else if (Capabilities.os.search(/win/i) > -1)
					return "http://airdownload.adobe.com/air/win/download/latest/AdobeAIRInstaller.exe";
				else 
					return "http://airdownload.adobe.com/air/lin/download/latest/AdobeAIRInstaller.bin";
			}
 
			protected function get fileName():String
			{
				var fileUrl:String = fileUrl;
				return fileUrl.slice(fileUrl.lastIndexOf("/") + 1);
			}
		]]>
	</fx:Script>
 
	<s:states>
		<s:State name="START_STATE"/>
		<s:State name="DOWNLOAD_STATE"/>
	</s:states>
 
	<halo:Image id="imgAirIcon" source="assets/air_icon_special.gif" mouseDown="imgAirIcon_mouseDownHandler(event)" toolTip="{fileUrl}" />
 
	<s:Label text="(Drag it out to start download)" />
 
	<halo:ProgressBar id="prgBar" bottom="10" horizontalCenter="0"  visible="false" visible.DOWNLOAD_STATE="true" label="Downloading {int(prgBar.percentComplete)}%"/>
 
</s:WindowedApplication>

Written by Piotr Walczyszyn

January 26th, 2010 at 5:37 pm

Posted in Examples

Tagged with

Flerry: Flex-Java bridge for Adobe AIR 2.0

with 83 comments

Today I published Flerry on Google Code, a Flex-Java bridge that uses NativeProcess API from Adobe AIR 2.0. Using it is very simple and similar to RemoteObject API in Flex. In fact I reused libraries from BlazeDS to do AMF de/serialization on Java side and on Flex side classes like AsyncToken, RemotingMessage, AcknowledgeMessage and ResultEvent/FaultEvent for eventing.

Here is short snippet how you can use it directly in MXML:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="300" minHeight="200" xmlns:flerry="net.riaspace.flerry.*">
    <fx:Script>
        <![CDATA[
            import flash.events.MouseEvent;
 
            import mx.controls.Alert;
            import mx.rpc.events.FaultEvent;
            import mx.rpc.events.ResultEvent;
 
            protected function nativeObject_faultHandler(event:FaultEvent):void
            {
              Alert.show(event.message.toString());
            }
 
            protected function addMethod_resultHandler(event:ResultEvent):void
            {
              txtResult.text = event.result.toString();
            }
 
            protected function btnAdd_clickHandler(event:MouseEvent):void
            {
              nativeObject.add(parseInt(txtValue1.text), parseInt(txtValue2.text));
            }
            ]]>
    </fx:Script>
    <fx:Declarations>
 
    <!-- Declaring NativeObject that points to 
            net.riaspace.flerrydemo.MyJavaObject class in ./jars/flerry-demo.jar -->
    <flerry:NativeObject id="nativeObject" binPath="./jars/flerry-demo.jar" 
            source="net.riaspace.flerrydemo.MyJavaObject"
            fault="nativeObject_faultHandler(event)">
 
      <!-- Declaring NativeMethod with custom result handler, for this example 
              actually result from NativeObject could be used -->
      <flerry:NativeMethod id="addMethod" name="add" 
            result="addMethod_resultHandler(event)" />
 
    </flerry:NativeObject> 
 
  </fx:Declarations>
 
  <s:HGroup verticalAlign="middle" textAlign="center" horizontalCenter="0" verticalCenter="0">
    <s:TextInput id="txtValue1" text="2" width="30" />
    <s:Label text="+" width="30" />
    <s:TextInput id="txtValue2" text="3" width="30" />
    <s:Button id="btnAdd" label="=" width="30" click="btnAdd_clickHandler(event)" />
    <s:TextInput id="txtResult" width="30" editable="false" />
  </s:HGroup>
 
</s:WindowedApplication>

Some NativeObject properties:

  • binPath – points to jar file with your Java application
  • source – points to java class that this NativeObject maps to
  • singleton – sets source class object as singleton
  • startupInfoProvider – custom implementation of net.riaspace.flerry.IStartupInfoProvider, by default Flerry comes with JavaStartupInfoProvider that tries to detect where Java is installed on users machine, in other case Error is thrown

In following posts I will explain in details how it all works, for now you can download flerry Flash Builder project with all the source code from here.

Written by Piotr Walczyszyn

January 13th, 2010 at 7:32 pm

Posted in Examples,Releases

Tagged with , ,

Simple Flex 4 components styling (part 2)

without comments

In my previous post I gave few hints about styling Flex 4 applications using default Spark theme. This time I extended it to additional MX containers and also wanted to explain what particular CSS properties mean.

  • chrome-color (chromeColor, it was renamed from baseColor after Flex 4 Beta 2) – The main color for a component
  • content-background-color (contentBackgroundColor) – Color of the fill of an item renderer
  • symbol-color (symbolColor) – Color of any symbol of a component. Examples include the check mark of a CheckBox or the arrow of a scroll button
  • selection-color (selectionColor) – The color of text when the component is enabled and has focus
  • focus-color (focusColor) – Color of focus ring when the component is in focus
  • roll-over-color (rollOverColor) – Color of the highlights when the mouse is over the component
  • color – Color of the text
  • text-roll-over-color (textRollOverColor) – Color of the text highlights when the mouse is over the component, used in old MX components.
  • accent-color (accentColor) – Additional color used for accent. This color is used by “emphasized” buttons (default button in Alert box), and the slider track highlight.
/* CSS file */
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
 
global
{
	chrome-color: #333333;
	content-background-color: #333333;
	symbol-color: #FFFFFF;
	selection-color: #FFB129;
	focus-color: #FF7F29;
	roll-over-color: #F7DCAD;
 
	color: #D7D6D6;
	text-roll-over-color: #D7D6D6;
 
	accent-color: #FFB129;
}
 
s|Panel
{
	background-color: #333333;
}
 
mx|Alert
{
	background-color: #333333;
}
 
mx|TabNavigator
{
	background-color: #333333;
}
 
mx|ToolTip
{
	color: #000000;
}

This it the result of applying this style sheet (same as in previous post):

This movie requires Flash Player 10

Written by Piotr Walczyszyn

January 6th, 2010 at 1:45 pm

Posted in Examples

Tagged with

Simple Flex 4 components styling (part 1)

with 6 comments

As you probably know, the upcoming Flex 4 (Gumbo) release was built with design in mind to let developers easily and quickly skin and style their applications. In particular, skinning can be realized with the use of a new component architecture called Spark that comes with two built-in themes, one also called Spark (the default) and the second one called Wireframe (very useful when prototyping). In addition to the skinning capabilities, new CSS properties were also introduced that make it even simpler to style existing components and quickly achieve really good looking results without needing new custom themes.

As an example I came up with a set of styles that you can apply to default Spark components to get a nice looking dark theme. Here is the example (with the source code here):

This movie requires Flash Player 10

Example above uses only following CSS properties:

/* CSS file */
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
 
global
{
	chrome-color: #333333;
	content-background-color: #333333;
	symbol-color: #FFFFFF;
	selection-color: #FFB129;
	focus-color: #FF7F29;
	roll-over-color: #F7DCAD;
	color: #D7D6D6;
}
 
s|Panel
{
	backgroundColor: #333333;
}

To make it even simpler to style your application theme there was a new Appearance panel introduced in Flash Builder 4. It is available in the design view for your main MXML component.

Appearance Panel

Written by Piotr Walczyszyn

January 5th, 2010 at 6:11 pm

Posted in Examples

Tagged with

Switch to our mobile site