Archive for category flex

How to Make a SWFLoader Scroll

By default, the SWFLoader doesn’t scroll so developers often wrap it in a scrolling mx container like a Canvas (since it does scroll and it’s scroll policies are set to auto). What I didn’t think about was that I’d have to know the actual size of the content I was loading in order for the scrollbars to appear. I tested this in both an MX Application and a Spark Application with Flex SDK 4.5 and achieved the same results.

To reiterate, my small test app below suggests that developers must know the size of the content they are loading in SWFLoader in order for the scrollbars to appear around that loaded content.

When I think about it, it makes sense…at the same time it caught me by surprise when I first implemented it in an app. Hoping this piece of info helps developers loading legacy or 3rd party SWFs they don’t have control over.

<?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:mx="library://ns.adobe.com/flex/mx"
	minWidth="0"
	minHeight="0"
	creationComplete="init(event)"
	backgroundColor="#FF0000"
	>

	<fx:Script>
		<![CDATA[
			import mx.containers.Canvas;
			import mx.controls.SWFLoader;
			import mx.events.FlexEvent;

			protected function init(event:FlexEvent):void
			{
				var swfLoaderContainer:Canvas = new Canvas();
				swfLoaderContainer.percentWidth = 100;
				swfLoaderContainer.percentHeight = 100;
				this.addElement(swfLoaderContainer);

				var swfLoader:SWFLoader = new SWFLoader();
				swfLoader.width = 1200; // does not add scroll bar
				swfLoader.height = 800; // does not add scroll bar
//				swfLoader.percentWidth = 100; // DOES NOT add scroll bar
//				swfLoader.percentHeight = 100; // DOES NOT add scroll bar
				swfLoader.scaleContent = false;
				swfLoaderContainer.addElement(swfLoader);

				var context:LoaderContext = new LoaderContext(false, new ApplicationDomain());
				swfLoader.loaderContext = context;
				swfLoader.load("SWFToLoad.swf");
			}

		]]>
	</fx:Script>

</s:Application>

Post to Twitter Tweet This Post

, , , ,

No Comments

Getting Flex Spark & MX Components to Use Embedded Fonts :: Part 2

In my last post about this I found an ugly workaround in order to get embedded fonts to work in both MX and Spark Components. Since then I’ve learned the best way to do this is simply to select the checkbox in the Project Properties -> Flex Compiler -> “Use Flash Text Engine in MX Components” checkbox = true.

NOTE: Using Flash Builder Burrito and Flex Hero 4.5 — haven’t tested to see if this was the previous issue or not but I wanted to make note of it.

Use Flash Text Engine in MX ComponentsThis seems to make embedded fonts play nice in both MX and Spark components in almost every situation. The one I couldn’t seem to get around was mx:Legend.

When I embedded a font and used this compiler setting, I would randomly see only a couple of my legend labels show up. However, by using just a small piece of my old workaround I was soon back in business.

NOTE: There is one rather large drawback to this though…you have to embed your font twice — once for Spark and once for MX.

Your css should look something like this:

/********************************************************
/ Fonts
/*******************************************************/
@font-face
{
	src: url("/resources/font/MyriadPro-Regular.otf");
	font-family: SparkEmbeddedFont;
	font-weight: normal;
	embed-as-cff: true;
}

@font-face
{
	src: url("/resources/font/MyriadPro-Bold.otf");
	font-family: SparkEmbeddedFont;
	font-weight: bold;
	embed-as-cff: true;
}

/********************************************************
/ NOTE: Due to an issue with the legend and embedded
/ fonts we need to embed the font as non cff too.
/*******************************************************/
@font-face
{
	src: url("/resources/font/MyriadPro-Regular.otf");
	font-family: MXEmbeddedFont;
	font-weight: normal;
	embed-as-cff: false;
}

@font-face
{
	src: url("/resources/font/MyriadPro-Bold.otf");
	font-family: MXEmbeddedFont;
	font-weight: bold;
	embed-as-cff: false;
}

/************************************************************
/ Flex Class-Level Styles
/************************************************************/
s|Application
{
	font-family: SparkEmbeddedFont;
	color: #000000;
}

mx|LegendItem, mx|PieSeries
{
	font-family: MXEmbeddedFont;
	font-size: 12;
	textFieldClass: ClassReference("mx.core.UITextField");
}

Post to Twitter Tweet This Post

, , , , ,

1 Comment

Flex 4 ModuleManager & CSS Inheriting Styles

A client I’m working with has a Flex 3.5 app that’s being migrated to 4.5 and one of the immediate issues we ran into (after we got it compiling successfully) was that the modules didn’t inherit the styles from the main app…worked fine in 3.5, but not in 4.5, so what gives?

