开发者

ActionScript: Changing a spark TitleWindow's titlebar color

I have a simple doubt. I have made a custom ActionScript mxml component, which is a spark TitleWindow with a text area, which header (titlebar) should display a green background if it finds the word 'success' in its text, or red, if it doesn't.

My problem i开发者_开发知识库s that I don't know where to access and modify this property, and the only turnaround I've found is binding the 'chromeColor' of the TitleWindow to depend on a boolean that will change depending on whether I find or not the word 'success'. And this does change the TitleBar background to the color I desire, however, it also changes the scrollbar color, for example, which is a bit nasty. The code for my class is the following:

<?xml version="1.0" encoding="utf-8"?>
<s:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009" 
           xmlns:s="library://ns.adobe.com/flex/spark" 
           xmlns:mx="library://ns.adobe.com/flex/mx" width="400" 
           title="Output: "
           chromeColor="{success ? ( 0x00ff6b as uint) : ( 0xFF0000 as uint)}"
           close="closeHandler(event)">
<fx:Script>
    <![CDATA[
        import mx.events.CloseEvent;
        import mx.managers.PopUpManager;

        [Bindable]
        public var success:Boolean = false;

        public function setText(text:String):void
        {
            textContainer.text = text;
            if(text.indexOf("SUCCESS")!=-1)
            {
                success=true;
            }
        }

        protected function closeHandler(event:CloseEvent):void
        {
            PopUpManager.removePopUp(this);
        }

    ]]>
</fx:Script>
<s:TextArea id="textContainer" x="0" y="0"  width="100%" height="100%"
            paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10" 
            borderVisible="false" editable="false" fontFamily="Courier New"/>
</s:TitleWindow>

So, thanks for reading, and hope anyone knows the answer :)

Cheers, pepillo


I'd solve it with extending standard component and creating custom skin.

My version of component:

package
{
import flash.events.MouseEvent;

import mx.managers.PopUpManager;

import spark.components.TextArea;
import spark.components.TitleWindow;

[SkinState("disabledSuccessful")]
[SkinState("disabledWithControlBarSuccessful")]
[SkinState("inactiveSuccessful")]
[SkinState("inactiveWithControlBarSuccessful")]
[SkinState("normalSuccessful")]
[SkinState("normalWithControlBarSuccessful")]
public class SuccessfulTitleWindow extends TitleWindow
{
    public function SuccessfulTitleWindow()
    {
        title = "Output: ";
    }

    [SkinPart(required = "false")]
    public var textContainer:TextArea;

    private var success:Boolean;
    private var textChanged:Boolean;
    private var textValue:String;

    /**
     * @inheritDoc
     */
    override protected function commitProperties():void
    {
        super.commitProperties();

        if (textChanged && textContainer)
        {
            textContainer.text = textValue;
            textChanged = false;
        }
    }

    /**
     * @inheritDoc
     */
    override protected function getCurrentSkinState():String
    {
        var skinState:String = super.getCurrentSkinState();
        return success ? skinState + "Successful" : skinState;
    }

    /**
     * @inheritDoc
     */
    override protected function partAdded(partName:String, instance:Object):void
    {
        super.partAdded(partName, instance);
        if (instance == textContainer)
        {
            textChanged = true;
            invalidateProperties();
        }
    }

    public function setText(text:String):void
    {
        if (text == textValue)
            return;
        success = text && text.indexOf("SUCCESS") != -1;
        invalidateSkinState();
        textValue = text;
        textChanged = true;
        invalidateProperties();
    }

    /**
     * @inheritDoc
     */
    override protected function closeButton_clickHandler(event:MouseEvent):void
    {
        super.closeButton_clickHandler(event);

        PopUpManager.removePopUp(this);
    }
}
}

The skin (based on standard skin):

