1

我有带皮肤的 Spark TextInput。这个皮肤有 3 种状态,需要能够根据监听的事件改变状态。

TextInput 的持有者是一个面板,当用户点击某个地方时,它会发送一个事件。

我不知道如何听这样的事件。

面板中的 textInput:

<s:TextInput id="nombre" x="10" y="23" width="264" borderVisible="false"
                 chromeColor="#791111" color="#741111" contentBackgroundColor="#ECECEC"
                 focusColor="#6E1212" fontWeight="bold" 
                 skinClass="skins.NormalInputText"
                 text="@{clientesModel.datosCliente.nombre}"/>

和皮肤 NormalInputText:

<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" 
alpha.disabledStates="0.5" blendMode="normal" currentState="normal"
creationComplete="init()">

<fx:Metadata>
<![CDATA[ 
    /** 
     * @copy spark.skins.spark.ApplicationSkin#hostComponent
     */
    [HostComponent("spark.components.TextInput")]
]]>
</fx:Metadata> 

<fx:Script fb:purpose="styling">
    <![CDATA[
        import mx.core.FlexVersion;


    private var paddingChanged:Boolean;


    /* Define the skin elements that should not be colorized. */
    static private const exclusions:Array = ["background", "textDisplay", "promptDisplay", "border"];

    /* exclusions before Flex 4.5 for backwards-compatibility purposes */
    static private const exclusions_4_0:Array = ["background", "textDisplay", "promptDisplay"];

    public function init():void {
        parent.addEventListener('panel_mode_edit',  editMode);
        parent.addEventListener('panel_mode_query', queryMode);
        parent.addEventListener('panel_mode_new',   newMode);
    }
    private function editMode(evt:Event):void {
        this.currentState = 'editing';
    }
    private function queryMode(evt:Event):void {
        this.currentState = 'normal';
    }
    private function newMode(evt:Event):void {
        this.currentState = 'adding';
    }

    override public function get colorizeExclusions():Array {
        // Since border is styleable via borderColor, no need to allow chromeColor to affect
        // the border.  This is wrapped in a compatibility flag since this change was added  
        // in Flex 4.5
        if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_4_5)
        {
            return exclusions_4_0;
        }

        return exclusions;
    }

    /* Define the content fill items that should be colored by the "contentBackgroundColor" style. */
    static private const contentFill:Array = ["bgFill"];

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

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

        if (paddingChanged)
        {
            updatePadding();
            paddingChanged = false;
        }
    }

    /**
     * @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;
            shadow.visible = true;
            background.left = background.top = background.right = background.bottom = 1;
            textDisplay.left = textDisplay.top = textDisplay.right = textDisplay.bottom = 1;
            if (promptDisplay)
            {
                promptDisplay.setLayoutBoundsSize(unscaledWidth - 2, unscaledHeight - 2);
                promptDisplay.setLayoutBoundsPosition(1, 1);
            }
        }
        else
        {
            border.visible = false;
            shadow.visible = false;
            background.left = background.top = background.right = background.bottom = 0;
            textDisplay.left = textDisplay.top = textDisplay.right = textDisplay.bottom = 0;
            if (promptDisplay)
            {
                promptDisplay.setLayoutBoundsSize(unscaledWidth, unscaledHeight);
                promptDisplay.setLayoutBoundsPosition(0, 0);
            }
        }

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

        super.updateDisplayList(unscaledWidth, unscaledHeight);
    }

    /**
     *  @private
     */
    private function updatePadding():void
    {
        if (!textDisplay)
            return;

        // Push padding styles into the textDisplay
        var padding:Number;

        padding = getStyle("paddingLeft");
        if (textDisplay.getStyle("paddingLeft") != padding)
            textDisplay.setStyle("paddingLeft", padding);

        padding = getStyle("paddingTop");
        if (textDisplay.getStyle("paddingTop") != padding)
            textDisplay.setStyle("paddingTop", padding);

        padding = getStyle("paddingRight");
        if (textDisplay.getStyle("paddingRight") != padding)
            textDisplay.setStyle("paddingRight", padding);

        padding = getStyle("paddingBottom");
        if (textDisplay.getStyle("paddingBottom") != padding)
            textDisplay.setStyle("paddingBottom", padding);

        if (!promptDisplay)
            return;

        padding = getStyle("paddingLeft");
        if (promptDisplay.getStyle("paddingLeft") != padding)
            promptDisplay.setStyle("paddingLeft", padding);

        padding = getStyle("paddingTop");
        if (promptDisplay.getStyle("paddingTop") != padding)
            promptDisplay.setStyle("paddingTop", padding);

        padding = getStyle("paddingRight");
        if (promptDisplay.getStyle("paddingRight") != padding)
            promptDisplay.setStyle("paddingRight", padding);

        padding = getStyle("paddingBottom");
        if (promptDisplay.getStyle("paddingBottom") != padding)
            promptDisplay.setStyle("paddingBottom", padding);
    }

    /**
     *  @private
     */
    override public function styleChanged(styleProp:String):void
    {
        var allStyles:Boolean = !styleProp || styleProp == "styleName";

        super.styleChanged(styleProp);

        if (allStyles || styleProp.indexOf("padding") == 0)
        {
            paddingChanged = true;
            invalidateProperties();
        }
    }
    ]]>
