Передача состояния дочерней кнопке Flex4 ButtonBar

У меня есть Spark ButtonBar с пользовательским скином, который определяет пользовательский скин для требования «middleButton». Мой CustomButtonBarSkin имеет настраиваемое состояние, свернутое, которое я хочу передать в свой скин middleButton, чтобы он мог изменять свой дизайн.

Можно ли сделать это? Я вижу, что мой скин кнопки может использовать parentDocument.currentState для получения свернутого состояния, но это действительно уродливо. Есть ли способ передать скин с панели на дочерние кнопки?


person Michael    schedule 16.04.2011    source источник


Ответы (4)


Я думаю, вам следует расширить значение по умолчанию 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>

Надеюсь, это решит вашу проблему.

И если ваше свернутое состояние связано только с изменением скина средней кнопки, вы можете удалить весь код, связанный с состояниями, как из пользовательского компонента, так и из скина.

person Constantiner    schedule 16.04.2011
comment
У меня уже есть расширение ButtonBar для поддержания свернутого состояния, поэтому ваш ответ здесь действительно соответствует тому, что я думал. Однако я не знал о переопределении функции рендеринга элементов, и я думаю, что это поможет. Есть ли способ иметь только одно объявление middleButton и переключить скин на него или установить состояние на скин этого объявления? - person Michael; 16.04.2011
comment
Как видите, кнопки представлены как IFactory. Таким образом, кажется, что нет способа декларативно установить состояния. Что касается наличия только одного объявления и переключения скина для него, я думаю, это возможно так же, как и в рендерах предметов для обычных List. Просто помните, что скин кнопки — это рендерер, а ButtonBar — это своего рода список. Таким образом, вы можете изменить значение поля некоторого поставщика данных, чтобы сообщить средству визуализации о переключении другого состояния. - person Constantiner; 16.04.2011
comment
Это решение работает, однако мне пришлось удалить свойство SkinPart.required=true свернутой средней кнопки, и я не знаю, почему. Если у меня есть свернутая кнопка в качестве требуемой SkinPart, я получаю исключение во время выполнения, указывающее, что в скине отсутствует требуемая часть, даже если она объявлена ​​просто отличной - я знаю это, потому что скин работает нормально без required=true, но я все еще хотел бы, чтобы это была обязательная часть. Любые идеи по этому поводу? - person Michael; 17.04.2011
comment
Хм. У меня нет проблем с кожей, включенной в мой ответ, и я не могу понять, в чем может быть проблема :( - person Constantiner; 17.04.2011

Недавно я работал над созданием скинов на панели кнопок и хотел расширить/удалить некоторые элементы поведения по умолчанию. Вместо того, чтобы расширять и перезаписывать или копировать/вставлять код 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 - все это не нужно, если вы не хотите togglebutton/selectedIndex. IMO, создавать кнопки на основе dataProvider довольно сложно, вместо того, чтобы просто объявлять кнопки в MXML и назначать там обработчики и другие свойства.

person Kevin Gallahan    schedule 16.04.2011
comment
Спасибо, Кевин, это отличное предложение. Если расширение ButtonBar не работает так, как я хочу, я попробую что-то вроде того, что вы предложили здесь. - person Michael; 16.04.2011

Недавно мне нужно было изменить скин компонента в зависимости от состояния его родителей. Я использовал то же решение, что и в HTML, используя CSS. В вашем случае что-то вроде:

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

:свернуто — это Псевдоселектор (для штатов).

К сожалению, это, похоже, не было обнаружено дочерним элементом (ошибка?), Если только я не изменил 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"
    >

Может быть, есть какой-то недействительный метод, который я должен был вызвать при изменении состояния родителей, чтобы ребенок принял это изменение, но просто изменил имя стиля на что-то фиктивное.

Возможно, это не очень широко используемый метод во Flex из-за того, что Flex 3 поддерживал только базовые селекторы CSS.

person rlovtang    schedule 16.04.2011

Может быть, я не совсем понимаю, что вы пытаетесь сделать, но мне это кажется довольно очевидным и простым. Просто настройте скин панели кнопок, чтобы установить состояние средней кнопки, когда свернутое состояние активно:

<s:Skin>

<s:states>
<s:State name="minimized" />
</s:states>

<s:ButtonBarButton currentState.minimized="someState" />

</s:Skin>

Возьми?

person J_A_X    schedule 16.04.2011