こんにちは、きんくまです。
前回interfaceについて書いたのですけど、書いてて最後に思い出したのでそれをこのエントリーに載せようと思います。
前回の最後にiOSやAndroidのネイティブアプリの開発だとinterfaceを使って、イベントが通知されることが多いことを
思いだしたのでした。
それで、これをAS3で似たように作ってみるとどうなるかです。
下の図のような地図を見せるアプリを作るとします。
地図の部分をMapViewとして、これがドラッグを始めたときと、ドラッグし終わったときに、
別のクラスからそのイベントを取りたいとします。
そこで、そのイベントをinterfaceで定義します。
package { public interface IMapViewDelegate { function willStartScroll(mapView:MapView,scrollPositionX:Number, scrollPositionY:Number):void; function didStopScroll(mapView:MapView,scrollPositionX:Number, scrollPositionY:Number):void; } }
willStartScrollはスクロールを始めたとき、didStopScrollはスクロールが終わったときに実行されます。
MapViewのクラスはこうします。
package { import flash.display.Graphics; import flash.display.Shape; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; public class MapView extends Sprite { private var _mapMask:Shape; private var _mapSprite:Sprite; public var delegate:IMapViewDelegate; public function MapView() { createView(); _mapSprite.addEventListener(MouseEvent.MOUSE_DOWN, onViewMouseDown); } protected function onViewMouseDown(event:MouseEvent):void { stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp); _mapSprite.startDrag(false); if(delegate != null){ //delegateに伝える delegate.willStartScroll(this, _mapSprite.x, _mapSprite.y); } } protected function onStageMouseUp(event:MouseEvent):void { stage.removeEventListener(MouseEvent.MOUSE_UP, onStageMouseUp); _mapSprite.stopDrag(); if(delegate != null){ //delegateに伝える delegate.didStopScroll(this, _mapSprite.x, _mapSprite.y); } } private function createView():void { _mapSprite = new Sprite(); addChild(_mapSprite); var g:Graphics = _mapSprite.graphics; g.beginFill(0xaaaaaa, 1); g.drawRect(0,0,4000,4000); g.endFill(); g.lineStyle(1,0); for(var i:int = 1; i < 40; i++){ g.moveTo(i * 100, 0); g.lineTo(i * 100, 4000); g.moveTo(0, i * 100); g.lineTo(4000, i * 100); } _mapSprite.x = -2000; _mapSprite.y = -2000; _mapMask = new Shape(); addChild(_mapMask); g = _mapMask.graphics; g.beginFill(0xff0000,1); g.drawRect(0,0,450,450); g.endFill(); _mapSprite.mask = _mapMask; } } }
中にdelegateというプロパティを用意して、その型をさきほど定義したIMapViewDelegateにします。
それで、delegateにイベントを伝えたいときに、その関数を実行します。
このMapViewを使うメインクラスはこうなります。
package { import flash.display.Sprite; [SWF(width="450",height="450",frameRate="30")] public class Interface2 extends Sprite implements IMapViewDelegate { private var _mapView:MapView; public function Interface2() { _mapView = new MapView(); _mapView.delegate = this; //ここでひもづけ addChild(_mapView); } public function willStartScroll(mapView:MapView,scrollPositionX:Number, scrollPositionY:Number):void { trace("start x:" + scrollPositionX + ", y:" +scrollPositionY); } public function didStopScroll(mapView:MapView,scrollPositionX:Number, scrollPositionY:Number):void { trace("stop x:" + scrollPositionX + ", y:" +scrollPositionY); } } }
mapViewを作ったあとに、自分自身の参照をdelegateに代入しています。
これをすると、mapViewのイベントをInterfaceに定義された関数経由で受け取ることができます。
mapView側はdelegateの実体がどんなクラスかを知らないのですが、IMapViewDelegateを実装していることを
知っているので、その関数を実行することができます。
delegateのクラスはどんなクラスでもよいので、柔軟性が高いやり方だと思います。
でも、これと同じようなことは、EventDispatcherですることができます。
その場合interfaceは必要ありません。
MapViewは
package { import flash.display.Graphics; import flash.display.Shape; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; public class MapView extends Sprite { public static const SCROLL_START:String = "scroll_start"; public static const SCROLL_STOP:String = "scroll_stop"; private var _mapMask:Shape; private var _mapSprite:Sprite; public function MapView() { createView(); _mapSprite.addEventListener(MouseEvent.MOUSE_DOWN, onViewMouseDown); } protected function onViewMouseDown(event:MouseEvent):void { stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp); _mapSprite.startDrag(false); dispatchEvent(new Event(SCROLL_START)); } protected function onStageMouseUp(event:MouseEvent):void { stage.removeEventListener(MouseEvent.MOUSE_UP, onStageMouseUp); _mapSprite.stopDrag(); dispatchEvent(new Event(SCROLL_STOP)); } public function get scrollPositionX():Number { return _mapSprite.x; } public function get scrollPositionY():Number { return _mapSprite.y; } private function createView():void { _mapSprite = new Sprite(); addChild(_mapSprite); var g:Graphics = _mapSprite.graphics; g.beginFill(0xaaaaaa, 1); g.drawRect(0,0,4000,4000); g.endFill(); g.lineStyle(1,0); for(var i:int = 1; i < 40; i++){ g.moveTo(i * 100, 0); g.lineTo(i * 100, 4000); g.moveTo(0, i * 100); g.lineTo(4000, i * 100); } _mapSprite.x = -2000; _mapSprite.y = -2000; _mapMask = new Shape(); addChild(_mapMask); g = _mapMask.graphics; g.beginFill(0xff0000,1); g.drawRect(0,0,450,450); g.endFill(); _mapSprite.mask = _mapMask; } } }
イベントの文字列 SCROLL_STARTとSCROLL_STOPを用意してあげて、イベントを発行したくなったらdispatchします。
それを受け取る側はこうです。
package { import flash.display.Sprite; import flash.events.Event; [SWF(width="450",height="450",frameRate="30")] public class Interface2 extends Sprite { private var _mapView:MapView; public function Interface2() { _mapView = new MapView(); _mapView.addEventListener(MapView.SCROLL_START, onMapScrollStart); _mapView.addEventListener(MapView.SCROLL_STOP, onMapScrollStop); addChild(_mapView); } protected function onMapScrollStart(event:Event):void { var map:MapView = event.currentTarget as MapView; trace("start x:" + map.scrollPositionX + ", y:" +map.scrollPositionY); } protected function onMapScrollStop(event:Event):void { var map:MapView = event.currentTarget as MapView; trace("stop x:" + map.scrollPositionX + ", y:" +map.scrollPositionY); } } }
前回はinterfaceを実装していたのですが、今回は不必要になったのでとってしまいました。
代わりにaddEventListenerをして、イベントを登録しました。
今回はinterfaceとEventDispatcherの2つの仕組みで同じ機能を作ってみました。
これの使い分けなんですが、AS3ではEventDispatcherだけで問題ないかと思います。
ただ、interfaceを使うとEventDisptacherという別のクラスを使わなくてよいので、実行速度が早くなるんじゃないかなと思います。あ、実測したわけじゃないので、適当なこと書いたかも。
では。
■ 自作iPhoneアプリ 好評発売中!
・フォルメモ - シンプルなフォルダつきメモ帳
・ジッピー電卓 - 消費税や割引もサクサク計算!
■ LINEスタンプ作りました!
毎日使える。とぼけたウサギ