超お手軽Dock

あちこちで公開されているMacOSXのDock風のコンポーネントですが、Boxレイアウトを応用すると結構簡単にできます。

というのも、Flex2ではコンポーネントのScaleを考慮してリアルタイムにレイアウトしてくれるため、個々のScaleを変えるだけでほかのコンポーネントが勝手によけてくれます。こういうのって、他のプラットフォームではなかなか思いつかないですよね。

ソース上の工夫としては、マウスオーバーしたときに徐々に大きくなるよう、個々のアイテムに対してエフェクトをかけています。

使い方ですが、PanelやApplicationでlayout='vertical',horizontalAlign='center'に指定し、
ZoomBoxにdirection='horizontal',verticalAlign='bottom'を指定して張り込んでやると、画面下部に表示されます。
(もとはBoxですから、アイテムは各自張り込んでください。Listではありません)

もっとかっこよくするには、鏡面加工を施したまな板(?)を張り込んでやるべきですが、それはまた今度。

import flash.display.DisplayObject;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.utils.Dictionary;

import mx.containers.Box;
import mx.effects.Zoom;

public class ZoomBox extends Box
{
	public static const MAX_ZOOM:Number = 2;
	public static const MAX_DISTANCE:Number = 200;

	public function ZoomBox()
	{
		super();
	}
	
	protected override function childrenCreated():void
	{
		super.childrenCreated();
		addEventListener(MouseEvent.MOUSE_MOVE, mouseOverHandler);
		addEventListener(MouseEvent.MOUSE_OUT, mouseOverHandler);
	}
	
	protected function mouseOverHandler(e:MouseEvent):void
	{
		e.stopImmediatePropagation();
		var insideMouse:Boolean = getRect(this).contains(mouseX,mouseY);
		for (var i:Number = 0; i < numChildren; i++){
			var child:DisplayObject = getChildAt(i);
			var z:Number = 1.0;
			if(insideMouse){
				var d:Number = getDistance(i,mouseX,mouseY);
				if(d <MAX_DISTANCE *2){
					z = Math.max(Math.cos(d/MAX_DISTANCE)*MAX_ZOOM+ 1, 1);
				}
			}
			applyEffect(child,z);

		}
		invalidateDisplayList();
	}
	
	private function getDistance(index:int, x:Number, y:Number):Number
	{
		var child:DisplayObject = getChildAt(index);
		var rect:Rectangle = child.getRect(this);
		if(child){
			var cx:Number = rect.x + child.width / 2;
			var cy:Number = rect.y + child.height /2;
			if(direction == "horizontal"){
				return Math.abs(x - cx);
			}else{
				return Math.abs(y - cy);
			}
		}
		return MAX_DISTANCE + 1;
	}
	
	private function applyEffect(child:DisplayObject, zoom:Number):void
	{
		var ef:Zoom = efDic[child] as Zoom;
		if(!ef){
			ef = new Zoom(child);
			ef.duration = 100;
			efDic[child] = ef;
		}
		if(ef.isPlaying){
			ef.stop();
		}
		ef.zoomWidthTo = ef.zoomHeightTo = zoom;
		ef.play();
	}
	
	private function isPlayingEffect(child:DisplayObject):Boolean
	{
		var ef:Zoom = efDic[child] as Zoom;
		return ef ? ef.isPlaying : false;
	}
	
	private var efDic:Dictionary = new Dictionary(true);
}