<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:fb="http://ns.adobe.com/flashbuilder/2009" blendMode="normal" mouseEnabled="false"
    minWidth="76" minHeight="76" alpha.disabledGroup="0.5" width="400">
    <fx:Metadata>[HostComponent("SuccessfulTitleWindow")]</fx:Metadata>

    <fx:Script fb:purpose="styling">
        /* Define the skin elements that should not be colorized. 
        For panel, border and title background are skinned, but the content area and title text are not. */
        static private const exclusions:Array = ["background", "titleDisplay", "contentGroup"];

        /**
         * @private
         */  
        override public function get colorizeExclusions():Array {return exclusions;}

        /**
         * @private
         */
        override protected function initializationComplete():void
        {
            useChromeColor = true;
            super.initializationComplete();
        }

        /**
         * @private
         */
        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            if (getStyle("borderVisible") == true)
            {
                border.visible = true;
                background.left = background.top = background.right = background.bottom = 1;
                contents.left = contents.top = contents.right = contents.bottom = 1;
            }
            else
            {
                border.visible = false;
                background.left = background.top = background.right = background.bottom = 0;
                contents.left = contents.top = contents.right = contents.bottom = 0;
            }

            dropShadow.visible = getStyle("dropShadowVisible");

            var cr:Number = getStyle("cornerRadius");
            var withControls:Boolean = 
                (currentState == "disabledWithControlBar" || 
                 currentState == "normalWithControlBar" ||
                 currentState == "inactiveWithControlBar");

            if (cornerRadius != cr)
            {
                cornerRadius = cr;

                dropShadow.tlRadius = cornerRadius;
                dropShadow.trRadius = cornerRadius;
                dropShadow.blRadius = withControls ? cornerRadius : 0;
                dropShadow.brRadius = withControls ? cornerRadius : 0;

                setPartCornerRadii(topMaskRect, withControls); 
                setPartCornerRadii(border, withControls); 
                setPartCornerRadii(background, withControls);
            }

            if (bottomMaskRect) setPartCornerRadii(bottomMaskRect, withControls); 

            borderStroke.color = getStyle("borderColor");
            borderStroke.alpha = getStyle("borderAlpha");
            backgroundFill.color = getStyle("backgroundColor");
            backgroundFill.alpha = getStyle("backgroundAlpha");

            super.updateDisplayList(unscaledWidth, unscaledHeight);
        }

        /**
         * @private
         */  
        private function setPartCornerRadii(target:Rect, includeBottom:Boolean):void
        {            
            target.topLeftRadiusX = cornerRadius;
            target.topRightRadiusX = cornerRadius;
            target.bottomLeftRadiusX = includeBottom ? cornerRadius : 0;
            target.bottomRightRadiusX = includeBottom ? cornerRadius : 0;
        }

        private var cornerRadius:Number;
    </fx:Script>

    <s:states>
        <s:State name="normal" stateGroups="normalGroup" />
        <s:State name="inactive" stateGroups="inactiveGroup" />
        <s:State name="disabled" stateGroups="disabledGroup" />
        <s:State name="normalWithControlBar" stateGroups="withControls, normalGroup" />
        <s:State name="inactiveWithControlBar" stateGroups="withControls, inactiveGroup" />
        <s:State name="disabledWithControlBar" stateGroups="withControls, disabledGroup" />
        <s:State name="normalSuccessful" stateGroups="successfulGroup, normalGroup" />
        <s:State name="inactiveSuccessful" stateGroups="inactiveGroup,successfulGroup" />
        <s:State name="disabledSuccessful" stateGroups="successfulGroup,disabledGroup" />
        <s:State name="normalWithControlBarSuccessful" stateGroups="withControls,successfulGroup,normalGroup" />
        <s:State name="inactiveWithControlBarSuccessful" stateGroups="withControls, inactiveGroup, successfulGroup" />
        <s:State name="disabledWithControlBarSuccessful" stateGroups="withControls, successfulGroup, disabledGroup" />
    </s:states>

    <!--- drop shadow can't be hittable so it stays sibling of other graphics @private-->
    <s:RectangularDropShadow id="dropShadow" blurX="20" blurY="20" alpha="0.32" 
                             alpha.inactiveGroup="0.22" distance="11"  distance.inactiveGroup="7"
                             angle="90" color="0x000000" left="0" top="0" right="0" bottom="0"/>

    <!--- drop shadow can't be hittable so all other graphics go in this group -->
    <s:Group left="0" right="0" top="0" bottom="0">

        <!--- top group mask @private-->
        <s:Group left="1" top="1" right="1" bottom="1" id="topGroupMask">
            <!--- @private-->
            <s:Rect id="topMaskRect" left="0" top="0" right="0" bottom="0">
                <s:fill>
                    <s:SolidColor alpha="0"/>
                </s:fill>
            </s:Rect>
        </s:Group>

        <!--- bottom group mask @private-->
        <s:Group left="1" top="1" right="1" bottom="1" id="bottomGroupMask" 
                 includeIn="withControls">
            <!--- @private-->
            <s:Rect id="bottomMaskRect" left="0" top="0" right="0" bottom="0">
                <s:fill>
                    <s:SolidColor alpha="0"/>
                </s:fill>
            </s:Rect>
        </s:Group>

        <!--- layer 1: border @private -->
        <s:Rect id="border" left="0" right="0" top="0" bottom="0" >
            <s:stroke>
                <!--- Defines the TitleWindowSkin class's border stroke. The default value is 1. -->
                <s:SolidColorStroke id="borderStroke" weight="1" />
            </s:stroke>
        </s:Rect>

        <!-- layer 2: background fill -->
        <!--- Defines the appearance of the TitleWindowSkin class's background. -->
        <s:Rect id="background" left="1" top="1" right="1" bottom="1">
            <s:fill>
                <!--- Defines the TitleWindowSkin class's background fill. The default color is 0xFFFFFF. -->
                <s:SolidColor id="backgroundFill" color="#FFFFFF"/>
            </s:fill>
        </s:Rect>

        <!-- layer 3: contents -->
        <!--- Contains the vertical stack of title bar content and control bar. -->
        <s:Group left="1" right="1" top="1" bottom="1" id="contents">
            <s:layout>
                <s:VerticalLayout gap="0" horizontalAlign="justify" />
            </s:layout>
            <!--- @private -->
            <s:Group id="topGroup" mask="{topGroupMask}">

                <!--- layer 0: title bar fill @private -->
                <s:Rect id="tbFill" left="0" right="0" top="0" bottom="1">
                    <s:fill>
                        <s:SolidColor color="0xFF0000" color.successfulGroup="0x00ff6b" alpha.inactiveGroup="0.8" />
                    </s:fill>
                </s:Rect>

                <!--- layer 1: title bar highlight @private -->
                <s:Rect id="tbHilite" left="0" right="0" top="0" bottom="0">
                    <s:stroke>
                        <s:LinearGradientStroke rotation="90" weight="1">
                            <s:GradientEntry color="0xE6E6E6" />
                            <s:GradientEntry color="0xFFFFFF" alpha="0.22"/>
                        </s:LinearGradientStroke>
                    </s:stroke>
                    <s:fill>
                        <s:LinearGradient rotation="90">
                            <s:GradientEntry color="0xFFFFFF" alpha="0.15" />
                            <s:GradientEntry color="0xFFFFFF" alpha="0.15" ratio="0.44"/>
                            <s:GradientEntry color="0xFFFFFF" alpha="0" ratio="0.4401"/>
                        </s:LinearGradient>
                    </s:fill>
                </s:Rect>

                <!--- layer 2: title bar divider @private -->
                <s:Rect id="tbDiv" left="0" right="0" height="1" bottom="0">
                    <s:fill>
                        <s:SolidColor color="0x000000" alpha="0.75" />
                    </s:fill>
                </s:Rect>

                <!-- layer 3: text -->
                <!--- @copy spark.components.Panel#titleDisplay -->
                <s:Label id="titleDisplay" maxDisplayedLines="1"
                         left="9" right="36" top="1" bottom="0" minHeight="30"
                         verticalAlign="middle" fontWeight="bold" />

                <!-- layer 4: moveArea -->
                <!--- @copy spark.components.TitleWindow#moveArea -->
                <s:Group id="moveArea" left="0" right="0" top="0" bottom="0" />

                <!--- @copy spark.components.TitleWindow#closeButton -->
                <s:Button id="closeButton" skinClass="spark.skins.spark.TitleWindowCloseButtonSkin"
                          width="15" height="15" right="7" top="7" />
            </s:Group>

            <!--
                Note: setting the minimum size to 0 here so that changes to the host component's
                size will not be thwarted by this skin part's minimum size.   This is a compromise,
                more about it here: http://bugs.adobe.com/jira/browse/SDK-21143
            -->
            <!--- @copy spark.components.SkinnableContainer#contentGroup -->
            <s:Group id="contentGroup" width="100%" height="100%" minWidth="0" minHeight="0">
                <s:TextArea id="textContainer" width="100%" height="100%"
                    paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10" 
                    borderVisible="false" editable="false" fontFamily="Courier New"/>
            </s:Group>

            <!--- @private -->
            <s:Group id="bottomGroup" minWidth="0" minHeight="0" 
                     includeIn="withControls">  

                <s:Group left="0" right="0" top="0" bottom="0" mask="{bottomGroupMask}">

                    <!-- layer 0: control bar divider line -->
                    <s:Rect left="0" right="0" top="0" height="1" alpha="0.22">
                        <s:fill>
                            <s:SolidColor color="0x000000" />
                        </s:fill>
                    </s:Rect>

                    <!-- layer 1: control bar highlight -->
                    <s:Rect left="0" right="0" top="1" bottom="0">
                        <s:stroke>
                            <s:LinearGradientStroke rotation="90" weight="1">
                                <s:GradientEntry color="0xFFFFFF" />
                                <s:GradientEntry color="0xD8D8D8" />
                            </s:LinearGradientStroke>
                        </s:stroke>
                    </s:Rect>

                    <!-- layer 2: control bar fill -->
                    <s:Rect left="1" right="1" top="2" bottom="1">
                        <s:fill>
                            <s:LinearGradient rotation="90">
                                <s:GradientEntry color="0xEDEDED"/>
                                <s:GradientEntry color="0xCDCDCD"/>
                            </s:LinearGradient>
                        </s:fill>
                    </s:Rect>
                </s:Group>

                <!--- @copy spark.components.Panel#controlBarGroup -->
                <s:Group id="controlBarGroup" left="0" right="0" top="1" bottom="1" minWidth="0" minHeight="0">
                    <s:layout>
                        <s:HorizontalLayout paddingLeft="10" paddingRight="10" paddingTop="7" paddingBottom="7" gap="10" />
                    </s:layout>
                </s:Group>
            </s:Group>
        </s:Group>
    </s:Group>
