Creating a justified multiline Spark Button control in Flex 4

The following example shows how you can create a multiline, justified label on Spark Button control in Flex 4 by creating a custom skin and setting the textAlign style and removing the maxDisplayedLines property.

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/03/09/creating-a-justified-multiline-spark-button-control-in-flex-4/ -->
<s:Application name="Spark_Button_skinClass_textAlign_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">
 
    <s:Button id="btn"
            label="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent sed nisi libero, id semper leo. Vivamus tempus massa nec sapien vehicula pharetra. Nullam ipsum tellus, tempus placerat euismod ut, pharetra eu velit. Suspendisse iaculis placerat metus, a facilisis libero ultricies id. Pellentesque eget lorem a diam tempus fringilla vitae fermentum purus.{'\n'}Vivamus condimentum euismod est, sit amet fermentum justo pretium quis. Donec pretium commodo augue varius imperdiet. Morbi facilisis mollis est, id cursus turpis sagittis a. Fusce nec dolor quis mi interdum congue a sit amet elit. Quisque auctor ornare imperdiet. Suspendisse velit purus, tincidunt at pellentesque vitae, malesuada sit amet ligula. Integer varius justo sit amet augue accumsan non tempor purus gravida."
            skinClass="skins.WrapButtonSkin"
            width="400"
            horizontalCenter="0" verticalCenter="0" />
 
</s:Application>

[GoogleAdsWide]

View source is enabled in the following example.

And the custom Spark Button skin, skins/WrapButtonSkin.mxml, is as follows:

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2010/03/09/creating-a-justified-multiline-spark-button-control-in-flex-4/ -->
<s:SparkSkin name="WrapButtonSkin"
        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;
                    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:Label id="labelDisplay"
            textAlign="justify"
            verticalAlign="middle"
            horizontalCenter="0" verticalCenter="1"
            left="10" right="10" top="10" bottom="10" />
 
</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.

4 thoughts on “Creating a justified multiline Spark Button control in Flex 4

  1. Wouldn’t it be better to extend spark ButtonSkin and do only that?

    override protected function childrenCreated():void {
    (labelDisplay as Label).maxDisplayedLines = 0;
    super.childrenCreated();
    }

    I know that copying a skin is thought as a best pracitice but sometimes the changes aren’t that much, especially changing some minor params.

    Thanks,
    Mike

Comments are closed.