How to Define Styles on Skins in Flex 4

The new component / skin separation in Flex 4 (the Spark Architecture) is pretty nifty. But if you want to add a configurable style to a skin then that style must be defined on the component. For instance if you want to add a backgroundColor style to a Button skin then you need to first create a new Button component with the style on it:

package
{
import spark.components.Button;
 
[Style(name="backgroundColor", type="uint", format="Color")]
public class SButton extends Button
{
 
}
}

Then create a new Button skin that uses the style:

<?xml version="1.0"?>
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
  xmlns:s="library://ns.adobe.com/flex/spark">
 
  <fx:Script>
    import mx.utils.ColorUtil;
  </fx:Script>
 
  <s:states>
    <s:State name="up"/>
    <s:State name="over"/>
    <s:State name="down"/>
  </s:states>
 
  <s:Rect width="100%" height="100%">
    <s:fill>
      <s:SolidColor color="{getStyle('backgroundColor')}"
                    color.over="{ColorUtil.adjustBrightness2(getStyle('backgroundColor'), 64)}"
                    color.down="{ColorUtil.adjustBrightness2(getStyle('backgroundColor'), -32)}"
      />
    </s:fill>
  </s:Rect>
 
  <s:Label id="labelDisplay" paddingBottom="3" paddingLeft="3" paddingRight="3" paddingTop="6"/>
 
</s:SparkSkin>

Then you can use the new Button and skin:

  <SButton label="backgroundColor = #ff0000" backgroundColor="#ff0000" skinClass="SButtonSkin"/>
  <SButton label="backgroundColor = #0000ff" backgroundColor="#0000ff" skinClass="SButtonSkin"/>

The reason that we had to create a new base class just to hold the style is because there would be no other way to set the style in MXML. We could have set the style via CSS or setStyle. Button does not have a style named “backgroundColor” so if we hadn’t created SButton and tried to just set a backgroundColor property on a Button instance via MXML, the compiler would have thrown an error.

So I (with the help of Ryan Frishberg and Mike Labriola) came up with a nifty little way to set styles on skins without having to create new base classes to hold the styles. The idea is that styles should be defined on the skins and you can use a property on the base components to set those styles via MXML. To make it happen I had to Monkey Patch a property named “style” onto UIComponent. In the setter for that style I just parse a string of HTML-ish styles and call setStyle. The cool thing is that I’m calling setStyle on the component but since skins inherit the styles of their host component the skin gets the styles. This also means that the styles don’t really need to be defined on the skins. Just used in the skins. Using the example above to set the backgroundColor on the Button I could just do:

  <s:Button label="backgroundColor = #ff0000" style="backgroundColor: #ff0000" skinClass="SButtonSkin"/>

I didn’t need a new Button class just to set the backgroundColor style. Here is a more complex example with more styles on the skin:

All of those buttons are using the same skin and the base Spark Button! The code for this example is on github. So check it out, fork it, and have fun. Let me know if you have any questions.

