Setting a rich text label on a Spark Button control in Flex 4

The following example shows how you can set a rich, multi-format text label on a Spark Button control by subclassing the Spark Button control and creating a custom Button skin which uses a RichText label display skin part.

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/10/22/setting-a-rich-text-label-on-a-spark-button-control-in-flex-4/ -->
<s:Application name="Spark_Button_textFlow_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.*">
 
    <fx:Style>
        @namespace comps "comps.*";
 
        comps|RichButton {
            skinClass: ClassReference("skins.RichButtonSkin");
        }
    </fx:Style>
 
    <comps:RichButton horizontalCenter="0" verticalCenter="0">
        <comps:textFlow>
            <s:TextFlow>
                <s:p fontStyle="italic">The quick<s:br/>brown fox <s:span fontWeight="bold">jumps<s:br/>over the</s:span> lazy <s:span color="#FF0000" fontStyle="normal">dog</s:span>.</s:p>
                <s:p>And then some more stuff.</s:p>
            </s:TextFlow>
        </comps:textFlow>
    </comps:RichButton>
 
</s:Application>

The custom Spark Button control, comps/RichButton.as, is as follows:

/** http://blog.flexexamples.com/2010/10/22/setting-a-rich-text-label-on-a-spark-button-control-in-flex-4/ */
package comps {
    import flashx.textLayout.elements.TextFlow;
    import spark.components.Button;
 
    public class RichButton extends Button {
        public function RichButton() {
            super();
        }
 
        [Bindable]
        public var textFlow:TextFlow;
    }
}

And the custom RichButton skin, skins/RichButtonSkin.mxml, is as follows:

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2010/10/22/setting-a-rich-text-label-on-a-spark-button-control-in-flex-4/ -->
<s:SparkSkin name="RichButtonSkin"
        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>
 
    <fx:Metadata>
        [HostComponent("comps.RichButton")]
    </fx:Metadata>
 
    <fx:Script fb:purpose="styling">
        <![CDATA[
            import spark.components.Group;
 
            /* 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;
                    lowlight.radiusX = cornerRadius;
                    highlight.radiusX = cornerRadius;
                    border.radiusX = cornerRadius;
                }
 
                if (highlightStroke) highlightStroke.radiusX = cornerRadius;
                if (hldownstroke1) hldownstroke1.radiusX = cornerRadius;
                if (hldownstroke2) hldownstroke2.radiusX = cornerRadius;
 
                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" />
                <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:LinearGradient rotation="90">
                <s:GradientEntry color="0xFFFFFF" color.over="0xBBBDBD" color.down="0xAAAAAA" alpha="0.85" />
                <s:GradientEntry color="0xD8D8D8" color.over="0x9FA0A1" color.down="0x929496" alpha="0.85" />
            </s:LinearGradient>
        </s:fill>
    </s:Rect>
 
    <!-- layer 3: fill lowlight -->
    <s:Rect id="lowlight" left="1" right="1" top="1" bottom="1" radiusX="2">
        <s:fill>
            <s:LinearGradient rotation="270">
                <s:GradientEntry color="0x000000" ratio="0.0" alpha="0.0627" />
                <s:GradientEntry color="0x000000" ratio="0.48" alpha="0.0099" />
                <s:GradientEntry color="0x000000" ratio="0.48001" alpha="0" />
            </s:LinearGradient>
        </s:fill>
    </s:Rect>
 
    <!-- layer 4: fill highlight -->
    <s:Rect id="highlight" left="1" right="1" top="1" bottom="1" radiusX="2">
        <s:fill>
            <s:LinearGradient rotation="90">
                <s:GradientEntry color="0xFFFFFF" ratio="0.0" alpha="0.33" alpha.over="0.22" alpha.down="0.12"/>
                <s:GradientEntry color="0xFFFFFF" ratio="0.48" alpha="0.33" alpha.over="0.22" alpha.down="0.12" />
                <s:GradientEntry color="0xFFFFFF" ratio="0.48001" alpha="0" />
            </s:LinearGradient>
        </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:RichText id="rt"
            textFlow="{hostComponent.textFlow}"
            textAlign="center"
            verticalAlign="middle"
            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.

One thought on “Setting a rich text label on a Spark Button control in Flex 4

  1. That’s very helpful example.
    With your example try to set the underline on first character of label.

    {hostComponent.label.substring(0,1)}{hostComponent.label.substring(1)}

    But when i apply this skin on my custom skin button. the icon is not set and tool tip when the width is reduce is not showing.

Comments are closed.