快捷搜索:

flex 图片展示效果

DisplayShelf.as文件如下:

package file

{

import flash.events.Event;

import flash.events.EventDispatcher;

import flash.events.KeyboardEvent;

import flash.events.MouseEvent;

import flash.events.TimerEvent;

import flash.filters.DropShadowFilter;

import flash.geom.Matrix;

import flash.ui.Keyboard;

import flash.utils.Dictionary;

import flash.utils.Timer;

import mx.collections.ArrayCollection;

import mx.collections.ICollectionView;

import mx.collections.IList;

import mx.collections.XMLListCollection;

import mx.controls.Image;

import mx.core.ClassFactory;

import mx.core.IDataRenderer;

import mx.core.IFactory;

import mx.core.UIComponent;

import mx.effects.AnimateProperty;

import mx.effects.easing.Quadratic;

import mx.events.CollectionEvent;

import mx.managers.HistoryManager;

import mx.managers.IFocusManagerComponent;

import mx.managers.IHistoryManagerClient;

// defining styles on the DisplayShelf.By defining these styles here in metadata, developers will be allowed

// to specify values for these styles as attributes on the MXML tag.Note that this component doesn't actually

// use these styles...instead, the TiltingTiles it contains use them. But this component assigns _itself_ as the

// stylename for those TiltingTile instances. That makes the tiltingTile inherit all the style values defined on this component.

// Thus by defining the styles on this component, we are automatically passing them through to the contained subcomponent.

// this is a common practice for aggregating subcomponents.

[Style(name="borderThickness", type="Number")]

[Style(name="borderColor", type="Number")]

// defining the change event. This event is dispatched whenever the selectedIndex of this component changes. By declaring it

// here, in metadata, we allow developers to specify a change handler on our MXML tag.

[Event("change")]

// defining the default property.By declaring dataProvider as our defaultProperty, we are allowing developers to specify the value of

// default property as the content of the DisplayShelf tag, without having to explciitly call it out as the value for defaultProperty.

[DefaultProperty("dataProvider")]

/* our custom component. Note a few things:

/1. we're extending UIComponent, not Canvas or some other Container. It's a common misconception that if you're going to

/have children, you must extend Container. Not True. Extend container if you want to do what containers do...namely, aggregate children

/specified in MXML...if you want easy access to a container's predefined layout algorithm...or if you want scrolling and clipping capabilities

/out of the box.Otherwise, using UIComponent as your base class is much simpler. All UIComponents can contain children for implementation purposes.

/2. We're implementing the IHistoryManagerClient interface. This allows us to save off our state whenever someone tells the history manager to save.

/we're making this component behave like the navigator classes...optionally, you can have the back button navigate back to previous selections of this component.

/3.We're implementing IFocusManager component.We do that to let the Focus Manager know that we want to accept focus and keyboard events.All of the functionality

/to do this is already supported in UICompoent, our base class...all we need to do is add this 'marker' interface, and override the keyDownHandler method to add our

/logic to interpret keystrokes.

*/

public class DisplayShelf extends UIComponent implements IHistoryManagerClient, IFocusManagerComponent

{

//---------------------------------------------------------------------------------------

// constants

//---------------------------------------------------------------------------------------

// how far, in pixels, each child will overlap when stacked sideways. This probably should be a percentage of the size of the children...i.e., overlap 1/5th...but

// we're taking a shortcut here by defining it in pixels.

private const kPaneOverlap:Number = 40;

//---------------------------------------------------------------------------------------

// private state

//---------------------------------------------------------------------------------------

// how far our selected item should 'pop' in front of the non-selected items.We'll use this value to compute a scale-down factor for

// the non-selected items.

private var _popout:Number = .43;

// storage for our data provider property. Note that we're requiring all of our dataproviders to implement the IList interface. We could have

// chosen Arrays, but then we wouldn't be able to detect when the developer added or removed items from the list. We also could have chosen

// ICollectionView, but that's a heavier interface that requires us to use cursors...something we don't really need to do.IList provides

// a nice compromise between functionality and simplicity.Note that all of the collection classes...ArrayCollection and XMLListCollection...defined

// by the framework implement the IList interface.

private var _dataProvider:IList;

// a flag to let us know when our children are dirty. We're going to be putting our children creation logic in our commitProperties function. Often

// there's more than one set of update logic that goes into commitProperties, so it's nice to store an extra flag to let you know whether a particular

// bit of updateLogic needs to be run. We'll set this flag when anything changes that requires us to regenerate our children.

private var _itemsDirty:Boolean = true;

// our array of children.These are the TiltingTiles that we'll generate, one for each item in the dataProvider.

private var _children:Array = [];

// the tilt angle for the non-selected children. This can be set by the developer.

private var _angle:Number = 35;

// the current selected index, as set by the developer.

private var _selectedIndex:Number = 0;

// the index (or rather, value, since it can be fractional) of the item at the center of our list as currently displayed. Since we animate from

// selected index to selected index when it changes, our 'current' position is different from the 'selected' position. By keeping track of this

// value, we can make sure that when we draw we're always drawing the 'current' index as it animates towards the selected index.

private var _currentPosition:Number = 0;

// a map that allows us to use an itemRenderer (actually, a tiltingTile) as a key to map back to the index of the it represents. We'll use this when

// the user clicks on one of the tilting tiles to decide what our new selected index is.We _could_ just iterate over our children list to

// find the index on click, but there are lots of use cases where you need to store extra data about an itemRenderer that can't be easily looked up.

// in those cases, Dictionaries are really useful tools. So we'll use one here just as a demonstration.

private var _itemIndexMap:Dictionary;

// a flag to control whether we want to automatically enable history management when the selected index changes.This way the component

// can be used in scenarios where it doesn't represent a 'location' to the user.

private var _enableHistory:Boolean = false;

// these are structures we'll need temporarily when calculating layout. Rather than allocating them again and again on update, we'll just allocate them

// once and hold on to them.

private var lCP:ChildPosition = new ChildPosition();

private var rCP:ChildPosition = new ChildPosition();

// the selected index, clamped to the range defined by the dataProvider. We store this separate from the actual selected index as assigned by the developer.

// we want to calculate it only once and then store it off. But if we stored it back into our selected index property, we'd need to worry about scenarios where

// the selectedIndex gets assigned before the dataprovider does. So we store it in a separate variable, so as not to trample the 'true' selected index.

private var _safeSelectedIndex:Number;

// storage for the item renderer factory, that will generate item renderer interfaces for us as necessary.

private var _itemRenderer:IFactory;

// the effect we'll use to animate from old to new selected index.If the user changes selected index in the middle of an animation, we'll want to cancel

// the old one, so we keep a reference to it.

private var _animation:AnimateProperty;

// whether or not we should automatically select a child when the user clicks on a particular item.It's generally good practice to avoid hard coding UI gestures

// into your component if you can avoid it...if possible, a good component will provide a default UI gesture, a way to disable it, and a programmatic way to

// build an alternate UI gesture. In this case, by default we select an item on click, we allow the developer to turn that off, and we allow the developer to

// set the selectedIndex programmatically so they can select on, say mouse over.

private var _selectOnClick:Boolean = true;

//---------------------------------------------------------------------------------------

// constructor

//---------------------------------------------------------------------------------------

public function DisplayShelf()

{

super();

// define a default empty dataprovider. Rather than deal with this property being null, it's easiest to always

// assume there's something, and substitute empty 'somethings' for null dataproviders.

dataProvider = new ArrayCollection();

// we register with the history manager to let it know that we will want to save state whenever someone tells the history manager to remember

// the current state of the application.

HistoryManager.register(this);

_itemIndexMap = new Dictionary(true);

// set up a default item renderer. We could require the developer to always specify one, but if we've got an 80% use case, it's nice to define

// a default one.Note that this does force the compiler to link in the Image class, even if the developer turns around and redefines the itemRenderer

// property, so there is a potential price to pay in application size. Chances are pretty good the developer is using Image somewhere though.

_itemRenderer = new ClassFactory(Image);

}

//---------------------------------------------------------------------------------------

// public properties

//---------------------------------------------------------------------------------------

/*True if the developer wants us to automatically save changes to the selectedIndex in the history manager or not.

*/

public function set enableHistory(value:Boolean):void

{

_enableHistory = value;

}

public function get enableHistory():Boolean

{

return _enableHistory;

}

/*How far out the selected item should 'pop' from the background items.A value of 0 doesn't pop it out at all, while a value of 1 will receed

* the background items infinitely to the horizon.Basically, the value is inverted and used as a scale factor for the background items.

* pick something appropriate.

* FWIW, now that I look at this, it really should be a style, not a property

*/

[Bindable] public function set popout(value:Number):void

{

_popout = value;

/*Being a good flex component, we don't want to recalculate every time someone changes this value. Instead, we store the change,

*and invalidate so we'll get to redrew the next time the screen is going to be updated.

*/

invalidateDisplayList();

}

public function get popout():Number

{

return _popout;

}

/* the index of the currently selected item in the dataProvider.Note that since this component animates its position, this is not necessarily the

* same as the item we are currently looking at. We might be in the middle of animating towards the selected item.

* note that since we are going to dispatch a well defined, named event when this value changes, we specify that

* event in the binding metadata. That let's flex know that we're going to be reponsible for dispatching the event ourselves.

* Otherwise the binding metadata would result in _another_ event being dispatched, which would be wasteful.

*/

[Bindable("change")]

public function set selectedIndex(value:Number):void

{

// save time and performancing by doing nothing if the selected index is already the new value.

if(_selectedIndex == value)

return;

// store off the new value.

_selectedIndex = value;

// since we are going to use this value to index into the item renderers, we want to make sure we don't use a value outside the range of

// existing renderers. Rather than having to liter our code with those checks all over the place, we'll clamp it to the legal range once now

// and store off the 'safe' value.

_safeSelectedIndex = Math.max(0,Math.min(_selectedIndex,_children.length-1));

// dispatch an event letting listeners know that

dispatchEvent(new Event("change"));

// when the selected index changes, we'll want to kick-start our animation.

startAnimation();

// tell the history manager that something significant to the history has changed.

if(_enableHistory)

HistoryManager.save();

}

public function get selectedIndex():Number

{

return _selectedIndex;

}

/* This property represents the current position in the child items that our component is looking at.

* All of our rendering is done off of this property. By exposing it as a public property, we can animate

* it, which means that even though we're incorporating animation, our rendering will always be in sync

* with the internal state of our application

*/

public function set currentPosition(value:Number):void

{

_currentPosition = value;

invalidateDisplayList();

}

public function get currentPosition():Number

{

return _currentPosition;

}

/* where we're getting our data from.We're going to follow the flex SDK convention of leaving our dataProvider property

* untyped, and automatically wrapping raw Arrays and XMLLists as a convenience. For this component, we're going to require

* that our dataProvider either implement the IList interface, or be something we can convert into an IList implementation.

*/

[Bindable] public function set dataProvider(value:Object):void

{

/* first, if we have a previous dataProvider, we're going to want to remove any event listeners from it

*/

if(_dataProvider != null)

{

_dataProvider.removeEventListener(CollectionEvent.COLLECTION_CHANGE,dataChangeHandler,false);

}

/* Now, as a convenience to the caller, convert our dataProvider into an IList implementation */

if (value is Array)

{

_dataProvider = new ArrayCollection(value as Array);

}

else if (value is IList)

{

_dataProvider = IList(value);

}

else if (value is XMLList)

{

_dataProvider = new XMLListCollection(value as XMLList);

}

/*Add an event listener so we know and can react when our dataProvider changes. Note that the convention in flex is that

* list-like components are only responsible for detecting and reacting to changes in the list itself, _not_ changes

* to the properties of the items themselves.It's the responsibility of the item renderers to do that as necessary.

*

* Also, note that we're using a weak listener here. Since the data provider is being passed in by an external caller,

* we don't know what the lifetime of the dataProvider is w/relation to our lifetime. Since we don't have a constructor,

* we won't ever get a chance to remove our listener. So we use a weak listener to make sure we don't get locked into

* memory by this.

*/

_dataProvider.addEventListener(CollectionEvent.COLLECTION_CHANGE,dataChangeHandler,false,0,true);

/* since we now need to re-allocate our item renderers, we'll set a flag and invalidate our properties.As with layout and size,

* by putting the item renderer generation into commitProperties, we avoid having to run it too often

*/

_itemsDirty = true;

invalidateProperties();

/*Our measured size is dependent on our number and size of items in the dataProvider, so we need to invalidate it here*/

invalidateSize();

}

public function get dataProvider():Object

{

return _dataProvider;

}

/* The UIComponent that we'll use to render our items.Since we need to create multiple of these...one for each item in the

* dataprovider...we need not an itemRenderer, but a _factory_ that can create itemRenderers on demand.That's why we type

* this property as an IFactory. IFactory is a special interface that signals to the compiler that we need an object that implements

* the factory pattern. When the MXML compiler sees a property of type IFactory, it allows the developer specify it's value in one

* of three ways:

* By specifying an object that implements the IFactory interface (that's normal).

* By specifying the name of a class...it automatically wraps the class in an instance of ClassFactory and assigns that to the property.

* By defining a component inline via ...it defines an implicit class, wraps it in a ClassFactory instance, and assigns that.

*/

public function set itemRenderer(value:IFactory):void

{

_itemRenderer = value;

/* store off the value, and set the flag to say that we need to re-generate all of our item renderers*/

_itemsDirty = true;

invalidateProperties();

invalidateSize();

}

public function get itemRenderer():IFactory

{

return _itemRenderer;

}

/* The angle of the background non-selected items*/

public function set angle(value:Number):void

{

_angle = value;

invalidateDisplayList();

}

public function get angle():Number

{

return _angle;

}

/* whether or not we should automatically select a child when the user clicks on a particular item.It's generally good practice to avoid hard coding UI gestures

* into your component if you can avoid it...if possible, a good component will provide a default UI gesture, a way to disable it, and a programmatic way to

* build an alternate UI gesture. In this case, by default we select an item on click, we allow the developer to turn that off, and we allow the developer to

* set the selectedIndex programmatically so they can select on, say mouse over.

*/

public function set selectOnClick(value:Boolean):void

{

_selectOnClick = value;

}

public function get selectOnClick():Boolean

{

return _selectOnClick;

}

//---------------------------------------------------------------------------------------

// property management

//---------------------------------------------------------------------------------------

/* this is the standard function where components put performance intensive computations and side-effects

* from changes to their properties.By calling invalidateProperties(), a component guarantees that this function

* will get called by the layout manager before the next time the screen is going to be updated, before their

* measure() or updateDisplayList() functions are called (if necessary).Note that there is no guarantee about the

* order in which commitProperties is called from component to component (i.e., it's not parent before child or vice versa).

*/

override protected function commitProperties():void

{

/*as components get more and more complicated, this function often grows to do more and more processing.

* as a performance optimization, it's usually good to put guards around different computations to make sure

* you're only re-calculating what you need to on any given pass. In this case, we've defined a flag to let us

* know when something has changed that requires us to regenerate our item renderers.

*

* When a component creates children/sub-components, there's generally two places it should consider doing it.

* For 'static' sub components, that don't come and go as the component is used, it's best to create them in the

* createChildren() function.But for children that are created and destroyed as the component is used,

* it's best to muck with them in the commitProperties() function. Adding children to a component automatically

* invalidates its size and display.Since commit properties runs before measure() and updateDisplayList() runs,

* adding children here won't accidentally trigger _another_ validation pass, which would happen if you tried to create them

* in updateDisplayList().

*/

if(_itemsDirty)

{

_itemsDirty = false;

/* we're going to create an item renderer for each item in the data provider */

/*first, let's clear out our old item renderers.Now this is horribly inefficient...if, say, the

* developer just added a single item to the data provider, there's no reason we need to throw all the

* old ones away. But we're going to do it for simplicity's sake here. In your code, be more efficient ;)

*/

for(i = numChildren-1;i>=0;i--)

{

removeChildAt(numChildren-1);

}

/* clear out our children list and child -> index map, since we just threw away all of our children */

_itemIndexMap = new Dictionary(true);

_children = [];

for(var i:int = 0;imxml文件如下:

img/photos400/photo01.jpg

img/photos400/photo02.jpg

img/photos400/photo03.jpg

img/photos400/photo04.jpg

img/photos400/photo05.jpg

img/photos400/photo06.jpg

img/photos400/photo07.jpg

img/photos400/photo08.jpg

img/photos400/photo09.jpg

img/photos400/photo10.jpg

img/photos400/photo11.jpg

img/photos400/photo12.jpg

img/photos400/photo13.jpg

img/photos400/photo14.jpg

img/photos400/photo15.jpg

img/photos400/photo16.jpg

img/photos400/photo17.jpg

img/photos400/photo18.jpg

img/photos400/photo19.jpg

-->

您可能还会对下面的文章感兴趣: