원리를 배운 곳:
http://www.quietlyscheming.com/blog/components/tutorial-displayshelf-component/
http://www.rictus.com/muchado/2006/07/05/live-reflection-component/



소스
Reflector.as
package
{
    import flash.display.BitmapData;
    import flash.display.GradientType;
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.geom.Matrix;
    import flash.geom.Point;
   
    import mx.core.UIComponent;
    import mx.events.FlexEvent;
    import mx.events.MoveEvent;
    import mx.events.ResizeEvent;

    public class Reflector extends UIComponent
    {
        private var cachedBitmap:BitmapData;
        private var cachedMatrix:Matrix = new Matrix();
        private var tempPoint:Point = new Point();
        private var refresh:Boolean = true;
       
        public function Reflector() {
            super();
        }
       
        private var _target:UIComponent;
       
        [Bindable]
        public function get target():UIComponent {
            return _target;
        }
       
        public function set target(value:UIComponent):void {
            if(_target == value)
                return;
           
            if(_target != null) {
                _target.removeEventListener(ResizeEvent.RESIZE, target_resizeHandler);
                _target.removeEventListener(MoveEvent.MOVE, target_moveHandler);
                _target.removeEventListener(FlexEvent.UPDATE_COMPLETE, target_updateHandler, true);
                _target.parent.removeEventListener(FlexEvent.UPDATE_COMPLETE, target_updateHandler2, true);           
            }
           
            _target = value;
            _target.addEventListener(ResizeEvent.RESIZE, target_resizeHandler);
            _target.addEventListener(MoveEvent.MOVE, target_moveHandler);
            _target.addEventListener(FlexEvent.UPDATE_COMPLETE, target_updateHandler, true);
            _target.parent.addEventListener(FlexEvent.UPDATE_COMPLETE, target_updateHandler2, true);           
           
            refresh = true;
            invalidateDisplayList();
        }
       
        private var _falloff:Number = 1;
       
        [Bindable]
        public function get falloff():Number {
            return _falloff;
        }
       
        public function set falloff(value:Number):void {
            if(_falloff == value)
                return;
               
            _falloff = value;
            refresh = true;
            invalidateDisplayList();
        }
       
        private function target_resizeHandler(e:ResizeEvent):void {
            refresh = true;
           
            this.width = _target.width;
            this.height = _target.height;
           
            target_moveHandler(null);
        }

        private function target_moveHandler(e:MoveEvent):void {
            move(_target.x, _target.y + _target.height);
        }

        private function target_updateHandler(e:FlexEvent):void {
            refresh = true;
            invalidateDisplayList();
        }
       
        private function target_updateHandler2(e:FlexEvent):void {
            if(e.target == _target) {
                refresh = true;
                invalidateDisplayList();
            }
        }
       
        override protected function updateDisplayList(w:Number, h:Number):void {
            if(refresh) {
                refresh = false;
                refreshCache();
            }
           
            var g:Graphics = graphics;
            g.clear();
            g.beginBitmapFill(cachedBitmap, cachedMatrix);
            g.drawRect(0, 0, w, h);
        }
       
        protected function refreshCache():void {
            // 알파비트맵을 위한 것 으로써,
            // 1. createGradientBox() 를 이용해 그라디언트 방향을 90도로 바꾼다.
            // 2. beginGradientFill()과 drawRect() 를 이용해  1에서 0으로 점점 흐려지는 알파를 그린다.
            //    이때, 그려지는 컬러는 무엇이든 상관없다. 중요한 것은 해당 컬러에 대응하는 알파값이다.
            //    이유는 copyPixels() 에서 alphaBitmap이 사용될 때, 비트맵이 가지고 있는 컬러는 무시하고
            //    알파만 참조하기 때문이다.
            var gradientSprite:Sprite = new Sprite();
            var gradientMatrix:Matrix = new Matrix();
            gradientMatrix.createGradientBox(_target.width, _target.height*_falloff, Math.PI/2, 0, _target.height*(1-_falloff));
            gradientSprite.graphics.beginGradientFill(GradientType.LINEAR, [0xffffff, 0xffffff], [0, 1], [0, 255], gradientMatrix);
            gradientSprite.graphics.drawRect(0, _target.height*(1-_falloff), _target.width, _target.height*_falloff);
           
            // 위에서 만들어진 Sprite를 비트맵에 그린다.
            var alphaBitmap:BitmapData = new BitmapData(_target.width, _target.height, true, 0);
            alphaBitmap.draw(gradientSprite);
           
            // target 객체를 그린다.
            var targetBitmap:BitmapData = new BitmapData(_target.width, _target.height, true, 0);
            targetBitmap.draw(_target);
           
            // 타겟비트맵을 복사한다. 복사할 때, 맨처음 만든 알파비트맵을 옵션으로 넣어준다.
            // 알파비트맵으로 인해  투명하게 그라데이션 된다.
            cachedBitmap = new BitmapData(_target.width, _target.height, true, 0);
            cachedBitmap.copyPixels(targetBitmap, cachedBitmap.rect, tempPoint, alphaBitmap);
           
            // 매트릭스의 y축을 -1로 설정하여 반전 시킨후, 반전된 만큼 원래 위치로 잡기위해 y좌표를 수정한다.
            cachedMatrix.identity();
            cachedMatrix.scale(1, -1);
            cachedMatrix.translate(0, _target.height);
        }
    }
}

main.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                xmlns:local="*"
                layout="absolute"
                backgroundColor="#000000" >
               
    <mx:Panel id="panel" x="10" y="10" width="337" height="102" layout="absolute" title="Reflection Panel" borderColor="#FDFF50">
        <mx:Label x="10" y="10" text="alpha"/>
        <mx:HSlider id="alphaSlider" x="54" y="10" width="253" minimum="0" maximum="1" liveDragging="true" value="1"/>
        <mx:Label x="9" y="36" text="falloff"/>
        <mx:HSlider id="falloffSlider" x="54" y="36" width="253" minimum="0" maximum="1" liveDragging="true" value="1"/>
    </mx:Panel>
    <local:Reflector target="{panel}" alpha="{alphaSlider.value}" falloff="{falloffSlider.value}"/>
   
</mx:Application>


신고
Posted by 째코