</fx:Script>

<fx:Script>
    <![CDATA[
    /** 
     * @private 
     */     
    private static const focusExclusions:Array = ["textDisplay"];

    /**
     *  @private
     */
    override public function get focusSkinExclusions():Array { return focusExclusions;};
    ]]>
</fx:Script>

<s:states>
    <s:State name="normal"/>
    <s:State name="editing" />
    <s:State name="adding" />
    <s:State name="disabled" stateGroups="disabledStates"/>
    <s:State name="normalWithPrompt"/>
    <s:State name="disabledWithPrompt" stateGroups="disabledStates"/>
</s:states>

<!-- border --> 
<!--- @private -->
<s:Rect left="0" right="0" top="0" bottom="0" id="border">
    <s:stroke>     
        <!--- @private -->
        <s:SolidColorStroke id="borderStroke" weight="0" />
    </s:stroke>
</s:Rect>

<!-- fill -->
<!--- Defines the appearance of the TextInput component's background. -->
<s:Rect id="background" left="1" right="1" top="1" bottom="1">
    <s:fill>
        <!--- @private Defines the background fill color. -->
        <s:SolidColor id="bgFill" color="#ebebeb" />
    </s:fill>
</s:Rect>

<!-- shadow -->
<!--- @private -->
<s:Rect left="1" top="1" right="1" height="1" id="shadow">
    <s:fill>
        <s:SolidColor color="0x000000" alpha="0.12" />
    </s:fill>
</s:Rect>

<!-- text -->
<!--- @copy spark.components.supportClasses.SkinnableTextBase#textDisplay -->
<s:RichEditableText id="textDisplay"
          verticalAlign="middle"
          widthInChars="10"
          color.normal="#999999"
          color.editing="#29ABE2"
          color.adding="#D67A1E"
          left="1" right="1" top="1" bottom="1" />
<!--- Defines the Label that is used for prompt text. The includeInLayout property is false so the prompt text does not affect measurement. -->
<s:Label id="promptDisplay" maxDisplayedLines="1"
            verticalAlign="middle"
            mouseEnabled="false" mouseChildren="false"
            includeIn="normalWithPrompt,disabledWithPrompt" 
            includeInLayout="false"
            color.normal="#999999"
            color.editing="#29ABE2"
            color.adding="#D67A1E"
            />

我使用 parent.addEventListener('panel_mode_edit', editMode); 用于收听事件,但它不起作用。

怎么了?

更新

发送事件:

panelClientes.dispatchEvent(new Event("panel_mode_query", true, true));

在 TextInput 外观中:

    public function init():void {
        hostComponent.addEventListener('panel_mode_edit',   editMode);
        hostComponent.addEventListener('panel_mode_query', queryMode);
        hostComponent.addEventListener('panel_mode_new',    newMode);
    }
    private function editMode(evt:Event):void {
        this.currentState = 'editing';
    }
    private function queryMode(evt:Event):void {
        this.currentState = 'normal';
    }
    private function newMode(evt:Event):void {
        this.currentState = 'adding';
    }
4

1 回答 1

2

首先,除了逻辑检查(主要是检查父项是否不存在),您不应该以任何方式收听或访问父parent在 OOP 语言中,您永远不想处理对象链;你总是想减少它。这既是正确的方法,也是防止错误的好方法。

现在,针对实际问题。皮肤不是它被应用到的对象。它不是该对象的一部分。两人的关系非常非常松散。您不能直接从主机访问皮肤,但您可以直接从皮肤访问主机。

您可以使用 访问皮肤附加到的组件hostComponent。现在,正如我上面所说,你不想做hostComponent.parent. 一方面,在将对象添加到父对象之前附加了皮肤(除非您之后在 AS3 中手动添加它,我怀疑您正在这样做并且无论如何都是一个坏主意)。相反,你想这样做:

  1. 在该父对象中侦听您的事件(我相信面板)
  2. 在该事件侦听器的处理程序中,您可以执行以下三件事之一:
    1. 在您监听皮肤变化的子对象中设置一个可绑定变量。这可以通过fx:definitions数组和皮肤中的 MXML 轻松完成,您可以在 MXML(使用{hostComponent.bindableVariableName})中或通过监听PropertyChangeEvent.PROPERTY_CHANGEhostComponent 上的事件来监听该更改。
    2. 调用一个完全设置不同皮肤的方法。它会不那么紧凑,但在抽象方面会更好,因为每个皮肤都会被归入单独的类。但是,如果在移动设备或速度较慢的桌面上,在对象出现在舞台上之后设置皮肤可能会很慢。
    3. 在子对象中调用一个方法,该方法调度您在皮肤中侦听的某种事件。这就是我个人过去的做法。它干净、OOP 友好,并且与其他 2 个选项一样快或更快。

与皮肤交流是 Flex 的一大痛点。这是一个有意的设计,但有时它是需要的。以正确的方式进行操作对于创建高效的应用程序至关重要。

于 2013-08-11T03:54:21.643 回答