CoverFlow

来源:互联网 发布:淘宝psp店 编辑:程序博客网 时间:2024/04/30 12:01

package com.rialvalue.layouts {
    import flash.events.TimerEvent;
    import flash.geom.Matrix3D;
    import flash.geom.PerspectiveProjection;
    import flash.geom.Point;
    import flash.geom.Vector3D;
    import flash.utils.Timer;

    import mx.core.ILayoutElement;
    import mx.core.IVisualElement;
    import mx.core.UIComponent;

    import spark.layouts.supportClasses.LayoutBase;

    public class CoverflowLayout extends LayoutBase {
        private static const ANIMATION_DURATION:int = 700;
        private static const ANIMATION_STEPS:int = 24; // fps
        private static const RIGHT_SIDE:int = -1;
        private static const LEFT_SIDE:int = 1;

        private var finalMatrixs:Vector.<Matrix3D>;
        private var centerX:Number;
        private var centerY:Number;
        private var transitionTimer:Timer;


        private var _elementRotation:Number;
        private var _selectedItemProximity:Number;
        private var _selectedIndex:int;
        private var _depthDistance:Number;
        private var _perspectiveProjectionX:Number;
        private var _perspectiveProjectionY:Number;
        private var _focalLength:Number = 300;
        private var _horizontalDistance:Number = 100;


        public function set perspectiveProjectionX(value:Number):void {
            _perspectiveProjectionX = value;
            invalidateTarget();
        }


        public function set perspectiveProjectionY(value:Number):void {
            _perspectiveProjectionY = value;
            invalidateTarget();
        }


        public function set focalLength(value:Number):void {
            _focalLength = value;
            invalidateTarget();
        }


        public function set elementRotation(value:Number):void {
            _elementRotation = value;
            invalidateTarget();
        }


        public function set horizontalDistance(value:Number):void {
            _horizontalDistance = value;
            invalidateTarget();
        }


        public function set depthDistance(value:Number):void {
            _depthDistance = value;
            invalidateTarget();
        }


        public function set selectedItemProximity(value:Number):void {
            _selectedItemProximity = value;
            invalidateTarget();
        }


        public function set selectedIndex(value:Number):void {
            _selectedIndex = value;

            if (target) {
                target.invalidateDisplayList();
                target.invalidateSize();
            }
        }


        private function invalidateTarget():void {
            if (target) {
                target.invalidateDisplayList();
                target.invalidateSize();
            }
        }


        private function centerPerspectiveProjection(width:Number, height:Number):void {
            _perspectiveProjectionX = _perspectiveProjectionX != -1 ? _perspectiveProjectionX : width / 2;
            _perspectiveProjectionY = _perspectiveProjectionY != -1 ? _perspectiveProjectionY : height / 2;

            var perspectiveProjection:PerspectiveProjection = new PerspectiveProjection();
            perspectiveProjection.projectionCenter = new Point(_perspectiveProjectionX, _perspectiveProjectionY);
            perspectiveProjection.focalLength = _focalLength;

            target.transform.perspectiveProjection = perspectiveProjection;
        }


        private function positionCentralElement(element:ILayoutElement, width:Number, height:Number):Matrix3D {
            element.setLayoutBoundsSize(NaN, NaN, false);
            var matrix:Matrix3D = new Matrix3D();
            var elementWidth:Number = element.getLayoutBoundsWidth(false);
            var elementHeight:Number = element.getLayoutBoundsHeight(false);

            centerX = (width - elementWidth) / 2;
            centerY = (height - elementHeight) / 2;

            matrix.appendTranslation(centerX, centerY, -_selectedItemProximity);

            element.setLayoutBoundsSize(NaN, NaN, false);

            if (element is IVisualElement) {
                IVisualElement(element).depth = 10;
            }

            return matrix;
        }


        private function positionLateralElement(element:ILayoutElement, index:int, side:int):Matrix3D {
            element.setLayoutBoundsSize(NaN, NaN, false);

            var matrix:Matrix3D = new Matrix3D();
            var elementWidth:Number = element.getLayoutBoundsWidth(false);
            var elementHeight:Number = element.getLayoutBoundsHeight(false);

            var zPosition:Number = index * _depthDistance;

            if (side == RIGHT_SIDE) {
                matrix.appendTranslation(-elementWidth, 0, 0);
                matrix.appendRotation(side * _elementRotation, Vector3D.Y_AXIS);
                matrix.appendTranslation(2 * elementWidth - _horizontalDistance, 0, 0);
            } else {
                matrix.appendRotation(side * _elementRotation, Vector3D.Y_AXIS);
            }

            matrix.appendTranslation(centerX - side * (index) * _horizontalDistance, centerY, zPosition);

            if (element is IVisualElement) {
                IVisualElement(element).depth = -zPosition;
            }

            return matrix;
        }


        override public function updateDisplayList(width:Number, height:Number):void {
            var i:int = 0;
            var j:int = 0;
            var numElements:int = target.numElements;
            var matrix:Matrix3D;

            if (numElements > 0) {
                centerPerspectiveProjection(width, height);
                finalMatrixs = new Vector.<Matrix3D>(numElements);

                var midElement:int = _selectedIndex == -1 ? Math.ceil(numElements / 2) : _selectedIndex;
                matrix = positionCentralElement(target.getVirtualElementAt(midElement), width, height);
                finalMatrixs[midElement] = matrix;

                for (i = midElement - 1; i >= 0; i--) {
                    matrix = positionLateralElement(target.getVirtualElementAt(i), midElement - i, LEFT_SIDE);
                    finalMatrixs[i] = matrix;
                }

                for (j = 0, i = midElement + 1; i < numElements; i++, j++) {
                    matrix = positionLateralElement(target.getVirtualElementAt(i), j, RIGHT_SIDE);
                    finalMatrixs[i] = matrix;
                }

                playTransition();
            }
        }


        private function playTransition():void {
            if (transitionTimer) {
                transitionTimer.stop();
                transitionTimer.reset();
            } else {
                transitionTimer = new Timer(ANIMATION_DURATION / ANIMATION_STEPS, ANIMATION_STEPS);
                transitionTimer.addEventListener(TimerEvent.TIMER, animationTickHandler);
                transitionTimer.addEventListener(TimerEvent.TIMER_COMPLETE, animationTimerCompleteHandler);
            }

            transitionTimer.start();
        }


        private function animationTickHandler(event:TimerEvent):void {
            var numElements:int = target.numElements;

            var initialMatrix:Matrix3D;
            var finalMatrix:Matrix3D;
            var element:ILayoutElement;

            for (var i:int = 0; i < numElements; i++) {
                finalMatrix = finalMatrixs[i];

                element = target.getVirtualElementAt(i);

                initialMatrix = UIComponent(element).transform.matrix3D;
                initialMatrix.interpolateTo(finalMatrix, 0.2);
                element.setLayoutMatrix3D(initialMatrix, false);

            }
        }


        private function animationTimerCompleteHandler(event:TimerEvent):void {
            finalMatrixs = null;
        }
    }
}
 
