For the past ten months I have been working on the same Flex/Air application. It is part of a larger, multi-tiered, multi-language project, of which the Flex subproject is but the front-end. (Actually, I have been involved in one of the other tiers, too, messing with a different programming language; not all my time has been devoted to Flex development during this year.)
Our Flex codebase is a nice instance of a complex, heterogeneous Air application to which probably more than twenty developers have contributed to date. A not-so-well-known Flex MVC framework is at the core of the architecture, and we leverage quite a good number of Flex components and Flash libraries from third parties. We do unit testing, code coverage and continuous integration.
Ever since I joined the team (when the guys had just upgraded from the beta 3 of Air to Air 1.0) there has been an odd issue with the Air project in Flex Builder 3: we could not use FB3's “design view” to preview the layout of the application or to edit our custom MXML components.
The problems were two. First, the design view displayed what looked like a blank canvas — sometimes with whimsical wireframe edges that seemed to represent containers and other children. But only a few of those children appeared (if any at all). Rarely their sizes and positions were right, or their actual contents visible (see the screenshot below). Only when previewing simple components that inherited directly from Flex standard components (and not from our own components) the result seemed correct.
The second problem was that when switching from code view to design view a pair of errors suddenly appeared for every custom font that the project uses (even if the project builds just fine in code view):
unable to resolve '/project/assets/fonts/customFont.ttf' for transcoding | project | line 195
Unable to transcode /project/assets/fonts/customFont.ttf. | project | line 195
We gave it a go at trying to solve these issues at the time (ten months ago), with no luck. It never was much of a problem, though. Not for me at least, since I usually prefer to work on code view, even for building layouts and style-tweaking (in design view FB3 is slow rendering your changes, and I'm too fussy with my code to accept the auto-generated MXML). But boy, was it annoying.
A few days ago I investigated these problems again for a while… and this time I cracked it. Let me share what I learnt, because I think it is not that obvious.
The main problem has to do with the limitations of the design view in FB3. As you probably know (because you bothered to read this far), MXML is just a more readable way to describe visual Flash objects. MXML is more intuitive than ActionScript to define the layout of your Flex GUI precisely because the nesting of XML nodes in MXML matches the nesting of visual components that those XML nodes represent. Actually, the Flex SDK compiles all MXML classes to intermediate AS. If you know that, you would presume that Flex Builder treats both AS classes and MXML classes in pretty much the same way. Well, it doesn't.
It turns out that the “design view” can render any MXML class, provided that all its ancestor classes (up to the first standard Flash component) are defined in MXML too, i.e. not in AS.
In our project we had the situation represented in the diagram below. Most of the “screens” or “pages” in our application are based (directly or indirectly) on a common class. That common class, in turn, inherits from some other class that is defined within the MVC framework. The problem was, that common class was written in ActionScript, thus cutting off the hierarchy of MXML classes that the design view in FB3 “understands”.
All I had to do was rewrite that class in MXML and keep the name of the file, changing its extension from as
to mxml
. It was a quick change: the class was short and I could maintain parts of the original ActionScript embedded within a Script
component anyway. Note that no other changes were necessary, because the subclasses don't care whether their superclass is originally written in AS or in MXML.
As for the other issue (the problem with the custom font families), it seems that the design view can't load custom fonts unless they are defined as embedded resources in AS, i.e. not in separate CSS files.
Originally we had something like this:
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Style source="../styles/fonts.css" />
</mx:WindowedApplication>
Where styles/fonts.css
contained:
@font-face {
font-family: "_DefaultFont";
font-weight: normal;
src: url("../assets/fonts/verdana.ttf");
}
@font-face {
font-family: "_DefaultFontBold";
font-weight: bold;
src: url("../assets/fonts/verdanab.ttf");
}
I removed the CSS file and embeded the two font families directly into the MXML component (which is less elegant, of course):
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
[Embed(source='../assets/fonts/verdana.ttf", fontWeight='normal',
fontName='_DefaultFont', mimeType='application/x-font')]
private var thisObjectIsNeverUsedButItHasToExist_1:Class;
[Embed(source='../assets/fonts/verdanab.ttf', fontWeight='bold',
fontName='_DefaultFontBold', mimeType='application/x-font')]
private var thisObjectIsNeverUsedButItHasToExist_2:Class;
]]></mx:Script>
</mx:WindowedApplication>
I guess the moral of the story is: Adobe, we need a better IDE!