Загрузка скинов для Flex Skins в Runtime

Автор: Brian Riggs (оригинал статьи)

Перевод: Андрей Горбатов (блог)

Существует много хороших ресурсов, где рассказано как создавать скины для Flex приложений.  Flex поддерживает два подхода: графическое и программное скинование. Графическое скинование – это создание графических наборов во Flash, Photoshop, Fireworks и встраивание их во Flex приложение.  Программное скинование – создание ActionScript класса, который определяет скин виджета.  Как вы уже догадались, графическое скинование проще, а программное – мощнее.
Единственным недостатком обоих подходов является то, что ресурсы для скинования (SWF/PNG/GIF/ и т.д. для графических скинов,  AS классы для программных скинов) должны быть доступны во время компиляции.  Или не должны?  Позже я объясню, как загружать скины в run-time (с помощью готового примера).
Чтобы сделать этот пример проще, я создам приложение, в котором динамически будет применен скин к кнопке. Приложение получит SWF со скинами в runtime, загрузит скины и применит их к кнопке.  Я буду использовать файл со скинами из статьи про скинование от NJ (на русском) и применять скины RadioButton к виджету  Button.  (Спасибо Roger Gonzalez и NJ за это решение.)

Шаг #1: Создание SWF оболочки для наборов скинов

Наборы скинов – это вышеупомянутый файл с темплейтом. Я хочу создать SWF оболочку, которую мое приложение сможет загрузить в runtime и извлечь необходимые скины, в данном случае это четыре символа для виджета RadioButton.  Вот исходный код SWF оболочки:

package
{   import flash.display.Sprite;
  public class Wrapper extends Sprite
  {
    [Embed(source="flex_skins.swf",symbol="RadioButton_upIcon")]
    public var rbUpSkin: Class;
    [Embed(source="flex_skins.swf",symbol="RadioButton_downIcon")]
    public var rbDownSkin: Class;
    [Embed(source="flex_skins.swf",symbol="RadioButton_disabledIcon")]
    public var rbDisabledSkin: Class;
    [Embed(source="flex_skins.swf",symbol="RadioButton_overIcon")]
    public var rbOverSkin: Class;
  }
}

Шаг #2: Закачка SWF оболочки на сервер

Flex приложение должно загружать файл откуда угодно!

Шаг #3: Во Flex приложении используйте класс Loader для загрузки оболочки

Я создал класс-утилиту ClassLoader для загрузки SWF и извлечения класса. Вот основной код:

loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
...
request = new URLRequest(swfLib);
var context:LoaderContext = new LoaderContext();
context.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
loader.load(request, context);

Обратите внимание, что Loader загружает SWF в ApplicationDomain, который является дочерним к текущему домену. Таким образом мы убеждаемся, что приложение может получить доступ к загруженному классу и его наборам.

Шаг #4: Получение класса из SWF и создание его экземпляра

Загружаем класс (в данном случае, "Wrapper"):

var wrapperClass:Class = loader.contentLoaderInfo.applicationDomain.getDefinition(className) as Class;
var wrapper:Object = new wrapperClass();

Шаг #5: Применение скинов с помощью setStyle

Теперь вам необходимо применить скины к кнопке:

StyleManager.getStyleDeclaration("Button").setStyle("upSkin", wrapper.rbUpSkin);
StyleManager.getStyleDeclaration("Button").setStyle("downSkin", wrapper.rbDownSkin);
StyleManager.getStyleDeclaration("Button").setStyle("disabledSkin", wrapper.rbDisabledSkin);
StyleManager.getStyleDeclaration("Button").setStyle("overSkin", wrapper.rbOverSkin);

Шаг #6: Запуск приложения

Приложение (смотреть здесь, включена возможность просмотра исходников) отображает текстовое поле, в которое вы можете ввести адрес SWF оболочки. (например, этой).  Затем нажмите "Apply" и скин кнопки изменится.  При наведении или клике мыши скин изменяется на соответствующий. 
Что же с этим делать?  Динамическое скинование дает нам огромную выгоду: вы даете возможность пользователям использовать свои скины в ваших приложениях. Представьте Winamp на Flex. Разработчику не надо создавать библиотеку скинов, пользователь сам сможет загрузить скины откуда-нибудь из внешних библиотек скинов. Также хорошо то, что разработчик может контролировать, какие виджеты могут сменить скин, а какие должны остаться не тронутыми (вызов setStyle только для нужных виджетов). И, наконец, внешнее хранение файлов со скинами обеспечит меньший вес файла приложения.