apache-flexfxg

A template for button skins using FXG graphics?


The UI in my app uses a lot of buttons that are mostly the same minus the FXG graphics used in their skins. Their skins look something like this

<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:s="library://ns.adobe.com/flex/spark" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt" xmlns:flm="http://ns.adobe.com/flame/2008" xmlns:graphics="assets.graphics.*" xmlns:ATE="http://ns.adobe.com/ate/2009">
    <fx:Metadata>[HostComponent("spark.components.Button")]</fx:Metadata>
    <s:states>
        <s:State name="up"/>
        <s:State name="over"/>
        <s:State name="down"/>
        <s:State name="disabled"/>
    </s:states>
    <graphics:RectangleGraphic bottom="0"/> 
    <graphics:ButtonTextGraphic alpha.disabled="0.45" x="22" y="6"/>
    <graphics:ButtonSymbolGraphic alpha.disabled="0.45" x="4" y="4">
        <graphics:filters>
            <s:GlowFilter includeIn="over, down" blurX="3" blurY="3" inner="false" color="#3F5F93" strength="2" alpha="1.0" quality="2" knockout="false"/>
            <s:GlowFilter includeIn="down" blurX="3" blurY="3" inner="false" color="0x5380d0" strength="2" alpha="1.0" quality="2" knockout="false"/>
        </graphics:filters>
    </graphics:ButtonSymbolGraphic>
    <graphics:SmallButtonLineSeparatorGraphic bottom="-0.5"/>
</s:Skin>

where RectangleGraphic and SmallButtonLineSeparatorGraphic are FXGs that are used across all buttons, and ButtonTextGraphic and ButtonSymbolGraphic are FXGs that are specific to each button. I would love to have a single template skin that is fed the two FXGs specific to each button, but I'm not sure how to best do that.


Solution

  • You'll have to do some ActionScript magic to make it work. Probably Leave RectangleGraphic and SmallButtonLineSeparatorGraphic as they are in MXML. Create variables for ButtonTextGraphic and ButtonSymbolGraphic. I'll just demonstrate using ButtonTextGraphic a sample. Something like this:

    public var buttonTextGraphicClass : Class;
    

    Also have variables for the class instance:

    public var buttonTextGraphic : Class;
    

    In the constructor, you can set the class values. Or if you're stuck w/ MXML, then use a preinitialize event handler:

    buttonTextGraphicClass = ButtonTextGraphic;
    

    in createChildren create the instances and add them:

    protected function override createChildren():void{
     super.createChildren();
     buttonTextGraphic = new buttonTextGraphicClass()
     // set other properties
     addElement(buttonTextGraphicClass);
    }
    

    Finally, in updateDisplayList() size and position them elements, something like this:

    buttonTextGraphic.x = 22
    buttonTextGraphic.y = 6
    buttonTextGraphic.width = unscaledWidth // or some other value
    buttonTextGraphic.height = unscaledHeight // or some value
    

    This way you can use the same exactly skin; just replacing the class instances for your changing FXG assets at runtime.

    I suggest reading up on the Flex Component LifeCycle. If you have Z-Order issues; you may have to switch to creating all the skin's children in ActionScript; or possibly use the "addElementAt" method.

    To accommodate for different states in the ActionScript code, you'll have to override the set currentState method to manually make our state changes, such as changing your glow or changing the alpha.

    Pretty much everything I describe here is the approach to creating ActionScript skins. You may benefit from looking at some of the existing Flex 4.5 Mobile Skins. I'd start with the Mobile ButtonSkin. I think the border is an FXG Asset; which is implemented using a similar approach to what I describe here.