</s:SparkSkin>

And the simple app to test:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:local="*">
    <s:VGroup verticalCenter="0" horizontalCenter="0">
        <local:SuccessfulTitleWindow skinClass="SuccessfulTitleWindowSkin" id="window" />
        <s:TextInput change="window.setText(event.currentTarget.text)" />
    </s:VGroup>
</s:Application>


The Flex 4 Way to do this, would be to create your own custom skin class by copying the code of TitleWindowSkin and to update this to have a green background. You would then tell felx to use your custom skin by adding a skinClass attribute to the TitleWindow tag or by setting the skinClass in a CSS configuration.


If using FlashBuilder, create a new MXML Skin derived from the skin type you want to override (good to use a package named skins). Then create a new ActionScript class and extend the MXML skin. You will then have full control over the skin, and be able to extend the template if necessary.

ActionScript: Changing a spark TitleWindow's titlebar color

In my case I wanted to override the skin of a TitleWindow [spark.skins.spark.TitleWindowSkin] (even on a mobile device). Many of the Dialog items (i.e. titlebar) are not skinnable but hard coded. tbFill is the ID of the TitleBar. I was able to adjust the Skin code to assign ID property names to the title bar gradient and read Style values to set the colors [in the updateDisplayList function]. Then use the name of your custom skin class as the skinClass property of the item you are skinning.

