Работа с событиями в ActionScript 3 и Adobe Flex Жизнь без событий Окно кнопкаНажата (Кнопка) родительскоеОкно.кнопкаНажата (я) Кнопка изменитьМетку (Строка) Жизнь без событий Окно кнопкаНажата (Кнопка) кнопка.изменитьМетку («Нажата») Кнопка изменитьМетку (Строка) Жизнь без событий • Кнопка и Окно знают друг о друге • Нельзя повторно использовать Кнопку Жизнь с событиями Окно кнопкаНажата (Событие) кнопка.регистрировать (кнопкаНажата) Кнопка регистрировать (Функция) изменитьМетку (Строка) Жизнь с событиями Окно кнопкаНажата (Событие) Событие нажатия и вызов обработчика Кнопка регистрировать (Функция) изменитьМетку (Строка) Жизнь с событиями Окно кнопкаНажата (Событие) кнопка.изменитьМетку («Нажата») Кнопка регистрировать (Функция) изменитьМетку (Строка) Жизнь с событиями • Окно знает о Кнопке • Кнопка ничего не знает об Окне • Кнопку можно повторно использовать! Кирпичики событий • • • • • • • Событие Извещение (dispatch) Поведение по умолчанию Поток события (event flow) Event object Event target Обработчик (listener) Реализации событийной модели • • • • • • on () – на кнопках и мувиклипах onClipEvent () – на мувиклипах XML.onLoad – методы-обработчики addListener () – листенеры addEventListener () – UIEventDispatcher DOM Level 3 !!! Поведение по умолчанию • Отсутствует у большинства событий • Не всякое поведение можно отменить • Бывает только у событий, генерируемых Flash Player’ом • Можно сделать аналог для кастомных событий Демо Поведение по умолчанию. PreventDefault.mxml Event flow Поток события Структура визуальных объектов Сцена Application Box1 Box2 Структура визуальных объектов Сцена Сцена Application Application Box1 Box2 Box1 Box1 Фазы событий • Фаза захвата (capture) • Целевая фаза (target) • Фаза пузырька (bubbling) Capture phase (фаза захвата) Сцена Application Box1 Box1 Target phase (целевая фаза) Сцена Application Box1 Box1 Bubbling phase (фаза пузырька) Сцена Application Box1 Box1 Event flow Сцена Фаза захвата Application Box1 Целевая фаза Фаза пузырька Box1 Event flow • Только для Display List – Можно сделать некоторый аналог • События клавиатуры и мыши (интерактив) • Event flow = capture + bubbling • Event object Event object • Наследуются от flash.events.Event • Описывают событие Свойства Event Object • • • • • • type cancelable bubbles eventPhase target currentTarget type • • • • Строка, идентифицирующая событие Только для чтения Устанавливается в конструкторе Event (type:String, bubbles:Boolean = false, cancelable:Boolean = false) • При наследовании пользоваться super (type) type: best practice package com.riapriority.events { import flash.events.Event; public class TestEvent extends Event { public static const MY_EVENT:String = "myEvent"; public static const ANOTHER_EVENT:String = "anotherEvent"; public function TestEvent(type:String) { super(type); } } } cancelable • Информация о возможности отмены поведения по умолчанию • Актуально только для событий Flash Player’а (пакет flash.*) • Можно использовать для организации собственного поведения по умолчанию bubbles • Относится к event flow • Показывает, участвует ли событие в баблинге • Если true, то capture + target + bubbling • Если false, то target phase • Может использоваться в собственных событиях eventPhase • Текущая фаза потока событий package flash.events { public final class EventPhase { public static const CAPTURING_PHASE:uint = 1; public static const AT_TARGET:uint = 2; public static const BUBBLING_PHASE:uint= 3; } } target • Ссылка на объект, являющийся целю события Сцена Application target Box1 Box1 currentTarget • Ссылка на текущий объект в event flow Сцена currentTarget Application target Box1 Box1 target и currentTarget • bubbles=false => target=currentTarget • target=currentTarget => eventPhase=2 • eventPhase=2 => target=currentTarge Демо Свойства Event object EventTestsClick.mxml EventTestsClickCapture.mxml Методы Event Object • • • • • preventDefault () isDefaultPrevented () stopPropogation () stopImmediatePropogation () clone () preventDefault () и isDefaultPrevented () • preventDefault () отменяет действие по умолчанию • isDefaultPrevented () проверяет, отменено ли действие • cancelable=false => isDefaultPrevented ()=false stopPropogation () • Отменяет вызов обработчиков в event flow Сцена Listener 1 Application Listener 2 Box1 stopPropogation () stopImmediatePropogation () • Отменяет вызов обработчиков в event flow Сцена Listener 1 Application Listener 2 Box1 stopImmediatePropogation () clone() • Необходимо реализовывать при создании собственных событий • Используется во внутренних механизмах диспетчеризации событий • dispatchEvent(event) Подписка и обработка IEventDispatcher package flash.events { public interface IEventDispatcher { function addEventListener(eventName:String, listener:Object, useCapture:Boolean=false, priority:Integer=0, useWeakReference:Boolean=false):Boolean; function removeEventListener(eventName:String, listener:Object, useCapture:Boolean=false):Boolean; function dispatchEvent(eventObject:Event):Boolean; function hasEventListener(eventName:String):Boolean; function willTrigger(eventName:String):Boolean; } } addEventListener • • • • • eventName: MouseEvent.CLICK, "click“ listener: ссылка на метод-обработчик useCapture: участие в capture phase priority: чем больше, тем раньше useWeakReference: сборка мусора addEventListener • Простейший случай addEventListener(MouseEvent.CLICK, clickHandler); – Подписка на target и bubbling phase • addEventListener(MouseEvent.CLICK, clickHandler, true); – Подписка только на capture phase • Оба вызова – подписка на все фазы addEventListener • priority может быть отрицательным • Одинаковый приоритет – в порядке добавления • useWeakReference позволяет не вызывать removeEventListener removeEventListener • Для удаления обработчиков всех фаз вызывайте дважды (useCapture)! • Удаляйте обработчики несуществующих объектов! • Или используйте weak reference Диспетчеризация событий • dispatchEvent (event) • target для event устанавливается автоматически (вызывающий объект)! • Например: dispatchEvent (new MyEvent (MyEvent.EVENT)); • Чаще всего при создании собственных компонент hasEventListener() и willTrigger() • hasEventListener(eventName:String): Boolean – подписался ли кто-то на событие? • willTrigger(eventName:String):Boolean – то же самое с учетом event flow Обработчики событий • function someHandler (event:Event):void • Обязательно указать один параметр! • Параметр – наследник flash.events.Event • someHandler (event:MouseEvent = null):void • someHandler (event:Event, second:Boolean = false):void Диспетчеры событий • • Наследование: class SomeClass extends EventDispatcher Композиция: package { class SomeClass implements IEventDispatcher { private var dispatcher:EventDispatcher; public function SomeClass () { // this в конструкторе для автоматического указания target dispatcher = new EventDispatcher (this); } … public function dispatchEvent(eventObject:Event):Boolean { return dispatcher.dispatchEvent (eventObject); } } } События в MXML <mx:Button click=“trace(‘Test!’)“ label=“Test” /> • Используется простая подписка addEventListener(MouseEvent.CLICK, clickHandler); • target и bubbling phase • Можно использовать ключевое слово event: <mx:Button click=“trace(event.eventPhase)“ label=“Test” /> • Нет легального способа отписки!!! События в MXML <mx:Script> <![CDATA[ private function onClick ():void {trace(“Test!”);} ]]> </mx:Script> <mx:Button click=“onClick ()“ label=“Test” /> Либо <mx:Script> <![CDATA[ private function onClick (event:MouseEvent):void {trace(event.eventPhase);} ]]> </mx:Script> <mx:Button click=“onClick (event)“ label=“Test” /> Метатэги • Используется в mxml (для компилятора и автокомплита) • name – текст, а не константа! • package { [Event(name="myEvent",type="com.riapriority.events. TestEvent")] class SomeClass extends EventDispatcher { … } • Или: <mx:Metadata> [Event(name="myEvent",type="com.riapriority.events. TestEvent")] </mx:Metadata> Кастомные события package com.riapriority.events { import flash.events.Event; public class TestEvent extends Event { public static const MY_EVENT:String = "myEvent"; public static const ANOTHER_EVENT:String = "anotherEvent"; public function TestEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false) { super(type, bubbles, cancelable); } override public function clone():Event { return new TestEvent (type, bubbles, cancelable); } } } Советы • Отписываться от ненужных событий • Трансформировать низкоуровневые события в события бизнес-логики – Для окна логина нажатие на кнопку Логин: • MouseEvent.CLICK – неправильно • LoginEvent.LOGIN – правильно! Демо Кастомные события CustomEvents.mxml Q&A Константин Ковалев http://riapriority.com/ constantiner@riapriority.com