【问题标题】:Passing a state to the child button of a Flex4 ButtonBar将状态传递给 Flex4 ButtonBar 的子按钮
【发布时间】:2011-04-16 05:28:22
【问题描述】:

我有一个具有自定义外观的 Spark ButtonBar,它为“middleButton”要求定义了一个自定义外观。我的 CustomButtonBarSkin 有一个自定义状态,minimized,我想将它传递到我的 middleButton 皮肤中,以便它可以修改其设计。

可以这样做吗?我可以看到我的按钮皮肤可以使用 parentDocument.currentState 来获得最小化状态,但这真的很难看。有什么方法可以将皮肤从栏传递到子按钮?

【问题讨论】:

    标签: apache-flex flex4 buttonbar flex-spark


    【解决方案1】:

    我认为你应该扩展默认的ButtonBar。像这样的:

    package
    {
    import mx.core.IFactory;
    
    import spark.components.ButtonBar;
    
    [SkinState("minimized")]
    [SkinState("minimizedDisabled")]
    public class MinimizableButtonBar extends ButtonBar
    {
        public function MinimizableButtonBar()
        {
            super();
    
            itemRendererFunction = defaultButtonBarItemRendererFunction;
        }
    
        [SkinPart(required="true", type="mx.core.IVisualElement")]
        public var middleButtonMinimized:IFactory;
    
        private var _minimized:Boolean;
    
        [Bindable]
        public function get minimized():Boolean
        {
            return _minimized;
        }
    
        public function set minimized(value:Boolean):void
        {
            if (_minimized == value)
                return;
    
            _minimized = value;
            invalidateSkinState();
            itemRendererFunction = defaultButtonBarItemRendererFunction;
        }
    
        override protected function getCurrentSkinState():String
        {
            if (_minimized)
                return enabled ? "minimized" : "minimizedDisabled";
            return super.getCurrentSkinState();
        }
    
        private function defaultButtonBarItemRendererFunction(data:Object):IFactory
        {
            var i:int = dataProvider.getItemIndex(data);
            if (i == 0)
                return firstButton ? firstButton : (_minimized ? middleButtonMinimized : middleButton);
    
            var n:int = dataProvider.length - 1;
            if (i == n)
                return lastButton ? lastButton : (_minimized ? middleButtonMinimized : middleButton);
    
            return (_minimized ? middleButtonMinimized : middleButton);
        }
    }
    }
    

    因此,使用此代码,您可以通过以下方式声明您的自定义皮肤:

    <?xml version="1.0" encoding="utf-8"?>
    <s:Skin alpha.disabledGroup="0.5" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark">
        <fx:Metadata>[HostComponent("MinimizableButtonBar")]</fx:Metadata>
    
        <s:states>
            <s:State name="normal" />
            <s:State name="disabled" stateGroups="disabledGroup" />
            <s:State name="minimized" stateGroups="minimizedGroup" />
            <s:State name="minimizedDisabled" stateGroups="disabledGroup,minimizedGroup" />
        </s:states>
    
        <fx:Declarations>
            <fx:Component id="firstButton">
                <s:ButtonBarButton skinClass="spark.skins.spark.ButtonBarFirstButtonSkin" />
            </fx:Component>
            <fx:Component id="middleButton">
                <s:ButtonBarButton skinClass="spark.skins.spark.ButtonBarMiddleButtonSkin" />
            </fx:Component>
            <fx:Component id="middleButtonMinimized">
                <s:ButtonBarButton skinClass="MinimazedButtonBarMiddleButtonSkin" />
            </fx:Component>
            <fx:Component id="lastButton">
                <s:ButtonBarButton skinClass="spark.skins.spark.ButtonBarLastButtonSkin" />
            </fx:Component>
        </fx:Declarations>
    
        <s:DataGroup height="100%" id="dataGroup" width="100%">
            <s:layout>
                <s:ButtonBarHorizontalLayout gap="-1" />
            </s:layout>
            <s:layout.minimizedGroup>
                <s:VerticalLayout />
            </s:layout.minimizedGroup>
        </s:DataGroup>
    </s:Skin>
    

    希望这能解决您的问题。

    如果您的最小化状态只是关于更改中间按钮外观,您可以从自定义组件和外观中删除所有与状态相关的代码。

    【讨论】:

    • 我已经有了ButtonBar的扩展来保持最小化状态,所以你这里的回答真的很符合我的想法。不过,我不知道项目渲染器函数覆盖,我认为这可以解决问题。有什么方法可以只声明一个 middleButton 并在其上切换皮肤,或者在该声明的皮肤上设置状态?
    • 如您所见,按钮表示为IFactory。所以似乎没有办法以声明方式设置状态。只有一个声明并为其切换皮肤怎么样?我想这可能与通常List 的项目渲染器中的方式相同。只要记住按钮皮肤是一个渲染器,ButtonBar 是一种列表。所以你可以改变一些数据提供者的字段值来通知渲染器切换另一个状态。
    • 这个解决方案有效,但是我不得不删除最小化的中间按钮的 SkinPart.required=true 属性,我不知道为什么。如果我将最小化按钮作为必需的 SkinPart,我会得到一个运行时异常,指出皮肤缺少必需的部分,即使它被声明得很好 - 我知道这是因为皮肤在没有 required=true 的情况下工作得很好,但是我仍然希望它是必需的部分。有什么想法吗?
    • 嗯。我的答案中包含的皮肤没有任何问题,并且无法意识到可能存在什么问题:(
    【解决方案2】:

    我最近正在处理按钮栏的皮肤,并希望扩展/删除一些默认行为。我没有扩展和覆盖或复制/粘贴 ButtonBar 代码,而是推出了我自己的简约组件:。

    public class HButtonBarGroup extends HGroup {
    
        public function HButtonBarGroup() {
            addEventListener(ElementExistenceEvent.ELEMENT_ADD, refreshSkins);
            super();
            gap = -1;
        }
    
        private function refreshSkins(event : * = null) : void {
            var buttonCount : int = numElements;
    
            for (var i : int = 0; i < buttonCount; i++) {
                var button : Button = getElementAt(i) as Button;
                var skinClass : Class
    
                if ((buttonCount == 0) || (buttonCount > 2 && (i != 0 && i != buttonCount)))
                    skinClass = GreyButtonBarMiddleButtonSkin;
                else if (i == 0)
                    skinClass = GreyButtonBarFirstButtonSkin;
                else
                    skinClass = GreyButtonBarLastButtonSkin;
    
                Button(getElementAt(i)).setStyle("skinClass", skinClass);
            }
        }
    }
    

    这将使您能够做任何您想做的事情,而不必在 ButtonBar、ButtonBarBase 和 ButtonBarSkin 周围踮脚——除非您想要切换按钮/选定索引,否则所有这些都是不必要的。 IMO 基于 dataProvider 创建按钮而不是仅仅在 MXML 中声明按钮并在那里分配处理程序和其他属性是很痛苦的。

    【讨论】:

    • 谢谢,凯文,这是一个很好的建议。如果 ButtonBar 扩展不能像我想要的那样工作,我会尝试像你在这里建议的那样。
    【解决方案3】:

    我最近需要根据其父状态更改组件的皮肤。我使用了与 HTML 相同的解决方案,使用 CSS。在您的情况下,类似于:

    s|ButtonBar:minimized s|ButtonBarButton {
        skinClass: ClassReference("CustomButtonBarSkin");
    }
    s|ButtonBarButton {
        skinClass: ClassReference("spark.skins.spark.ButtonBarMiddleButtonSkin");
    }
    

    :minimizedPseudo Selector(用于州)。

    不幸的是,除非我在状态更改时更改了父元素上的 styleName:

    <s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx"
        styleName.normal="foo" styleName.minimized="foo"
        >
    

    也许有一些无效方法我应该调用父母状态更改来让孩子接受更改,但只需将 styleName 更改为虚假的东西就可以了。

    这可能不是 Flex 中广泛使用的技术,因为 Flex 3 仅支持基本的 CSS 选择器。

    【讨论】:

      【解决方案4】:

      也许我没有完全理解您想要做的事情,但这对我来说似乎相当明显和容易。只需让您的自定义按钮栏皮肤在最小化状态处于活动状态时设置中间按钮的状态:

      <s:Skin>
      
      <s:states>
      <s:State name="minimized" />
      </s:states>
      
      <s:ButtonBarButton currentState.minimized="someState" />
      
      </s:Skin>
      

      明白了吗?

      【讨论】:

        猜你喜欢
        • 2019-03-08
        • 2019-10-27
        • 1970-01-01
        • 2019-01-20
        • 2022-01-18
        • 2020-05-18
        • 1970-01-01
        • 2018-08-25
        • 2021-11-12
        相关资源
        最近更新 更多