主文件:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
      xmlns:s="library://ns.adobe.com/flex/spark"
      xmlns:mx="library://ns.adobe.com/flex/mx"
      minWidth="800"
      minHeight="480"
      xmlns:local="*"
      creationComplete="init()"
      xmlns:layouts="com.rialvalue.layouts.*"
      viewSourceURL="srcview/index.html">
 <fx:Metadata>
  [SWF(width="800", height="480")]
 </fx:Metadata>
 <fx:Script>
  <![CDATA[
   import mx.events.CollectionEvent;

   [Bindable]
   private var presets:ArrayCollection;


   private function init():void
   {
    dp.disableAutoUpdate();
    dp2.disableAutoUpdate();

    for (var i:int=1; i < 32; i++)
    {
     dp.addItem("photos/photo_" + i + ".jpg");
    }

    for (i=0; i < 10; i++)
    {
     dp2.addItem("photos/photo_" + i + ".jpg");
    }

    dp.enableAutoUpdate();
    dp2.enableAutoUpdate();

    initPresets();
   }


   private function initPresets():void
   {
    presets=new ArrayCollection();
    presets.disableAutoUpdate();
    presets.addItem({label: "Preset1", projectionX: -1, projectionY: -1, focalLength: 300, hDistance: 103, depth: 1, rotation: -70, proximity: 75});
    presets.addItem({label: "Preset2", projectionX: -1, projectionY: -1, focalLength: 300, hDistance: 100, depth: 1, rotation: -45, proximity: 30});
    presets.addItem({label: "Preset3", projectionX: -1, projectionY: 60, focalLength: 300, hDistance: 87, depth: 55, rotation: 0, proximity: 30});
    presets.addItem({label: "Preset4", projectionX: 468, projectionY: 298, focalLength: 327, hDistance: 88, depth: 50, rotation: -45, proximity: 30});
    presets.addItem({label: "Preset5", projectionX: 236, projectionY: -6, focalLength: 416, hDistance: 36, depth: 100, rotation: 0, proximity: 30});
    presets.enableAutoUpdate();
    presetsSelector.selectedIndex=0;
   }
  ]]>
 </fx:Script>

 <fx:Declarations>
  <s:ArrayCollection id="dp"/>
  <s:ArrayCollection id="dp2"/>

  <fx:Component id="renderer1">
   <mx:Image source="{data}"/>
  </fx:Component>

  <fx:Component id="renderer2">
   <local:PodRenderer autoDrawBackground="false"/>
  </fx:Component>
 </fx:Declarations>

 <s:layout>
  <s:VerticalLayout horizontalAlign="center"
        verticalAlign="middle"/>
 </s:layout>

 <s:List dataProvider="{ dataSelector.selectedItem.data }"
   width="750"
   height="375"
   id="list"
   selectedIndex="@{ selectedSlider.value}"
   itemRenderer="{rendererSelector.selectedItem.data}">
  <s:layout>
   <layouts:CoverflowLayout id="coverflow"
          selectedIndex="{ list.selectedIndex }"
          horizontalDistance="{horizontalDistance.value}"
          selectedItemProximity="{selectedItemProximity.value}"
          depthDistance="{depthDistance.value}"
          elementRotation="{elementRotation.value}"
          focalLength="{focalLength.value}"
          perspectiveProjectionX="{projectionX.value}"
          perspectiveProjectionY="{projectionY.value}"/>
  </s:layout>
 </s:List>

 <s:HGroup width="850">
  <s:VGroup width="50%">
   <mx:Form>
    <mx:FormItem label="Selected Item">
     <s:HSlider id="selectedSlider"
          minimum="0"
          maximum="{ dp.length}"
          stepSize="1"
          value="5"/>
    </mx:FormItem>

    <mx:FormItem label="Presets">
     <s:ComboBox id="presetsSelector"
        dataProvider="{presets}"/>
    </mx:FormItem>

    <mx:FormItem label="Perspectivice Projection center"
        direction="vertical">
     <s:HSlider id="projectionX"
          minimum="-1000"
          maximum="1000"
          value="{presetsSelector.selectedItem.projectionX}"/>
     <s:HSlider id="projectionY"
          minimum="-1000"
          maximum="1000"
          value="{presetsSelector.selectedItem.projectionY}"/>
    </mx:FormItem>

    <mx:FormItem label="Element rotation">
     <s:HSlider id="elementRotation"
          minimum="-90"
          maximum="0"
          stepSize="1"
          value="{presetsSelector.selectedItem.rotation}"/>
    </mx:FormItem>

   </mx:Form>
  </s:VGroup>

  <s:VGroup width="50%">
   <mx:Form>
    <mx:FormItem label="Renderer">
     <s:ComboBox id="rendererSelector"
        selectedIndex="0">
      <s:dataProvider>
       <s:ArrayCollection>
        <fx:Object label="renderer1"
             data="{renderer1}"/>
        <fx:Object label="renderer2"
             data="{renderer2}"/>
       </s:ArrayCollection>
      </s:dataProvider>
     </s:ComboBox>
    </mx:FormItem>

    <mx:FormItem label="Focal length">
     <s:HSlider id="focalLength"
          minimum="1"
          maximum="1000"
          value="{presetsSelector.selectedItem.focalLength}"/>
    </mx:FormItem>

    <mx:FormItem label="Horizontal distance">
     <s:HSlider id="horizontalDistance"
          minimum="0"
          maximum="200"
          stepSize="1"
          value="{presetsSelector.selectedItem.hDistance}"/>
    </mx:FormItem>

    <mx:FormItem label="Depth distance">
     <s:HSlider id="depthDistance"
          minimum="1"
          maximum="200"
          stepSize="1"
          value="{presetsSelector.selectedItem.depth}"/>
    </mx:FormItem>

    <mx:FormItem label="Selected Item proximity">
     <s:HSlider id="selectedItemProximity"
          minimum="0"
          maximum="200"
          stepSize="1"
          value="{presetsSelector.selectedItem.proximity}"/>
    </mx:FormItem>

    <mx:FormItem label="DataProvider">
     <s:ComboBox id="dataSelector"
        selectedIndex="0">
      <s:dataProvider>
       <s:ArrayCollection>
        <fx:Object label="dp1"
             data="{dp}"/>
        <fx:Object label="dp2"
             data="{dp2}"/>
       </s:ArrayCollection>
      </s:dataProvider>
     </s:ComboBox>
    </mx:FormItem>
   </mx:Form>
  </s:VGroup>
 </s:HGroup>
