А что делать, если наш проект компилируется Flex SDK?
Можно сделать маленький модулек, который будет загружать и мониторить загрузку основного SWF. Ну а если требуется наличие только одного SWF?
Люди советуют почитать статью Preloaders in AS3. Читаем.
Основную мысль автору статьи, подсказал Ted Patrick, намекнув на мета-тег [Frame] и поглядеть исходник mx.core.Application.
Поглядим-ка
"...\Flex2SDK\frameworks\source\mx\core\Application.as ".
Как отметил 101 (тот что автор статьи) там и правда есть тег
[Frame(factoryClass="mx.managers.SystemManager")]
. А в комментарии, по-моему, ключевой является фраза "Все фреймворки инициализируются SystemManager-ом".Идем смотреть
"...\Flex2SDK\frameworks\source\mx\managers\SystemManager.as".
И правда - видим интересные фразы типа "ВНИМАНИЕ: Минимизируйте не флэшовые классы, которые импортируете здесь, всё что связано с SystemManager будет загружено в 1й фрейм до того, как загрузится прелоадер, и вообще, что-либо отображающееся." Кроме того, несколько ниже, говорится, что "SystemManager - первый визуальный класс, который создается в приложении. Он так же отвечает за создание mx.preloaders.Preloader, который отображает mx.preloaders.DownloadProgressBar до конца загрузки приложения, после чего SystemManager создает mx.core.Application instance". Собственно, вызывается метод SystemManager.create, код которого приводит 101 (автор).
Он пришел к следующим мыслям:
- Сначала создаем основной класс MainClass как обычно и указываем компилятору чтобы он его компилил.
- Затем в этом классе вставляем тег [Frame(factoryClass="MyFactoryClass")], который указывает на некий другой класс MyFactoryClass.
Итак, нам остается всего-навсего создать класс обычного прелоадера, который:
- Делает stop();
- Мониторит загрузку любым удобным для нас способом.
- После полной загрузки делает nextFrame();
Еще одна любопытная особенность этого решения - основной таймлайн представляет MainClass, но в качестве "Document Class" теперь выступает не MainClass, а MyFactoryClass. Из этого следует:
- MyFactoryClass должен наследоваться от MovieClip. И не в коем случае не от Sprite.
- При инстанцировании MainClass, необходимо добавить (addChild) его в дисплей-лист MyFactoryClass.
- MainClass не будет являться корнем дисплей-листа. Он будет чайлдом MyFactoryClass.
- В своем конструкторе, MainClass не должен ссылаться на "stage", так как он будет доступен только после добавления (addChild) MainClass в дисплей-лист.
В основном классе FrameTest - это то что выше называлось MainClass - всё просто. Имбедится и выводится картинка "big_asset.jpg", желательно очень большого размера. Единственное необычное - это фраза
[Frame(factoryClass="MyFactory")]
.Класс MyFactory - это наш вышеописываемый MyFactoryClass.
- В конструкторе производится остановка тайм-лайна stop(), выставляются параметры stage и добавляется обработчик "ENTER_FRAME".
- Обработчик onEnterFrame() рисует полосу состояния загрузки вычисляя процент загрузки:
var percent:Number = root.loaderInfo.bytesLoaded / root.loaderInfo.bytesTotal;
- При выполнении условия framesLoaded == totalFrames, объект отписывается от события "ENTER_FRAME", осуществляет переход на следующий фрейм nextFrame() и производит инициализацию init().
- Метод инициализации init() получает определение основного класса
var mainClass:Class = Class(getDefinitionByName("FrameTest"));
и, если такой класс существуетif (mainClass)
, инстанцирует его и добавляет в дисплей-лист:var app:Object = new mainClass(); addChild(app as DisplayObject);
.
Всё. Переходим к практике.
* * *
Не забудем положить картинку "big_asset.jpg" в папку с классами.
Первая коррекция - getDefinitionByName вызывает исключение, в случае если класс не найден. Поэтому проверки if(mainClass)
недостаточно. Нужна обработка исключения try ... catch.
* * *
Пробуем trace(this.currentFrame);
. Он выдает правильно - 1 из конструктора MyFactory
, 2 - из init();
.
Попробуем, как это будет работать в интернете. Хм. Прелоадер отрабатывает, но как-то поздно. Мой Naviscope показывает, что SWF загружается больше чем на половину, когда только начинает происходить отрисовка полосы загрузки. Попробую еще утяжелить SWF-ку. Для этого добавляю картинок.
Интересное наблюдение - если накопировать одну и ту же картинку и имбедить копии, размер SWF не изменится - как будто внедрена одна картинка! Вот это сжатие!
Итак, утяжелил до 20 мБ. Теперь всё встало на свои места. Прелоадер аккуратно отрабатывает объем и затем отображается картинка! Всё дело было в слишком быстром интернете.
Итак, подход прост и практичен. Спокойно делаем правильные и эффектные флэшки любого размера!
15 комментариев:
Хорошая статья, как раз то, что мне нужно было. Но не все так гладко. Вообщем выходят ошибки при компиляции и swf-файл не создается. все делаю как описано, в чем может быть проблема?
Сообщения:
Error: Unable to resolve resource bundle "skins" for locale "en_US".
Error: Unable to resolve resource bundle "styles" for locale "en_US".
Error: Unable to resolve resource bundle "skins" for locale "en_US".
Error: Unable to resolve resource bundle "core" for locale "en_US".
Error: Unable to resolve resource bundle "core" for locale "en_US".
Error: Unable to resolve resource bundle "effects" for locale "en_US".
Error: Unable to resolve resource bundle "core" for locale "en_US".
я делал в коне так:
var stage:Stage = super.stage;
var loaderInfo:LoaderInfo = super.loaderInfo;
if (super.parent) {
super.parent.removeChild( this );
}
if (loaderInfo.hasDefinition("MainClass")) {
var C:Class = loaderInfo.getDefinition("MainClass") as Class;
if (C) {
var root:DisplayObject = new C() as DisplayObject;
stage.addChild( root );
}
}
2 Vietnam: Мда... Без ложка дегтя не обошлось. А ты чем компилируешь? Я проверял на Flex 2 SDK. Надо будет попробовать под 3ю версию. Любопытная ошибочка :)
2 BlooDHounD: Ага, то есть ты MainClass прикрепить к stage а не к фабрике, а фабрику расстрелять. Вполне логично - попробую.
2 Racer: Использую Flex 3 SDK 3
2 BlooDHounD: Не помогло! Ошибки так и лезут! :(
"MainClass" я так понимаю это полный путь к классу!
Так и не поможет - тут явно другая причина.
Гугл дает такие ссылки:
http://bugs.adobe.com/jira/browse/SDK-11329
Описание бага, но не понятно, как его вылечили.
На
http://www.boostworthy.com/blog/?p=142
Говорят:
Добавил в build.properties:
flexlib.dir=frameworks/libs
flexlocale.dir=frameworks/locale/en_US
Необходимо изменить "en_US" если используется другая локаль.
В build.xml он добавил в -library-path эти значения:
Всё работает.
Тут http://www.deitte.com/archives/2006/10/using_resource.htm про аналогичные ошибки говорят:
В Flex 3 было много изменений относительно ResourceBundle. И посылает сюда: http://labs.adobe.com/wiki/index.php/Flex_3:Feature_Introductions:_Runtime_Localization
Тут много чего написано про локали, но прямого ответа нет.
Попробуй покопать в этих местах - может быть вылечится?
to Vietnam, мой пост не для вас :)
я этот эффект со стэджем давно юзаю.
2 BlooDHounD: А ты компилил свой код Flex 3 SDK? Не сталкивался с подобной ошибкой?
конечно компилил, я только под ним и работаю %) если ты про ошибку Vietnam, то у него проблемы с тем, что он скорее всего покоцал фремворк. у него нету файлов локацизации. тут: \sdks\3.0.0\frameworks\locale\en_US\
или они просто битые.
вообще этот код не для фсекс-фреймворка. во флексе так работает SystemManager. правда там непонятки с тем как он работает. советую посмотреть в этом классе мутод info(). он всегда позвращает новый пустой объект, а во всём классе из него переменные дёргаются. только компилятор что-то подгенерирывает, толи ещё что. и ещё там есть 3й кадр с некими extraClasses. тоже не понял с чем их едят.
Спасибо! Насчет 3-его кадра - любопытно.
про extraClass тут написно:
http://nondocs.blogspot.com/2007/04/metadataframe_22.html
но флекс всёравно себя странно ведёт с ним.
Кто-нить с последним Flex SDK проверял этот хак? 101 пишет, что вроде как он больше не работает и другого решения не знает.
Честно говоря, я так этим способом толком и не пользовался. Есть еще статейка, продолжение. Вот это я пользовал, вроде не так давно.
Кстати, в 9й бэте FlashDevelop, для чистых AS3 приложений уже есть встроенный шаблон приложения с прелоудером, где достаточно только подставить свой код в уже заготовленный класс.
Добрый день.
Можете пояснить строчку:
[Embed(source="big_asset.jpg")]private var Asset:Class;
Я так понял создаете класс для картинки которая не находится даже в библиотеке.
Пытаюсь делать тоже самое, выдает ошибку "1013: The private attribute may be used only on class property definitions.".
В чем проблема может быть?
Эта строчка внедряет в swf изображение, определяет его как класс, который затем можно инстанцировать. Ошибка означает что это определение должно находиться в пределах определения класса.
Ребят, а в SDK4 в FDT4 соответственно кто нибудь проверял? У меня не видит stage, в основном классе )
Отправить комментарий