skinClass="skins.defaultSkin"

Overall it's not that difficult to do, using this method. Here is the skin class.

package skins
{
    
    public class defaultSkin extends dlgTitleWindowSkin 
    {
        public function defaultSkin()
        {
            super();
            this.setStyle("backgroundColor","#fff2bd");
            this.setStyle("tbFill_GradientStart","#ff5f3b");
            this.setStyle("tbFill_GradientEnd","#ff5f3b ");
        }
    }
}

In the derived MXML Skin:

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
...
            tbFill_GradientStart.color = getStyle("tbFill_GradientStart");
            tbFill_GradientEnd.color = getStyle("tbFill_GradientEnd");
            
            super.updateDisplayList(unscaledWidth, unscaledHeight);
}
...
    <!--- layer 0: title bar fill @private -->
    <s:Rect id="tbFill" left="0" right="0" top="0" bottom="1">
        <s:fill>
            <s:LinearGradient rotation="90">
                <s:GradientEntry id="tbFill_GradientStart" color="0xD2D2D2"
                                 color.inactiveGroup="0xEAEAEA"/>
                <s:GradientEntry id="tbFill_GradientEnd" color="0x9A9A9A"
                                 color.inactiveGroup="0xCECECE"/>
            </s:LinearGradient>
        </s:fill>
    </s:Rect>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