Setting a bitmap fill on a Spark Button control in Flex 4 (redux)

In a previous example, “Setting a bitmap fill on a Spark Button control in Flex 4”, we saw how you could apply a background bitmap fill on a Spark Button control in Flex 4 by creating a custom skin, using the BitmapFill class, and setting the skinClass style.

The following example shows how you can extend the Spark Button class and add a custom style for the background image fill instead of creating several different skins for each bitmap fill.

The following example(s) require Flash Player 10 and the Adobe Flex 4 SDK. To download the Adobe Flash Builder 4 trial, see www.adobe.com/products/flex/. To download the latest nightly build of the Flex 4 SDK, see opensource.adobe.com/wiki/display/flexsdk/Download+Flex+4.

For more information on getting started with Flex 4 and Flash Builder 4, see the official Adobe Flex Team blog.

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2010/04/29/setting-a-bitmap-fill-on-a-spark-button-control-in-flex-4-redux/ -->
<s:Application name="Spark_Button_skinClass_BitmapFill_test2"
        xmlns:fx="http://ns.adobe.com/mxml/2009"
        xmlns:s="library://ns.adobe.com/flex/spark"
        xmlns:mx="library://ns.adobe.com/flex/mx"
        xmlns:comps="comps.*">
    <s:layout>
        <s:VerticalLayout horizontalAlign="center" verticalAlign="middle" />
    </s:layout>
 
    <fx:Style>
        @namespace s "library://ns.adobe.com/flex/spark";
        @namespace mx "library://ns.adobe.com/flex/mx";
        @namespace comps "comps.*";
 
        comps|BitmapButton {
            fontWeight: bold;
            skinClass: ClassReference("skins.CustomSparkButtonSkin");
        }
    </fx:Style>
 
    <comps:BitmapButton id="btn1"
            label="Spark Button w/ BitmapFill"
            backgroundFill="@Embed('skins/pattern_143.gif')" />
 
    <comps:BitmapButton id="btn2"
            label="Spark Button w/ BitmapFill"
            backgroundFill="@Embed('skins/redbluebg.gif')" />
 
</s:Application>

The custom Spark Button subclass, comps/BitmapButton.as, with our custom style is as follows:

/** http://blog.flexexamples.com/2010/04/29/setting-a-bitmap-fill-on-a-spark-button-control-in-flex-4-redux/ */
package comps {
    import spark.components.Button;
 
    [Style(name="backgroundFill", type="Class")]
 
    public class IconButton extends Button {
        public function IconButton() {
            super();
        }
    }
}

And the custom BitmapButton skin, skins/CustomSparkButtonSkin.mxml, is as follows:

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2010/04/29/setting-a-bitmap-fill-on-a-spark-button-control-in-flex-4-redux/ -->
<s:SparkSkin name="CustomSparkButtonSkin"
             xmlns:fx="http://ns.adobe.com/mxml/2009"
             xmlns:s="library://ns.adobe.com/flex/spark"
             xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
             minWidth="21" minHeight="21"
             alpha.disabled="0.5">
    <!-- states -->
    <s:states>
        <s:State name="up" />
        <s:State name="over" />
        <s:State name="down" />
        <s:State name="disabled" />
    </s:states>
 
    <!-- host component -->
    <fx:Metadata>
        [HostComponent("spark.components.Button")]
    </fx:Metadata>
 
    <fx:Script fb:purpose="styling">
        <![CDATA[
            /* Define the skin elements that should not be colorized.
            For button, the graphics are colorized but the label is not. */
            static private const exclusions:Array = ["labelDisplay"];
 
            override public function get colorizeExclusions():Array {
                return exclusions;
            }
 
            override protected function initializationComplete():void {
                useChromeColor = true;
                super.initializationComplete();
            }
 
            override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number) : void {
                var cr:Number = getStyle("cornerRadius");
 
                if (cornerRadius != cr) {
                    cornerRadius = cr;
                    shadow.radiusX = cornerRadius;
                    fill.radiusX = cornerRadius;
                    border.radiusX = cornerRadius;
                }
 
                if (highlightStroke) {
                    highlightStroke.radiusX = cornerRadius;
                }
                if (hldownstroke1) {
                    hldownstroke1.radiusX = cornerRadius;
                }
                if (hldownstroke2) {
                    hldownstroke2.radiusX = cornerRadius;
                }
 
                bmpFill.source = getStyle("backgroundFill");
                super.updateDisplayList(unscaledWidth, unscaledHeight);
            }
 
            private var cornerRadius:Number = 2;
        ]]>
    </fx:Script>
 
    <!-- layer 1: shadow -->
    <s:Rect id="shadow" left="-1" right="-1" top="-1" bottom="-1" radiusX="2">
        <s:fill>
            <s:LinearGradient rotation="90">
                <s:GradientEntry color="0x000000" color.down="0xFFFFFF" alpha="0.01" alpha.down="0.0" />
                <s:GradientEntry color="0x000000" color.down="0xFFFFFF" alpha="0.07" alpha.down="0.5" />
            </s:LinearGradient>
        </s:fill>
    </s:Rect>
 
    <!-- layer 2: fill -->
    <s:Rect id="fill" left="1" right="1" top="1" bottom="1" radiusX="2">
        <s:fill>
            <s:BitmapFill id="bmpFill" fillMode="repeat" />
        </s:fill>
    </s:Rect>
 
    <!-- layer 5: highlight stroke (all states except down) -->
    <s:Rect id="highlightStroke" left="1" right="1" top="1" bottom="1" radiusX="2" excludeFrom="down">
        <s:stroke>
            <s:LinearGradientStroke rotation="90" weight="1">
                <s:GradientEntry color="0xFFFFFF" alpha.over="0.22" />
                <s:GradientEntry color="0xD8D8D8" alpha.over="0.22" />
            </s:LinearGradientStroke>
        </s:stroke>
    </s:Rect>
 
    <!-- layer 6: highlight stroke (down state only) -->
    <s:Rect id="hldownstroke1" left="1" right="1" top="1" bottom="1" radiusX="2" includeIn="down">
        <s:stroke>
            <s:LinearGradientStroke rotation="90" weight="1">
                <s:GradientEntry color="0x000000" alpha="0.25" ratio="0.0" />
                <s:GradientEntry color="0x000000" alpha="0.25" ratio="0.001" />
                <s:GradientEntry color="0x000000" alpha="0.07" ratio="0.0011" />
                <s:GradientEntry color="0x000000" alpha="0.07" ratio="0.965" />
                <s:GradientEntry color="0x000000" alpha="0.00" ratio="0.9651" />
            </s:LinearGradientStroke>
        </s:stroke>
    </s:Rect>
 
    <s:Rect id="hldownstroke2" left="2" right="2" top="2" bottom="2" radiusX="2" includeIn="down">
        <s:stroke>
            <s:LinearGradientStroke rotation="90" weight="1">
                <s:GradientEntry color="0x000000" alpha="0.09" ratio="0.0" />
                <s:GradientEntry color="0x000000" alpha="0.00" ratio="0.0001" />
            </s:LinearGradientStroke>
        </s:stroke>
    </s:Rect>
 
    <!-- layer 7: border - put on top of the fill so it doesn't disappear when scale is less than 1 -->
    <s:Rect id="border" left="0" right="0" top="0" bottom="0" width="69" height="20" radiusX="2">
        <s:stroke>
            <s:LinearGradientStroke rotation="90" weight="1">
                <s:GradientEntry color="0x000000" alpha="0.5625" alpha.down="0.6375" />
                <s:GradientEntry color="0x000000" alpha="0.75" alpha.down="0.85" />
            </s:LinearGradientStroke>
        </s:stroke>
    </s:Rect>
 
    <!-- layer 8: text -->
    <s:Label id="labelDisplay"
             textAlign="center"
             verticalAlign="middle"
             maxDisplayedLines="1"
             horizontalCenter="0" verticalCenter="1"
             left="10" right="10" top="2" bottom="2" />
 