So I created a simple PoC with a ModuleLoader and it did indeed pick up on the main apps styles as expected. Next I changed my PoC to resemble the client’s architecture a bit more and used a ModuleManager to load the module — low and behold, the module didn’t inherit the main app’s styles.

After some reading on Adobe’s docs I found the following as the key fix:

Using the ModuleManager class to load modules

You can use the ModuleManager class to load the module. This technique is less abstract than using the tag, but it does provide you with greater control over how and when the module is loaded.

To use the ModuleManager to load a module in ActionScript:

  1. Get a reference to the module’s IModuleInfo interface by using the ModuleManager getModule() method.
  2. Call the interface’s load() method.
  3. The application that loads the module should pass in its moduleFactory property. This lets the module know who its parent style manager is. When using the load() method, you can specify the application’s moduleFactory with the fourth parameter, as the following example shows:

    info.load(null, null, null, moduleFactory);
  4. Use the factory property of the interface to call the create() method and cast the return value as the module’s class. If you are adding the module to a container, you can cast the return value as an IVisualElement (for Spark containers) or a DisplayObject (for MX containers) so that they can be added to the display list.

So the key is passing in a reference to the moduleFactory when calling the ModuleManager.load() method. The 4th parameter is the moduleManager. If you don’t have a reference the main app lying around, just use:

info.load(null, null, null, FlexGlobals.topLevelApplication.moduleFactory);

Link to Adobe’s Docs on this.

Post to Twitter Tweet This Post

, , , , , ,

3 Comments

Great Ant Build Series for Flex

Many people have asked if we use Maven or Ant for Flex builds…while we like Maven for Java, we don’t like Maven for Flex. It’s not that we don’t like Maven in general (obviously since we’re cool with it for Java), we just found it’s almost too much trouble with Flex. It never fails to make us want to pull our hair out and say “Why bother?” — Yes, we have used FlexMojos and we’re still not convinced. So we use Ant for Flex builds.

Instead of writing our own Ant build tutorial series for Flex, we’d like to push you to Jon Campos’s tutorials:

January 7th, 2010 - Using ANT to build an Application
January 14th, 2010 - Building a Library with ANT
January 19th, 2010 - Building the HTML Wrapper with ANT
January 20th, 2010 - Building a Custom HTML Wrapper with ANT
January 21st, 2010 - Including Assets Files with ANT
January 26th, 2010 - Building a Library and Application with ANT
January 28th, 2010 - Building ASDocs with ANT
February 2nd, 2010 - Run Flex Unit Tests from ANT
February 4th, 2010 - Run FlexMonkey Tests from ANT
February 9th, 2010 - The Master Flex ANT File

Thanks for an awesome series Jon.

As a side note, if someone can convince me that mvn + flex is better/easier than ant by all means ping me. brianr@webappsolution.com

Post to Twitter Tweet This Post

, ,

1 Comment

Getting Spark & MX Components to Use Embedded Fonts :: UPDATED**

You’d think embedding a font and declaring it as an Spark Application style would cascade down to all components — after all, CSS = Cascading Style Sheet, right? Well, it doesn’t. The font won’t show up in your MX components.

After bumping our heads against this about 8-9 months ago we decided to move on…I recently had to come back to it and found this helpful link that allowed me to do the following to get this working as expected.

UPDATE*: Added style for MX DataGrid.

@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";

@font-face
{
	src: url("/resources/fonts/Chalkboard.ttc");
	font-family: ChalkboardEmbedded;
	font-weight: normal;
	font-style: normal;
	embed-as-cff: true;
}

s|Application
{
	font-family: ChalkboardEmbedded;
	font-size: 12;
}

mx|global
{
	textFieldClass: ClassReference("mx.core.UIFTETextField");
}

mx|DataGrid
{
	defaultDataGridItemEditor: ClassReference("mx.controls.MXFTETextInput");
	defaultDataGridItemRenderer: ClassReference("mx.controls.dataGridClasses.FTEDataGridItemRenderer");
}

The class-level global style is what does the trick as it instructs all MX components using text fields to use the UIFTETextField class — it allows MX or Halo components to leverage CFF embedded fonts.

Run the app with those styles defined and you’ll notice that one component still doesn’t want to listen — the title of the Spark Panel (or at least that’s the only component I’ve run across so far that doesn’t work).

I tried defining the style for the Spark Panel specifically, but no dice. I also tried creating a new skin for the Spark Panel and set the fontFamily property of the titleDisplay to my embedded font of ChalkboardEmbedded and that also failed. Anyone else come up with a solution for this?

UPDATE*: This approach failed for the following MX classes:

  • ProgressBar
  • FormHeading