</s:Application>
 PodRenderer:

<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt"
    xmlns:flm="http://ns.adobe.com/flame/2008" xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark">

    <!-- Generate with Adobe Catalyst CS5 -->

    <s:states>
        <s:State name="up"/>
        <s:State name="overed"/>
    </s:states>

    <s:Group id="group2" x="0" blendMode="normal" x.overed="18" y.overed="0" y.up="10">
        <s:Group id="group1" x="0" y="132" blendMode="normal" d:userLabel="shadowAndReflect" y.overed="142">
            <s:Group id="group3" x="32" y="8" ai:spare="1" d:userLabel="reflectGroup" luminosityClip="true" maskType="luminosity"
                x.overed="14">
                <s:mask>
                    <s:Group x="-9.761" y="-2.774">
                        <s:Rect width="159.361" height="149.932">
                            <s:fill>
                                <s:LinearGradient scaleX="149.932" x="79.6807" y="0" rotation="90">
                                    <s:GradientEntry color="#FFFFFF" ratio="0"/>
                                    <s:GradientEntry ratio="1"/>
                                </s:LinearGradient>
                            </s:fill>
                        </s:Rect>
                    </s:Group>
                </s:mask>
                <s:Rect width="140" height="140" x="0" y="0" alpha="0.77" d:id="6" d:userLabel="reflect" flm:variant="5"
                    height.up="72">
                    <s:fill>
                        <s:LinearGradient scaleX="140.03" x="0" y="70.0146">
                            <s:GradientEntry color="#F5F7F9" ratio="0"/>
                            <s:GradientEntry color="#E0E2E4" ratio="0.026793"/>
                            <s:GradientEntry color="#D2D5D7" ratio="0.0560065"/>
                            <s:GradientEntry color="#CCCFD1" ratio="0.0882261"/>
                            <s:GradientEntry color="#CACDCF" ratio="0.131868"/>
                            <s:GradientEntry color="#D7D9DB" ratio="0.895604"/>
                            <s:GradientEntry color="#E0E2E4" ratio="0.940392"/>
                            <s:GradientEntry color="#F5F7F9" ratio="1"/>
                        </s:LinearGradient>
                    </s:fill>
                </s:Rect>
            </s:Group>
            <s:BitmapImage id="bitmapimage1" source="@Embed('assets/itemShadow.png')" x="0" y="0" alpha="0.49" d:id="7"
                d:userLabel="shadow" flm:variant="7" height.overed="17" smooth="true" width.overed="165"/>
        </s:Group>
        <s:Group id="group4" x="32" y="0" d:userLabel="Item" 
            x.overed="14">
            <s:Rect width="140" height="140" x="0" y="0" d:id="8" d:userLabel="background" flm:variant="8">
                <s:fill>
                    <s:LinearGradient scaleX="140.03" x="0" y="70.0142">
                        <s:GradientEntry color="#F5F7F9" ratio="0"/>
                        <s:GradientEntry color="#E0E2E4" ratio="0.026793"/>
                        <s:GradientEntry color="#D2D5D7" ratio="0.0560065"/>
                        <s:GradientEntry color="#CCCFD1" ratio="0.0882261"/>
                        <s:GradientEntry color="#CACDCF" ratio="0.131868"/>
                        <s:GradientEntry color="#D7D9DB" ratio="0.895604"/>
                        <s:GradientEntry color="#E0E2E4" ratio="0.940392"/>
                        <s:GradientEntry color="#F5F7F9" ratio="1"/>
                    </s:LinearGradient>
                </s:fill>
            </s:Rect>
            <s:Path
                data="M 102.053 0 L 9.976 0 C 4.475 0 0 4.537 0 10.112 L 0 11.319 C 0 16.898 4.475 21.438 9.976 21.438 L 102.053 21.438 C 107.551 21.438 112.025 16.898 112.025 11.319 L 112.025 10.112 C 112.025 4.537 107.551 0 102.053 0 L 102.053 0 Z"
                x="13.661" y="110.022" alpha="0.55" d:id="10" d:userLabel="backgroundAmount" flm:variant="10" winding="nonZero" includeIn="overed">
                <s:fill>
                    <s:LinearGradient scaleX="21.438" x="56.013" y="0" rotation="90">
                        <s:GradientEntry color="#929EA1" ratio="0"/>
                        <s:GradientEntry color="#A8B1B3" ratio="0.11423"/>
                        <s:GradientEntry color="#B7BEBF" ratio="0.229583"/>
                        <s:GradientEntry color="#C0C6C7" ratio="0.346308"/>
                        <s:GradientEntry color="#C3C8C9" ratio="0.467033"/>
                        <s:GradientEntry color="#C4C9CA" ratio="0.704834"/>
                        <s:GradientEntry color="#CBCFD0" ratio="0.823039"/>
                        <s:GradientEntry color="#DEE0E1" ratio="0.920046"/>
                        <s:GradientEntry color="#FFFFFF" ratio="1"/>
                    </s:LinearGradient>
                </s:fill>
            </s:Path>
           
            <s:Rect width="140" height="34" x="0" y="0" d:id="12" d:userLabel="backgroundHeader" flm:variant="12">
                <s:fill>
                    <s:LinearGradient scaleX="139.94" x="0" y="16.8472">
                        <s:GradientEntry color="#004F4F" ratio="0"/>
                        <s:GradientEntry color="#003A32" ratio="0.0489363"/>
                        <s:GradientEntry color="#002B1C" ratio="0.0961603"/>
                        <s:GradientEntry color="#00210E" ratio="0.141323"/>
                        <s:GradientEntry color="#001D09" ratio="0.181319"/>
                        <s:GradientEntry color="#002715" ratio="0.316858"/>
                        <s:GradientEntry color="#003B2F" ratio="0.510989"/>
                        <s:GradientEntry color="#003224" ratio="0.662366"/>
                        <s:GradientEntry color="#001D09" ratio="0.857143"/>
                        <s:GradientEntry color="#002D20" ratio="0.915877"/>
                        <s:GradientEntry color="#004F4F" ratio="1"/>
                    </s:LinearGradient>
                </s:fill>
            </s:Rect>
            <s:Rect width="140" height="1" x="0" y="0" d:userLabel="headerPath">
                <s:fill>
                    <s:SolidColor color="#008F96"/>
                </s:fill>
            </s:Rect>
        </s:Group>
    </s:Group>
</s:ItemRenderer>

rialvalue.com/coverflow
原创粉丝点击