This entry was posted in Flex. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
  • http://nsdevaraj.wordpress.com/ Devaraj

    While trying to run it from git, got the below error
    ReferenceError: Error #1056: Cannot create property style on spark.components.Button

    • http://www.jamesward.com James Ward

      You need to turn off the Framework RSLs in order for Monkey Patching to work. Let me know if that works.

  • http://agileui.blogspot.com Rob McKeown

    This is great but it would be even better if the SDK supported this rather than having to Monkey Patch it. These real world requirements seem to have gotten lost in the engineering of the new Spark components. The idea of having to create custom skins and button classes just to set the background color of a button is kind of ridiculous. In my opinion, the components should be able to accept dynamic style attributes just for this reason. So you could do something like:

  • http://agileui.blogspot.com Rob McKeown

    Sorry my code snippet got lost… the idea is to be able to specify an attribute like style:backgroundColor=”#ff0000″ and have it turn into the same as setStyle(“backgroundColor”, 0xff0000);

    • http://www.jamesward.com James Ward

      I’d love some official MXML syntax that would do this. Can you file a feature request and post it here?

  • http://brianlegros.com/blog Brian

    I’m probably missing something huge here, but why not just add the styles to the skin and use CSS to style to skin instead of the component?

    • http://www.jamesward.com James Ward

      You can do that. But not everyone wants to use CSS all of the time.

  • http://agileui.blogspot.com Rob McKeown

    Here is the link to the feature request: https://bugs.adobe.com/jira/browse/SDK-27186

  • jimi

    maybe i am missing something more here, but i find it absolutely wrong having to duplicate tons of code just to change a background alpha value on a skin. If you want to change the skin background alpha, you need to create a new skin, duplicating ALL the original skin code and change it. This is unmaintainable. Just imagine that the original skins get updated or changed. You need to go skin by skin to update the base changes. This will lead to tons of duplicated code. Just what modern languages and OOP try to avoid. Maybe i am wrong???

    Is it possible to extend the skin and modify only the alpha parameter so when the base skin changes, i do not need to also change the copy??

    i hope i’m wrong, but from a developer point of view, this is a disaster.

    • http://www.jamesward.com James Ward

      It is not possible to extend MXML skins. Thus the reason that I created this project to show how skins can be reused by passing in style parameters.

      • jimi

        Ok, but this does not solve the real problem with code reuse: At the moment we are copying one skin to create another one we are duplicating code that may change somewhere in the future, leading to big redundancy problems. If to use an existing skin we must duplicate it’s code, there’s a big problem here for those of us who want to reuse the maximum code possible (and i think all good developers think allways about it).

        maybe i am wrong again, but seems that adobe is focusing more on “i don’t know f*** about developing” designers than in real developrers… so sad

        • http://www.jamesward.com James Ward

          Totally agree that not being able to extend skins and MXML based classes is sad. I’m not sure if there is a “feature request” for this in the Flex bug database yet. If not, file one so I can vote on it.

          • jimi

            hope we see it on the future!

          • http://www.saltwebsites.com/ Fletch

            Alright I put it in, please vote for it! Allow Skin Inheritance in Flex 4.

            In case that link doesn’t work for some reason, just go to Flex SDK ideas and find it.

        • http://blog.flexuous.com Justin Ohms

          You can and always have been able to freely extend MXML classes. I’ve been doing that for years.

          Extending a skin is no different. I have several skins in my current project that all inherit from a base skin. In fact you do that very thing above.

          The entire AS framework is built on this ability.

          There is really nothing to it….

          in ActionScript:

          public fooTwoClass extends superFooClass
          ….

          in MXML :

          means you are extending SparkSkin and creating a new class

          i.e. your own button skin extends SparkSkin

          • http://www.jamesward.com James Ward

            Yeah. Of course you can extend a class created with ActionScript. But you can’t really extend a class that was created with MXML.

  • http://dougr.net Doug

    Hey James!
    I tried this out on s:Application, wanting to get a transparent background for the application container. I simply created an .as class SApplication:

    package components
    {
    import spark.components.Application;

    [Style(name="backgroundAlpha",type="Number",default="0")]
    public class SApplication extends Application
    {
    public function SApplication()
    {
    super();
    }
    }
    }

    I instantiated the new app class as such:


    I created a new version of the spark ApplicationSkin and modified the override:

    override protected function updateDisplayList(unscaledWidth:Number,
    unscaledHeight:Number) : void
    {
    bgRectFill.color = getStyle('backgroundColor');
    bgRectFill.alpha = getStyle('backgroundAlpha');
    super.updateDisplayList(unscaledWidth, unscaledHeight);
    }

    as well as the SolidColor fill:

    I also added the transparent wmode to swfObject embed to make sure my html bg was transparent:

    var flashvars = {};
    var params = {
    params:wmode = "transparent"
    };

    var attributes = {};

    var so = new SWFObject("src/drcFlex.swf", "drcFlex", "900", "250", "10", null, params, null);
    so.write("flowNav");

    And alas… I’ve got nothing – any ideas, see anything above that is incorrect, or different way to approach this????
    Hope my code tags work :-)
    BTW – was great to meet you last spring at FlashCamp Chicago!

    Doug
    follow me @dougrdotnet

  • http://dougr.net Doug

    Sweet!! I’ll write it up today and post back. Why I didn’t find that in my research, I have no idea.
    Ya, sorry about that – feel free to kill that waste of space 2nd post :D
    Should have known, My blog handles mxml the same way….And….I’m obviously too lazy to escape!!

    Thanks!

  • http://dougr.net Doug

    James,
    Ya K BalaSubramanian’s post was a better solution than my own – simpler. As it turns out my problem was actually in my configuration of SWFObject. After triple checking my js, I went over to http://www.bobbyvandersluis.com/swfobject/generator/index.html and used the SWFObject 2 HTML and JavaScript generator v1.2 – I was missing an the expressInstallSwfurl argument between version and flashvars arguments – swfobject.embedSWF(swfUrl, id, width, height, version, expressInstallSwfurl, flashvars, params, attributes, callbackFn).
    So, there you go – simple to add a transparent background on s:Application – just gotta pay attention to details :-)
    Thanks for the link!
    HTH someone else too!
    Doug

  • gowtham

    hi james ward,

    i need to create a simple but different flex video player???

    with following requirements:

    1.Application should display list of all videos.
    2. When user selects a video from the list, more details of the video should be displayed and user should be able to play the selected video.
    3. User should be able to Play, Pause and Stop the video selected.
    4. Display the time left and total time of video being played.
    5. Represent rating for videos using stars in the left hand side pane.
    6. Add seek bar to the video player.
    7. Allow users to tag a video. Tags should be displayed when the video is selected.
    8. User should be able to mark a video as a favorite. Status should be updated in the left panel.

    any help……….?
    if u have any model flex player mail u……………
    waiting for ur reply

  • gowtham

    thanks……………….

    i will check that link……………………………

  • http://flexdiary.blogspot.com Amy

    I’m getting some weird issues with button styles, and I was wondering if you could shed some light. It seems that any style starting with the string “show” is ignored (http://tech.groups.yahoo.com/group/flexcoders/message/161797), and also the spark button explicitly prevents you from using textAlign as a style on a button (http://tech.groups.yahoo.com/group/flexcoders/message/161798). Can you shed any light on how to get around these restrictions, and why on earth they are there in the first place?

    Thanks, and see you @ 360|Flex!

    • http://www.jamesward.com James Ward

      Looks like you got the “show” problem worked out. But the other problem AFAIK is just a FOL. :( Sorry. See you at 360!

      • http://www.taterboy.com Todd

        The amount of code it took to create a skin to style an existing component, this just seems backwards, I would love to write a few lines of css if it meant not having to create a new skin. In the case of the spark button component, it’s just not worth the effort, you can create a brand new custom button component with more styling ability in about the same amount of work. I know, I know, I’ll go add a feature request.

  • Sxd

    seem like spark button not have “style” property

  • raj roy

    thx bro…very helpful.

  • lionheart

    Hello. Thanks for this wonderful explanation about Flex styling.

    Hope you can help me with my problem. I need to dynamically check if a given style is defined on a given component. How will I do that?

    For example, if a we defined a “style1″ style for a given component, and I need to check like this pseudocode …. var style1Defined:Boolean = component has the property “style1″;

  • tarun

    change the thickness of the border of TextInput while displaying the error String

  • darren

    Hi. interesting post. I wish I could monkey patch the sdk used at work.
    It sounds like in the comments someone was saying you can’t extend an mxml class.
    I assume I am misreading, but in case I’m not, you definitely can.
    a component saved as “TemplateApplication.mxml”:

    
       
    

    can be used in an app named ‘MainApp.mxml” as such:

    
       
    

    And in this case TemplateApplication extends Application.

    The same can be done, obviously for any mxml component, from s:Button to s:SparkSkin. It’s the same syntax as the “Code-Behind” approach, but in this case the code is another mxml file, not an actionscript file.