Thursday, December 17, 2009

Flash Builder: Spark Skinning Issue to look out for (hopefully they'll fix this)

If you're in the ActionScript world and haven't cracked open the beta of Flash Builder (the latest version of Flex Builder, just rebranded), it's time to hit the Adobe site and pull it down. There's a lot to like about it.


It ain't perfect yet though. Here's a brief post about a couple of things I've discovered that might throw you when you get started.


Spark Skinning

The new Spark components (get ready for the new s: namespace) seem to work great, and have a lot less overhead than the old mx flex ones. For instance, "groups", like s:HGroup and s:VGroup, can be used instead of "boxes", like HBox and VBox. They work the same way, but don't contain logic for scrollbars and such. This somewhat mediates the old Flex issue of nested containers impacting performance. Although you should still always be careful nesting containers, its good to know that, at least to a point, you can be a little more creative about their use without overtly damaging your app's perf. You can also do more with CSS than in the past as far as skinning, fonts, and so forth. Great stuff.


However, it's still in beta, and I stumbled across what appears to be more of an API/OOP design flaw than a bug, but nevertheless still feels like something is broken, so here it is:


When using a Spark List component, you may want to reskin the Scrollbar (let's face it, the default scrollbars are UGLY). To skin the scrollbar, you would implement a new skin class for the part of the scrollbar that you want to alter, then simply apply it to that element of the scrollbar. The easiest way to to this would be to just copy the content of the default skin class, put it in a new class, modify it to suit your needs, then apply it in place of the default one. Note that the Spark documentation says this is the way to go; you shouldn't override or extend skin classes.


However, the default scrollbar skin for the increment and decrement arrows contains an "Arrow" MXML piece. Remember, this is the SKIN class, not the implementation class. Even if I omit the skin class entirely, I would expect the app to still compile and run; a null check would avoid any errors, though you may not see a skin for the scrollbar, or a default system skin would be used; something other than the app completely breaking without any compile-time errors.


You can find the Spark skin classes in [FB Install folder]/sdks/[version]/frameworks/projects/sparkskins/src/mx/skins/spark, which is great; using them as a starting point for skinning you Spark components makes this actually very easy.


Anyway, in those default Arrow classes (the ones I'm interested in are ScrollBarUpButtonSkin, and ScrollBarDownButtonSkin), you'll see this MXML fragment:



<!-- arrow -->
<s:Path horizontalCenter="0" verticalCenter="-1" id="arrow"
data="M 3.5 0.0 L 7.0 7.0 L 0.0 7.0 L 3.5 0.0">
<s:fill>
<s:RadialGradient rotation="90" focalPointRatio="1">
<s:GradientEntry id="arrowFill1" color="0" alpha="0.65" />
<s:GradientEntry id="arrowFill2" color="0" alpha="0.8" />
</s:RadialGradient>
</s:fill>
</s:Path>


Now, I don't want that, because I'm drawing some very custom shape in place of this default arrow. So, I omit that MXML fragment, and replace it with a Graphic object, in which I use the new drawing MXML stuff to create a new arrow.



<s:Graphic width="25" height="20">
<s:Path data="M 0 0
L 25 0
L 25 10
L 12.5 20
L 0 10
L 0 0" >

<s:stroke>
<s:SolidColorStroke color="0x29a094"/>
</s:stroke>

<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xFFFFFF" alpha="1"/>
<s:GradientEntry color="0x7ac8c5" alpha="1"/>
</s:LinearGradient>
</s:fill>

</s:Path>
</s:Graphic>


After making the new class with the Graphic element instead of the old "arrow" drawing path one, I applied it to my Spark List component and compiled; new errors. I ran the program though, and it crashed right away. The error was that the "arrow" property could not be found, and there was no default value, etc. So, out of curiosity (and the desire to get the app running), I just added a public var, "arrow" : Object, and again compiled without errors. Running it though caused another error, and then another, because "arrowFill1" and "arrowFill2" were not found, no default value, etc.


So, I had to add these three public vars to my custom class to get the app to run.



// don't remove these, they are placeholders for the wonky "arrow" mxml that isn't needed here.
public var arrow : Object = { };
public var arrowFill1 : uint = 0;
public var arrowFill2 : uint = 0;


After that it worked.


To me, this is broken; as long as the skin class is properly made, it shouldn't need to contain ANYTHING in order to run properly, as long as any necessary interfaces are implemented (a well built API should be interface based). Implementation of functional objects should not be a concern of the skin class. But it is; you have to put in those dummy properties to get this to work.


I circulated this find, and the consensus seemed to be that yes, this should be fixed; there's no reason a required visual object should be in a skin class, circumventing compile time errors and crashing the entire app when it tries to instantiate a skin for a scrollbar. Evidently, more hacking away found that this is the case in a number of Spark skins.


Insurmountable? Nah, just add the public properties to satisfy the Spark parent component demand for whatever it's looking for. But it's wonky and, as far as the consensus of the people I referred the error to, should be addressed by Adobe before the product is released, for the sake of elegance if nothing else.


As always, thanks for visiting.