This approach failed for the following Spark classes:

  • Panel

UPDATE*:I spoke to several Adobeans on the Flex Doc team and this is unfortunately a known issue:

This approach works for most components, but not Panel and a couple others (he identified Panel and ProgressBar in his blog). I suspect he found a bug. This whole thing about using the same embedded font in MX and Spark components was meant to be a temporary solution until Spark had parity with MX controls. A year and a half later, and there’s still no parity, so there’s no surprise that users are running into this.

Brian, I would ask him to submit a bug.

He can take a look at the spec: http://opensource.adobe.com/wiki/display/flexsdk/Font+Embedding+Reprise

That spec seems to indicate that Panel and ProgressBar should work the way it is documented.

Post to Twitter Tweet This Post

, , , , ,

2 Comments

Swiz EventHandler Filtering With Pub/Sub Topics - Part 1

We tend to build many Flex applications with modules, so having the ability to broadcast and listen for messages based on the scope attribute for both Dispatchers and EventHandlers is essential in Swiz.

UPDATE: Part 2 has Swiz framework code changes and a more robust solution.

If you don’t know about Swiz Event Scoping, then read on; otherwise, skip to the section labeled Filtering With Topics below.

Background

You can read the actual documentation from Swiz in the last link, but the gist is that you can tell Swiz to either broadcast events on a “global” level (using the highest level Application object) or on a “local” level (using the Module itself) and then listen to those events in the same fashion. This allows you to tell modules to listen to events only from themselves and not other modules (that might have the same events) or to listen to all events from your main, shell application and/or all other modules. Let’s look at a quick example by assuming the dispatching code is in LoginViewMediator and the handling code is in LoginController in a Module.

Local Event Dispatching

Local Event Dispatching From LoginViewMediator

/**
 * Allows this class to dispatch local events. Only methods using an
 * EventHandler metatadata tag with the property of scope="local" can
 * handle this event.
 *
 * <p>
 * The event dispatcher is injected by Swiz due to the [Dispatcher] metadata
 * and the class member's type of IEventDispatcher.
 * </p>
 */
[Dispatcher(scope="local")]
public var localDispatcher:IEventDispatcher;
...
public function login(userName:String, password:String):void
{
	logger.debug("login");

	var appEvt:AppEvent;

	appEvt = new AppEvent(AppEvent.SERVICE_LOGIN);
	appEvt.username = userName;
	appEvt.password = password;
	this.localDispatcher.dispatchEvent(appEvt);
}

Local Event Handling in LoginController

[EventHandler(event="AppEvent.SERVICE_LOGIN", properties="username, password", scope="local")]
public function login(username:String, password:String):void
{
	logger.debug("login: username = " + username + ", password = " + password);
}

If we had other Modules with this same EventHandler statement in their LoginController they would not fire because we specified the scope as local. If we change the scope property to global and the AppEvent is in a common library that all Modules can use, then they would each hear this event and all fire, which in many cases is not what you want. Just so we have a full understanding of what’s going on, let’s show an example of broadcasting global events in a similar fashion:

Global Event Dispatching

Global Event Dispatching From ModuleA

/**
 * Allows this class to dispatch global events. Only methods using an
 * EventHandler metatadata tag with the property of scope="global" can
 * handle this event. This means other modules and even the shell application
 * can handle this event if we want.
 *
 * <p>
 * The event dispatcher is injected by Swiz due to the [Dispatcher] metadata
 * and the class member's type of IEventDispatcher.
 * </p>
 */
[Dispatcher(scope="global")]
public var globalDispatcher:IEventDispatcher;
...
public function sayHello():void
{
	logger.debug("sayHello");

	var appEvt:AppEvent;

	appEvt = new AppEvent(AppEvent.SAY_HELLO);
	appEvt.hello = "Hello World!";
	this.globalDispatcher.dispatchEvent(appEvt);
}

Global Event Handling in Module B

[EventHandler(event="AppEvent.SAY_HELLO", properties="hello", scope="global")]
public function hello(hello:String):void
{
	logger.debug("hello = " + hello);
}

Filtering With Topics

Again, this is awesome…but what if you want to broadcast a message that you only want some of the modules to hear? You could obviously put in some simple logic in the event handler that determines if your Module was supposed to listen to the event based on a parameter passed in the EventHandler MetaData, but this could potentially become a large and unwieldy task that you’ll need to apply to all new modules…so what if we introduce filtering of Swiz events via a topic attribute in the EventHandler metadata and a corresponding topic property in our dispatched event?

To do this, we’ll need to do some quick monkey patching to Swiz (by creating the same package structure and adding the same classes we want to change that exist in the Swiz SWC). First, let’s add the topic property to the org.swizframework.metadata.EventHandlerMetadataTag. Add the topic property:

protected var _topic:String;
public function get topic():String
{
	return _topic;
}

Then add the following to the method override public function copyFrom( metadataTag:IMetadataTag ):void

if( hasArg( "topic" ) )
    _topic = getArg( "topic" ).value;

Next we’ll edit the method public function handleEvent( event:Event ):void in org.swizframework.utils.event.EventHandler. Add the following right after the first if() statement:

// look for a topic -- if the one exists in the EventHandler MeataData and
// the event does not have one or the value does not equal the EventHandler's
// then we'll filter out this event and not allow it
if(metadataTag.topic != null)
{
	if(event["topic"] == null)
	{
		return;
	}
	else if(event["topic"] != metadataTag.topic)
	{
		return;
	}
}

That’s it. Let’s give it a whirl by using a global dispatcher again, but adding a topic property to the event and a topic attribute to the EventHandler metadata.

Global Event Dispatching From ModuleA

/**
 * Allows this class to dispatch global events. Only methods using an
 * EventHandler metatadata tag with the property of scope="global" can
 * handle this event. This means other modules and even the shell application
 * can handle this event if we want.
 *
 * <p>
 * The event dispatcher is injected by Swiz due to the [Dispatcher] metadata
 * and the class member's type of IEventDispatcher.
 * </p>
 */
[Dispatcher(scope="global")]
public var globalDispatcher:IEventDispatcher;
...
public function sayHello():void
{
	logger.debug("sayHello");

	var appEvt:AppEvent;

	appEvt = new AppEvent(AppEvent.SAY_HELLO);
	appEvt.hello = "Hello World!";
        appEvt.topic = "wasiTopic";
	this.globalDispatcher.dispatchEvent(appEvt);
}

Global Event Handling in Module B

[EventHandler(event="AppEvent.SAY_HELLO", properties="hello", scope="global", topic="wasiTopic")]
public function helloWithTopic(hello:String):void
{
	logger.debug("hello = " + hello); // WORKS
}

[EventHandler(event="AppEvent.SAY_HELLO", properties="hello", scope="global")]
public function helloWithOutTopic(hello:String):void
{
	logger.debug("hello = " + hello); // NOPE
}

[EventHandler(event="AppEvent.SAY_HELLO", properties="hello", scope="global", topic="fooTopic")]
public function helloWithOutTopic(hello:String):void
{
	logger.debug("hello = " + hello); // NOPE
}

UPDATE: Part 2 has Swiz framework code changes and a more robust solution.

Post to Twitter Tweet This Post

, , , , ,

1 Comment

Some Helpful Settings For Maven Builds

When running Maven builds, there are typically a few settings that are useful to have in your ~/.bash_profile (for Mac or similar, depending on your shell) to help get things off on the right foot.

Set memory usage to 1024M minimum.
export MAVEN_OPTS=-Xmx1024m

Set the path to the appropriate SDK for Flash Builder
FLASH4_SDK=’/Applications/Adobe Flash Builder 4 Plug-in/sdks/3.5.0′

Set the path for ADL if building AIR applications
ADL_PATH=${FLASH4_SDK}/bin

Set the path to the Flash Player for launching FlexUnit tests
FLASH_PLAYER_PATH=’/Applications/Adobe Flash Builder 4 Plug-in/Player/mac/Flash Player.app/Contents/MacOS’

Append these to the current path
export PATH=${PATH}:${ADL_PATH}
export PATH=${PATH}:${FLASH_PLAYER_PATH}

Post to Twitter Tweet This Post

, ,

No Comments

Substitution Tokens in Resource Bundle Strings in Flex

There’s many times where you want to use a Resource Bundle String in-conjunction with variable data. People often breakup the RB String into 2 pieces like so:

part1=My name is
part2=and I like

And then put it back together in AS like:

var part1:String = ResourceManager.getInstance().getString('Labels', 'part1');
var name:String = "Brian Riley";
var part2:String = ResourceManager.getInstance().getString('Labels', 'part2');
var likes:String = "beer.";

var myStr:String = part1 + " " + name + " " + part2 + " " + likes;

Which works, but it’s a lot of unnecessary code. Take advantage of the tokens allowed in RBs and do the following:

likes=My name is {0} and I like {1}

var likes:String = ResourceManager.getInstance().getString('Labels', 'likes', ["Brian Riley", "beer."]);

The ResourceManager class will automatically substitue the tokens {0} and {1} in order and replace them with the array of strings provided as the last param in the getString() method.

Much simpler, right?

Post to Twitter Tweet This Post

, , , , ,

No Comments