</s:SparkSkin>

This entry is based on a beta version of the Flex 4 SDK and therefore is very likely to change as development of the Flex SDK continues. The API can (and will) change causing examples to possibly not compile in newer versions of the Flex 4 SDK.

2 thoughts on “Setting a bitmap fill on a Spark Button control in Flex 4 (redux)

  1. Another neat trick…
    If you don’t specify the backgroundFill style, the button fill is transparent.
    Since backgroundFill is a style, you can create a custom CSS selector and set the styleName property on several buttons to have them all use the same background fill (instead of using @Embed() in several places).

    <?xml version="1.0" encoding="utf-8"?>
    <s:Application name="Spark_Button_skinClass_BitmapFill_test"
            xmlns:fx="http://ns.adobe.com/mxml/2009"
            xmlns:s="library://ns.adobe.com/flex/spark"
            xmlns:mx="library://ns.adobe.com/flex/mx"
            xmlns:comps="comps.*"
            backgroundColor="red">
        <s:layout>
            <s:VerticalLayout horizontalAlign="center" verticalAlign="middle" />
        </s:layout>
     
        <fx:Style>
            @namespace s "library://ns.adobe.com/flex/spark";
            @namespace mx "library://ns.adobe.com/flex/mx";
            @namespace comps "comps.*";
     
            comps|IconButton {
                fontWeight: bold;
                skinClass: ClassReference("skins.CustomSparkButtonSkin");
            }
     
            .pattern143 {
                backgroundFill: Embed("skins/pattern_143.gif");
            }
        </fx:Style>
     
        <comps:IconButton id="btn1"
                label="Spark Button w/ BitmapFill"
                backgroundFill="@Embed('skins/pattern_143.gif')" />
     
        <comps:IconButton id="btn2"
                label="Spark Button w/ BitmapFill"
                backgroundFill="@Embed('skins/redbluebg.gif')" />
     
        <comps:IconButton id="btn3"
                label="Spark Button w/ BitmapFill" />
     
        <comps:IconButton id="btn4"
                label="Spark Button w/ BitmapFill"
                styleName="pattern143" />
     
        <comps:IconButton id="btn5"
                label="Spark Button w/ BitmapFill"
                styleName="pattern143" />
     
    </s:Application>

    Peter

  2. Thanks for this sample, just newbie on flex, it helped me!

    But I face an problem when the image is smaller than the button: the screen goes just entirely white. But you use the String parameter “repeat” that should be ok. I don’t see why “clip” would be better, and i don’t want a “scale”.

    Thank you guy!

Comments are closed.