This article was written while researching development of a non-Mobile application.
Flex Mobile skinning follows the same approach, but has many differences with greater constraints (especially greater emphasis on Actionscript over MXML), less features, and replacement classes (eg. for text rendering) in order to achieve decent performance on less powerful mobile devices. See http://www.adobe.com/devnet/flex/articles/mobile-skinning-part1.html for specifics.
The Flex 4 component architecture is designed so that the visual appearance of each component is provided by a separate, but associated “skin” class, that can be created in various ways by a designer or developer.
A designer using Flash Catalyst can select some artwork, then convert it to a skin class, specifying the standard component it should map to. This class library can be used in a Flash Builder project.
A developer can easily use the “New…” menu item in Builder to create a skin class based on a standard template. This generated class descends from a generic skin class, and includes a non-trivial amount of code.
Skins are responsible for rendering their children.
Skin parameters can be given in CSS, then used by the skin code.
Flex 4 has some very significant improvements in CSS, including more advanced selectors
For a custom component to appear in Catalyst for skinning, it must follow some strict rules, including being developed in AS3 not MXML.
http://www.slideshare.net/danorlando/360flex-2011-optimizing-the-designer-developer-workflow-using-flash-builder-4-flash-catalyst-cs5 slide 18.
A very useful ability of Flex is the simple separation of areas of an application UI into reusable components containing subcomponents. These can be skinned as a whole, but it is quite complex and ultimately not worthwhile. Instead the container can be skinned as simply a container, and then the subcomponents skinned separately. CSS allows selecting of subcomponents just like in HTML. Also the subcomponents are likely to be standard components anyway, so can be skinned accordingly, not treated as special because they are inside a container.
Some discussion on the web says that compared to Flex 3, Flex 4 skinning makes some simple things much harder, but advanced things much easier.
Builder generates AS3 skins, subclassing Skin, SparkButtonSkin and probably others.
Catalyst generates MXML skins, subclassing Skin and adding states and drawing code.
1. The standard components and skins are lacking basic functionality
Flex 4 skins don’t have as many configurable parameters as Flex 3 components, and you are often forced to use skinning even for some trivial customisations
eg. the Flex 4 Button lets you change the text color, but not the background color in CSS
2. Adobe implicitly encourages skins to be created as application specific, without inheritance or linking in shared code
Builder generates code from templates for the standard components, and this code will therefore be repeated for each custom component you create. Like any code this needs to be maintained, debugged etc and violates DRY (Do not repeat yourself). If Adobe later updates their template for this code, your components will of course not be updated.
Skins created in Catalyst don’t use CSS at all eg. to seperate out assets or colors from rendering code. Please consider and support users in creating configurable components (via CSS), and properly supporting inheritance to maximise reuse.
3. Round-tripping is not the Holy Grail
There is no need for both Builder and Catalyst to be able to edit the same application or library project, and this is an enormous task for Adobe to implement, full of gnarly issues now and into the future. Anyway, developers are quite capable of using Flash Catalyst if necessary, and probably already have or could be given a license to do so. Flash Catalyst applications or libraries only really need to be edited by Flash Catalyst.
Instead we need a linear workflow from designer to developer. The designer should be able to open and edit the FXP/L file as they need, without interference from the developer (although the developer would need to occasionally view and edit). When a developer gets the latest FXP/FXPL by updating from version control, ideally they would be able to rebuild the application in Builder and see the result including the latest FXP/FXPL. This would mean allowing Builder to link in (not import) an FXP/FXPL from Catalyst. Manual exporting and importing is a timewaster and error-prone.
Supporting the FXP format in Builder and encouraging its use in workflow tutorials means that its very easy for developers to do things inside a FXP that are valid in Builder but will make them incompatible with Catalyst. Imagine spending hours on skins that work fine in Builder, only to find you have ruined compatibility with Catalyst and your designer. Adobe provides a compatibility checker to assist in avoiding this, but it is still a productivity risk. Developers shouldn’t try to be too clever in an FXP.
4. FXPL is not a real project format in Catalyst
FXP is the application project format for Catalyst. It is equivalent to a zipped Builder application project. Builder can also load, save and edit FXP files. Catalyst also provides some support for the FXPL format, which is equivalent to a zipped Flex Library project. In Catalyst however, FXPL’s aren’t real projects. You can’t open or save them - you import them into your FXP, or you export your FXP as a FXPL. This is a fundamental faux pas - applications and libraries are different animals - its going to end in confusion when designers unwittingly export one as the other type.
In Catalyst, importing an FXPL does not link the given library, it merges a copy of its files into the current project, once again violating DRY. And so if we are using Catalyst and want to make a minor change to an FXPL, we must begin with an FXP, import the FXPL, make the change and export to FXPL. Presumably the result won’t just have our minor change, the whole FXP will be included too. Catalyst does not support linking of libraries of any sort into an FXP.
On the Builder side, we can import an FXPL from Catalyst into a Builder Library Project, and that seems like a potential way of working intelligently with a version control system, doing a roundtrip to the designer and back using FXPL as a transport format, and checking it in on each return, and perhaps throwing away the FXPL. But it is a manual process for the designer to pass it over, and the developer to receive it. Ideally the designer would just open, save and edit an FXPL, and potentially export a swc for simple linking into the Builder application.
5. FXP/FXPL files are not version control system-friendly
Being zipped into a single file defeats the merging abilities of version control systems like subversion or git. It means that if a designer and developer both modify a common Catalyst project, their changes cannot be automatically combined, and they will have to choose who’s project will be the next version, then apply the other’s changes to that. With a normal unzipped Builder project however, a version control system can merge changes automatically. Simply allowing Catalyst projects to operate on an unzipped folder would solve this problem, but admittedly tempt them into modifying and corrupting the contents without the tool.
There are also some issues with .svn folders being deleted by Builder and Catalyst. See http://kb2.adobe.com/cps/899/cpsid_89968.html
This is not a problem if we treat FXP/FXPL as merely a transport format (a concept I wouldn’t encourage), or if it is very unlikely that two users would work on the same FXP/FXPL at the same time.
6. Skins in Catalyst projects can’t be linked into the application in a Builder project.
We need to view and edit skins in a Catalyst project, then somehow link (not import) that into a Builder application project. Builder can link to SWC files and Flex Library Projects, but Catalyst won’t output a SWC, or work with FXPLs properly.
How to fix the situation
1. For now, use this script to compile FXP -> SWC
Catalyst projects are FXP. For linking into Builder, the ideal format is SWC. Therefore we need a simple conversion process from FXP -> SWC. Thankfully this has been solved here : http://www.rogue-development.com/blog2/2009/06/compiling-fxp-swc-a-catalyst-workflow
2. Develop a reusable set of components skins calling getStyle() instead of hardcoded values, drawing code or embedded assets.
The Flex 4 skinning model is actually a great opportunity for component developers as it completely separates the component logic from appearance and interaction. Most of the reasons we may have had for making a custom component in Flex 3, may only require a custom skin in Flex 4. This also means we don’t have to duplicate, maintain or replace component logic when are only interested in the appearance or interaction.
There is now an opportunity for the Flex community to develop open source skin libraries that replace the standard Spark skins and provide adequate customisability via CSS, such that a single skin can work for the requirements of most applications.
Messages to Adobe:
- Please make the standard skins + CSS good enough for 90% of use cases. This would greatly reduce the need for skinning for general applications.
- Round-tripping is not the Holy Grail. Linear workflows are easier to implement, and keep Catalyst accessible in its licensing and distribution to both designers and developers.
- Please allow loading and saving of FXPL projects in Catalyst
- Please allow linking of FXPLs into FXPs in Catalyst
- Please allow building of FXPLs and FXPs to SWCs in Catalyst
- Please allow linking of libraries into Catalyst
- Provide a commandline method of compiling a FXP/FXPL to a swc
- perhaps provide an option where a parallel swc is recompiled whenever the project is saved in Catalyst, for automatic linking into builder.
A small conundrum : For a designer to develop their skin classes, they need to lay out instances of them, compile, run and play with them. Normally this would require an application project, not library project ie an FXP. On the other hand, a library project is more like what we are trying to achieve - a project linkable into the application. This is solved by compiling FXP -> SWC, or if Catalyst fully supported FXPL projects, it could allow components to be dropped onto a pasteboard for experimenting with, and this pasteboard would not be compiled into the production SWC.
References & interesting links