пятница, февраля 06, 2009

Неэффектные эффекты. Flex

Просто хотел сделать выезжающую/убирающуюся панельку, активирующуюся при наведении мышки на некий контейнер. И сделать это чисто средствами Flex.

По началу, сделал просто появляющуюся/исчезающую панель, используя ее свойства showEffect/hideEffect. По событию наведения мыши делал visible=true, при отведении - наоборот. Эффекты:
<mx:Fade id="PanelFadeIn" alphaFrom="0" alphaTo="1" duration="400"/>
<mx:Fade id="PanelFadeOut" alphaFrom="1" alphaTo="0" duration="400" startDelay="1000"/>

Полная фигня получилась. Эффекты конфликтовали и панель появлялась и исчезала непредсказуемым образом.
Чтобы образумить эффекты, пришлось их останавливать (stop()) перед тем как переключать visible. Так более-менее заработало.

Попробовал другой способ - есть два стэйта, в которых панель находится в разных положениях. При наведении на контейнер мыши, стейт сменяется и панель перемещается в другое место, при отведении - возвращается на прежнее.
Сначала применил свойство moveEffect, в которое указывается имя эффекта <mx:Move id="PanelMotion" /> Получаю опять ерунду. В начале вроде бы всё корректно - уезжает, приезжает, но после нескольких таких движений, что-то там начинает заедать. Метод не годится.

Применяем другую тактику - используем transitions. Сразу всё встает на свои места:
<mx:transitions>
<mx:Transition fromState="Normal" toState="PanelIsShown">
<mx:Move duration="200" target="{сontrolPanel}"/>
</mx:Transition>
<mx:Transition fromState="PanelIsShown" toState="Normal">
<mx:Move duration="200" target="{сontrolPanel}"/>
</mx:Transition>
</mx:transitions>
Можно конечно обойтись одним блоком fromState="*" toState="*", но в некоторых ситуациях, панель "промигивает" в неположенных местах. Но это, конечно, зависит от специфики конкретного приложения.

В итоге, появление/убирание панели сделать средствами Flex удалось, но не так, как хотелось бы. Дело в том, что я хотел сделать небольшую паузу перед тем, как панель уберется. Сделал я следующее: второй блок transitions заменил на:
<mx:Sequence target="{сontrolPanel}">
<mx:Pause duration="1000"/>
<mx:Move duration="200"/>
</mx:Sequence>

Это вызвало две идиотские проблемы:
1. Такой способ наотрез отказывается работать, если в state меняется не непосредственно координата, а, к примеру, свойства right/left: <mx:SetStyle target="{сontrolPanel}" name="right" value="50"/> - анимация просто отсутствует.

2. Панель полностью исчезает и снова появляется, если быстро убрать мышь и опять навести ее на контейнер. А по-хорошему, панель должна оставаться на месте.

* * *

В общем, решая совсем простую задачу, я столкнулся с кучей дурацких проблем, которые, возможно, решаемы, но скорее всего через шаманские средства - наследование классов эффектов и модификация методов этих классов под свои нужды.

Или я что-то не допонял, или работа с эффектами оставляет желать лучшего...
Разочарован :(

* * *

Вот пример с аналогичной панелькой:
Sliding Canvas with Flex. Исходный код тут. Работает вполне стабильно. Замечательно. И главное, у меня такие штуки проходили почему то криво... Сам виноват. Поленился сделать такую же проверку transitionHappening. А проверял свойство isPlaying, а оно как-то не правильно показывает если стоит startDelay. Другой подход с принудительной остановкой stop() тоже не проходит - надо было изначально блокировать переключение visible, как в примере. А всё лень виновата - добавлять лишние скрипты не хочется :).
Хотя, с другой стороны, управлять положением компонентов через механизм стэйтов правильнее (универсальнее).

* * *

В итоге, всё получилось с применением showEffect/hideEffect. Получилось вполне стабильно и без неприятных побочных эффектов:


public function hideControlPanel():void {
panelShowEffect.stop();
panelHideEffect.stop();
if (controlPanel.visible)
controlPanel.visible=false;
}

public function showControlPanel():void {
if (!this.enabled) return;
panelShowEffect.stop();
panelHideEffect.stop();
if (!controlPanel.visible)
controlPanel.visible=true;
}

. . .

<mx:canvas width="{controlPanel.width}" height="100%" clipcontent="true" rollover="showControlPanel()" rollout="hideControlPanel()" creationcomplete="hideControlPanel()" backgroundcolor="#FFFFFF" backgroundalpha="0">

. . .

<mx:Move id="panelShowEffect" xTo="0" duration="200"/>
<mx:Move id="panelHideEffect" startDelay="1000" duration="200" xTo="{-controlPanel.width}"/>

. . .

<mx:VBox
id="controlPanel"
height="100%"
showEffect="{panelShowEffect}"
hideEffect="{panelHideEffect}"
x="{-controlPanel.width}"
visible="false"
>

. . . Содержимое панели . . .

</mx:VBox>

. . .

</mx:Canvas>



Единственная проблема -пришлось отказаться от эффекта WipeUp/Down, примененного к компоненту, вложенному в выезжающую панель, из-за его нестабильной работы.

2 комментария:

GB комментирует...

Я думаю можно было обойтись одним эффектом и реверсить его. Проблем с ползающей панелью вообще не должно быть. Если быстро убирали мышку - эффект уже работал: ждал секунду, потом начинал двигаться. Так что разбирайтесь, по-моему, вы просто не поняли принцип действия.

Unknown комментирует...

Хорошо бы, если так... Еще покопаюсь конечно, но времени жалко. Может где-нть есть примеры на такую панельку.

Да в принципе, сделать, чтобы панелька ездила туда-сюда по жестким координатам, проблем бы не вызвало. Тут дело в деталях - панелька подвешена к правому нижнему краю не жесткого окна, нужна задержка после старта эффекта и т.п. Вот в этих деталях, у меня flex и засыпался.
Понятно, что покодив полдня-день всё это я решу, но ведь это Flex! Хочется чтоб в три строчки всё заработало :), иначе зачем он вообще такой нужен...