Рубрика: ActionScript 3.0
Как много аргументов может быть у функции?
Коллеги не раз жаловались мне на мой класс UploadAction, единственный метод которого имел следующий вид:
- public function start(fileStorage:FileStorage, directoryPath:String = "",
- typeFilter:Array = null, nativeFiles:Array = null,
- singleFile:Boolean = false,
- defaultResize:int = UploadFileData.RESIZE_NONE,
- toUploadedFileSet:Boolean = false, autoClose:Boolean = false):void
Вызовы иногда выглядели удручающе:
- action.start(fileStorage, null, null, null, false, UploadFileData.RESIZE_NONE, true);
Я разводил руками - что тут поделаешь? Очень умный метод просто. И вот недавно в книге Объектно ориентированное конструирование программных систем я прочитал замечательный принцип:
Определение: операнд и опция
Аргумент является операндом, если он представляет объект, с которым оперирует программа.
Аргемент является опцией, если он задает режим выполнения операции.Принцип операндов
Аргументы методов должны быть только операндами, но не опциями.
Яркий пример применения подобного метода - drawing API Graphics в ActionScript 3.0 - там, например, цвет, прозрачность и толщина не являются аргументами метода drawRect().
Так что UploadAction я переделываю ![]()
Приложение под цвет кофточки
Flex 4 предоставляет нам возможность легко изменять цветовую гамму всего приложения. Flash Player предоставляет доступ к веб-камере. Так почему-бы не попробовать раскрасить Flex-приложение на основе картинки с камеры? ![]()
Flex-модули в AIR
Проблема
Для нас это значит, что:
- Просто так загрузить модули в debug-режиме из папки вне bin-debug Вашего проекта нельзя. Также нельзя загружать модули по абсолютным путям (причем даже из bin-debug).
- Просто так загрузить модули в AIR-приложение с какого-либо сервера нельзя.
VerifyError: Error #1014: Class mx.modules::Module could not be found. at flash.display::MovieClip/nextFrame() at mx.core::FlexModuleFactory/deferredNextFrame()
Решение
Существует обход этого запрета. Достаточно предварительно загрузить .swf-файл через URLLoader, а затем загружать модуль не по ссылке, а как ByteArray:
- moduleInfo.load(null, null, byteArray);
P.S
Аналогичная проблема существует для стилей, там это решается через monkey-patching StyleManagerImpl.
Как обойти список запрещенных слов в ContextMenuItem
Только т-с-с. Известный список запрещенных слов можно обхитрить, добавив в конец строки символ с кодом 160 ![]()
Другой подход к стилизации Flex-приложения
Проблема
При использовании нескольких внешних файлов стилей все они являются copy-paste одного шаблона с разными цветами/картинками. Из этого следует, что:
- Каждый из SWF стилей может занимать от 30 Кб до 300 и более Кб, в то же время очевидно что их код во многом совпадает. Хотелось бы не грузить одно и тоже.
- Из-за отсутствия настоящей иерархии в стилях одни и те же цвета приходится указывать в множестве мест
- Создание нового стиля - нудная работа по копи-пасту и замене цветов и картинок по всему (возможно - огромному) CSS-файлу
- Нельзя дать сторонним разработчикам возможность делать свои стили - ведь классы и селекторы переименовываются, добавляются новые. В то время по сути цвета и картинки остаются те же.
- Нельзя дать пользователю возможность настроить приложение под свои цвета.
Решение
Решение работает по той же схеме, что и недавний пост про изменение размера текста в приложении.
Вместо указаний явных значений для стилей вроде “backgroundColor", “color", “borderThickness” - указываются идентификаторы значений ("color1″) для стилей “backgroundColorId", “colorId", “borderThicknessId” а реальные значения в них проставляются в процессе выполнения:
- Application
- {
- colorId: "color4";
- fontSize: 12;
- backgroundColorId: "color0";
- }
Стиль можно задать следующим образом:
- private var style1:Object =
- {
- color0: 0x222222,
- color1: 0x333333,
- color2: 0x666666,
- color3: 0xAAAAAA,
- color4: 0xDDDDDD
- };
Код применения нового стиля:
- /**
- * Applies style to the application.
- *
- * @param object Keys are Strings like "color1", values are real style
- * values ex. "0xFFCC00".
- */
- private function applyStyle(object:Object):void
- {
- var selectors:Array = StyleManager.selectors;
- var bitmapClassCacheIndex:int = 0;
- var n:int = selectors.length;
- for (var i:int = 0; i < n; i++)
- {
- var selector:String = selectors[i];
- var declaration:CSSStyleDeclaration =
- StyleManager.getStyleDeclaration(selector);
- for each (name in idAttributes)
- {
- var idValue:String = declaration.getStyle(name + "Id") as String;
- if (!idValue)
- continue;
- if (object[idValue] is BitmapData)
- {
- var bitmapClass:Class = RuntimeBitmapAsset.bitmapDatas[idValue];
- if (!bitmapClass)
- {
- bitmapClassCacheIndex =
- bitmapClassCacheIndex % bitmapClassCache.length;
- bitmapClass = bitmapClassCache[bitmapClassCacheIndex++];
- RuntimeBitmapAsset.bitmapDatas[getQualifiedClassName(
- new bitmapClass())] = object[idValue];
- }
- declaration.setStyle(name, bitmapClass);
- }
- else if (object.hasOwnProperty(idValue))
- {
- declaration.setStyle(name, object[idValue]);
- }
- else
- {
- declaration.clearStyle(name);
- }
- }
- StyleManager.setStyleDeclaration(selector, declaration, i == n - 1);
- }
- }
Runtime иконки для Flex-компонент
Проблема
Flex SDK позволяет в качестве значение стиля “icon” для mx.controls.Button и других icon-стилей других компонент указывать только Class, экземпляры которого будут удовлетворять IFlexDisplayObject. Обычно это делается так:
- [Embed("mouse.png")]
- private var icon1:Class;
- <mx:Button icon="{icon1}"/>
Проблема в том, что mouse.png может определяться в процессе работы приложения.
Возможные пути решения
По мере поступления картинок компилировать из них SWF и подгружать.
Данный метод не всегда доступен и не удобен.
Сделать monkey-patch соответсвующих компонент SDK.
При смене версии Flex SDK возможно придется изменять и патчи. Также monkey patching приносит проблемы при работе с RSL. (eng)
Сгенерировать SWF с картинкой на лету.
Для этого придется изучить SWF Specification и AVM2 Bytecode.
Я разбирал уже скомпилированную SWF с одной картинкой, дошел до байткода. В случае PNG с прозрачностью выяснилось, что маска прозрачности, похоже, хранится отдельно, а сама картинка хранится в байткоде, так что не ждите легкого решения. По дороге выяснилось, что минимальный размер SWF - где-то 30 байтов.
Использовать несколько заранее вкомпилированных классов и ассоциировать с ними BitmapData по мере необходимости.
Этот способ будет рассмотрен далее.
Кеш классов-наследников BitmapAsset
Класс-картинка должен просто вызвать родительский конструктор BitmapAsset, передав ему нужное значение BitmapData. Реазилуем это следующим образом:
- package bitmaps
- {
- import flash.display.BitmapData;
- import flash.display.PixelSnapping;
- import flash.utils.getQualifiedClassName;
- import mx.core.BitmapAsset;
- public class RuntimeBitmapAsset extends BitmapAsset
- {
- /**
- * Maps class names to BitmapData instances.
- */
- public static const bitmapDatas:Object = {};
- public function RuntimeBitmapAsset()
- {
- var name:String = getQualifiedClassName(this);
- var bitmapData:BitmapData = bitmapDatas[name];
- if (!bitmapData)
- trace("Warning: BitmapData for \"" + name + "\" not found");
- super(bitmapData, PixelSnapping.AUTO, true);
- }
- }
- }
Далее создаем нужное количество классов-приспособленцев B0, B1, B2 …:
- package bitmaps
- {
- public class B0 extends RuntimeBitmapAsset
- {
- }
- }
Использование
- import flash.utils.getQualifiedClassName;
- import bitmaps.*;
- import mx.controls.Button;
- /**
- * Array of Class-es.
- */
- private var bitmapClasses:Array = [ B0, B1, B2 ];
- /**
- * Index of next available element in bitmapClasses
- */
- private var index:int = 0;
- private function addSample():void
- {
- if (container.numChildren == bitmapClasses.length)
- container.removeChildAt(0);
- var button:Button = new Button();
- button.label = "Button with icon using cache class B" + index;
- var theClass:Class = getNextBitmapClass(getRandomBitmapData());
- button.setStyle("icon", theClass);
- container.addChild(button);
- }
- private function getNextBitmapClass(bitmapData:BitmapData):Class
- {
- var bitmapClass:Class = bitmapClasses[index];
- index = (index + 1) % bitmapClasses.length;
- RuntimeBitmapAsset.bitmapDatas[getQualifiedClassName(new bitmapClass())] = bitmapData;
- return bitmapClass;
- }
- private function getRandomBitmapData():BitmapData
- {
- var bitmapData:BitmapData = new BitmapData(16, 16, true, 0);
- var seed:Number = Math.floor(Math.random() * 10);
- var channels:uint = BitmapDataChannel.RED | BitmapDataChannel.BLUE;
- bitmapData.perlinNoise(100 * Math.random(), 100 * Math.random(), 10 * Math.random(),
- seed, false, true, channels, false, null);
- return bitmapData;
- }
Flash Catalyst и его место в рабочем цикле Flex-проекта
Написал небольшой обзор места Flash Catalyst в рабочем цикле Flex-проекта.
Вопрос: соответствует ли то, что я написал, действительности?
Возможно, у Вас есть, что добавить?
Публичная Beta клиента COnline для коммуникационного сервера CommuniGate Pro:
Вкратце: COnline это расширенная версия GMail Notifier, только для нашего сервера:
Установок CommuniGate Pro в России очень много, другое дело что самые популярные почтовые сервисы используют свои почтовые сервера. Возможно, ваша корпоративная почта использует CommuniGate Pro и это приложение как раз для вас? ![]()
Библиотека CGP Client Library
Несколько недель назад я опубликовал библиотеку, которая позволяет очень быстро написать Flash/Flex/AIR-клиента для известного коммуникационного сервера CommuniGate Pro (почта, телефония, календари, файлы и т.п.).
Библиотека лежит на Google Code, доступна в исходных кодах и может быть использована в проприетарном ПО. Пример использования с view source.
Зачем мне это надо?
Сервер CommuniGate Pro продается по всему миру. Если Вы напишете что-то классное и нужное покупателям CGP (в основном это провайдеры), то это можно продать. Как покупателям CGP, так и самой компании CommuniGate Systems.
И снова про ошибки во Flash Player
FileReference objects obtained from FileReferenceList do not load()
Причем только в AIR. Ссылка на баг в Adobe JIRA, там же можно найти много подтверждающих примеров. Некто Supriya Rao посчитал(а), что это Not a Bug и сделал(а) его Closed. Нет слов…
Добавим к этому то, что в Flash Player Runtime (не AIR) FileReference.load() работает, но для того, чтобы отправить multipart POST-запрос нам нужно действие юзера (клик мыши/клавиши) - и получаем полную невозможность пользоваться функцией load().
Заключение
Пошел делать revert до версии, в которой работа идет через AIR-овский File. И искать/чинить баги в своем приложении, чтобы они не тратили время юзеров так, как Adobe тратит моё.
:: Следующие >>









