Nothing is more annoying than loading up a full browser flex app that has a login screen… It looks like it’s ready so you start typing only to realize that doesn’t let you type anything in. Usually, this is because your SWF file doesn’t have the browser focus. Even if you’ve set the focus to a text input field in ActionScript, you can still fall victim to this issue.

I’d like to share a few techniques I’ve used to ensure that the Flex app is able to get the browser’s focus immediately after loading.

First, you need to ensure that your wmode is set to opaque inside your html script. This isn’t required for all browsers, but in my layman’s testing, Chrome seemed to need it. If you’re using swfobject (the default for a FlashBuilder 4 app), customizing your html template will look something like this.

        <script type="text/javascript" src="swfobject.js"></script>
        <script type="text/javascript">
            <!-- For version detection, set to min. required Flash Player version, or 0 (or 0.0.0), for no version detection. -->
            var swfVersionStr = "${version_major}.${version_minor}.${version_revision}";
            <!-- To use express install, set to playerProductInstall.swf, otherwise the empty string. -->
            var xiSwfUrlStr = "${expressInstallSwf}";
            var flashvars = {};
            var params = {};
            params.quality = "high";
            params.bgcolor = "${bgcolor}";
            params.allowscriptaccess = "sameDomain";
            params.allowfullscreen = "true";
            params.wmode = "opaque";
            var attributes = {};
            attributes.id = "${application}";
            attributes.name = "${application}";
            attributes.align = "middle";
            swfobject.embedSWF(
                "${swf}.swf", "flashContent",
                "${width}", "${height}",
                swfVersionStr, xiSwfUrlStr,
                flashvars, params, attributes);
            <!-- JavaScript enabled so display the flashContent div in case it is not replaced with a swf object. -->
            swfobject.createCSS("#flashContent", "display:block;text-align:left;");
        </script>

Next, you need to run a bit of javascript code to set the focus to your Flex app after it has loaded. There are a number of techniques floating around to do this from your html template, but I prefer the tried and true method of using ExternalInterface from inside your Flex app’s applicationComplete handler. That way, you’re absolutely sure everything has loaded and you’re ready to give yourself the focus.

protected function applicationCompleteHandler(event:FlexEvent):void
{
    //set focus to this app using javascript
    if(ExternalInterface.available)
    {
        ExternalInterface.call("eval", "document.getElementById('" + ExternalInterface.objectID + "').tabIndex=0");
        ExternalInterface.call("eval", "document.getElementById('" + ExternalInterface.objectID + "').focus()");
    }
}

Setting the tabIndex to a value is another one of those quirky Chrome requirements. I found it on a bug report for Google Chrome and it seems to work for me. http://code.google.com/p/chromium/issues/detail?id=27868#c15 I’ve tested this code in Firefox, IE, and Chrome. It should work in Safari as well, but I haven’t tested that one.

Post to Twitter

Posted by Andrew, filed under as3, Flex. Date: December 30, 2010, 6:42 pm | 16 Comments »

When you layer Bitmap images on top of each other in Flash/Flex/AIR, an interesting thing happens. Mouse events are captured by the top-most image and aren’t passed through to anything underneath. Even when hovering over, or clicking on transparent areas, the events just don’t get through. Moses over at MosesSupposes created an InteractivePNG solution that does some interesting mouse handling and hit detection.

In the above example (click the image, right-click to view src), I have two transparent png bitmaps layered on top of each other. On the left side, I’m using the standard BitmapImage tag. When you hover over any part of the images (even transparent areas), you’ll notice that you get the SNOWFLAKE! tooltip. Since the snowflake is on top, it is capturing all mouse activity so nothing gets through to Santa underneath.

On the right, I’m using BitmapSprite. When you have a Sprite that is rendered using graphics drawing, mouse events are only captured in areas where the graphics object has physically been drawn on. BitmapSprite is designed to take an input Bitmap, convert it into 1-pixel tall rectangle bitmap fills that are drawn to the sprite’s graphics object. In this manner, any transparent pixel doesn’t capture mouse events and everything is passed down to objects beneath. When you hover over a snowflake pixel, you get the tooltip SNOWFLAKE!, and when you hover over santa, you get a SANTA! tooltip. With this solution, we’re also caching the result as a bitmap so we only pay the rendering penalty once. No mouse-handling or hit detection kung-fu necessary. Nifty!

Post to Twitter

Posted by Andrew, filed under as3, Flex. Date: December 1, 2010, 12:07 pm | 10 Comments »