PageRenderTime 48ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/com/custardbelly/as3flobile/controls/list/ScrollList.as

http://github.com/bustardcelly/as3flobile
ActionScript | 1114 lines | 600 code | 124 blank | 390 comment | 60 complexity | 4ec8dba111e171bc1c45a270a7a5f997 MD5 | raw file
  1. /**
  2. * <p>Original Author: toddanderson</p>
  3. * <p>Class File: ScrollList.as</p>
  4. * <p>Version: 0.4</p>
  5. *
  6. * <p>Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:</p>
  12. *
  13. * <p>The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.</p>
  15. *
  16. * <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.</p>
  23. *
  24. * <p>Licensed under The MIT License</p>
  25. * <p>Redistributions of files must retain the above copyright notice.</p>
  26. */
  27. package com.custardbelly.as3flobile.controls.list
  28. {
  29. import com.custardbelly.as3flobile.controls.core.AS3FlobileComponent;
  30. import com.custardbelly.as3flobile.controls.list.layout.IScrollListLayout;
  31. import com.custardbelly.as3flobile.controls.list.layout.ScrollListVerticalLayout;
  32. import com.custardbelly.as3flobile.controls.list.renderer.DefaultScrollListItemRenderer;
  33. import com.custardbelly.as3flobile.controls.list.renderer.IScrollListItemRenderer;
  34. import com.custardbelly.as3flobile.controls.viewport.IScrollViewport;
  35. import com.custardbelly.as3flobile.controls.viewport.ScrollViewport;
  36. import com.custardbelly.as3flobile.controls.viewport.context.BaseScrollViewportStrategy;
  37. import com.custardbelly.as3flobile.controls.viewport.context.IScrollViewportContext;
  38. import com.custardbelly.as3flobile.controls.viewport.context.ScrollViewportMouseContext;
  39. import com.custardbelly.as3flobile.helper.ITapMediator;
  40. import com.custardbelly.as3flobile.helper.MouseTapMediator;
  41. import com.custardbelly.as3flobile.skin.ScrollListSkin;
  42. import flash.display.DisplayObject;
  43. import flash.display.Graphics;
  44. import flash.display.InteractiveObject;
  45. import flash.display.Sprite;
  46. import flash.events.Event;
  47. import flash.events.MouseEvent;
  48. import flash.geom.Point;
  49. import flash.geom.Rectangle;
  50. import flash.utils.getDefinitionByName;
  51. import flash.utils.getQualifiedClassName;
  52. import org.osflash.signals.DeluxeSignal;
  53. import org.osflash.signals.events.GenericEvent;
  54. /**
  55. * ScrollList is a display component that allows you to scroll through a list of items using a mouse or touch gesture.
  56. * @author toddanderson
  57. */
  58. public class ScrollList extends AS3FlobileComponent implements IScrollListContainer, IScrollListLayoutTarget
  59. {
  60. protected var _listHolder:ScrollListHolder;
  61. protected var _bounds:Rectangle;
  62. protected var _viewport:IScrollViewport;
  63. protected var _itemRenderer:String;
  64. protected var _tapMediator:ITapMediator;
  65. protected var _layout:IScrollListLayout;
  66. protected var _scrollContext:IScrollViewportContext;
  67. protected var _cells:Vector.<IScrollListItemRenderer>;
  68. protected var _cellAmount:int;
  69. protected var _seperatorLength:int;
  70. protected var _currentScrollPosition:Point;
  71. protected var _isScrolling:Boolean;
  72. protected var _selectionEnabled:Boolean;
  73. protected var _selectedRenderer:IScrollListItemRenderer;
  74. protected var _selectedIndex:int = -1;
  75. protected var _labelField:String = "label";
  76. protected var _dataProvider:Array;
  77. /* Signals */
  78. protected var _scrollStart:DeluxeSignal;
  79. protected var _scrollEnd:DeluxeSignal;
  80. protected var _scrollChange:DeluxeSignal;
  81. protected var _selectionChange:DeluxeSignal;
  82. protected var _signalEvent:GenericEvent;
  83. /**
  84. * Constructor.
  85. */
  86. public function ScrollList()
  87. {
  88. // Get default scroll context.
  89. _scrollContext = getDefaultScrollContext();
  90. super();
  91. }
  92. /**
  93. * Static factory method to create a new instance of ScrollList with default properties.
  94. * @param bounds Rectangle The rectangular area to be shown by the list.
  95. * @return ScrollList
  96. */
  97. public static function initWithScrollRect( bounds:Rectangle ):ScrollList
  98. {
  99. var list:ScrollList = new ScrollList();
  100. list.width = bounds.width;
  101. list.height = bounds.height;
  102. return list;
  103. }
  104. /**
  105. * @inherit
  106. */
  107. override protected function initialize():void
  108. {
  109. super.initialize();
  110. _width = 100;
  111. _height = 100;
  112. updatePadding( 2, 2, 2, 2 );
  113. _seperatorLength = 2;
  114. _selectionEnabled = true;
  115. _bounds = new Rectangle( 0, 0, _width, _height );
  116. _currentScrollPosition = new Point( 0, 0 );
  117. _cells = new Vector.<IScrollListItemRenderer>()
  118. _itemRenderer = getQualifiedClassName( DefaultScrollListItemRenderer );
  119. _layout = getDefaultLayout();
  120. _skin = new ScrollListSkin();
  121. _skin.target = this;
  122. _scrollStart = new DeluxeSignal( this );
  123. _scrollEnd = new DeluxeSignal( this );
  124. _scrollChange = new DeluxeSignal( this );
  125. _selectionChange = new DeluxeSignal( this );
  126. _signalEvent = new GenericEvent();
  127. }
  128. /**
  129. * @inherit
  130. */
  131. override protected function createChildren():void
  132. {
  133. // List holder will be managed by this ScrollList instance, but actually be on the display list of the viewport.
  134. createListHolderIfNotExist();
  135. _listHolder.mouseChildren = false;
  136. _listHolder.cacheAsBitmap = true;
  137. // Create the viewport and point to the list holder target.
  138. var horizPadding:int = ( _padding.left + _padding.right );
  139. var vertPadding:int = ( _padding.top + _padding.bottom );
  140. _viewport = new ScrollViewport();
  141. _viewport.scrollStart.add( scrollViewDidStart );
  142. _viewport.scrollChange.add( scrollViewDidAnimate );
  143. _viewport.scrollEnd.add( scrollViewDidEnd );
  144. _viewport.context = _scrollContext;
  145. _viewport.content = _listHolder;
  146. _viewport.width = _width - horizPadding;
  147. _viewport.height = _height - vertPadding;
  148. _viewport.x = _padding.left;
  149. _viewport.y = _padding.top;
  150. addChild( _viewport as DisplayObject );
  151. _tapMediator = getDefaultTapMediator( _listHolder, handleListTap );
  152. }
  153. /**
  154. * @private
  155. *
  156. * If not instantiated, creates an instance of a ScrollListHolder and returns the reference.
  157. * @return ScrollListHolder
  158. */
  159. protected function createListHolderIfNotExist():ScrollListHolder
  160. {
  161. // Create if not exists.
  162. if( _listHolder == null )
  163. _listHolder = new ScrollListHolder();
  164. // Return instance.
  165. return _listHolder;
  166. }
  167. /**
  168. * @private
  169. *
  170. * Factory method to return default IScrollViewportContext implementation used.
  171. * @return IScrollViewportContext
  172. */
  173. protected function getDefaultScrollContext():IScrollViewportContext
  174. {
  175. return new ScrollViewportMouseContext( new BaseScrollViewportStrategy() );
  176. }
  177. /**
  178. * @private
  179. *
  180. * Factory method to return default ITapMediator implementation used for tap gesture for list selection.
  181. * @param display InteractiveObject The interactive display to listen for events on that represent a tap.
  182. * @param tapHandler Function The handler method to invoke upon notification of a tap gesture.
  183. * @return ITapMediator
  184. */
  185. protected function getDefaultTapMediator( display:InteractiveObject, tapHandler:Function ):ITapMediator
  186. {
  187. return new MouseTapMediator();
  188. }
  189. /**
  190. * @private
  191. *
  192. * Factory method to return default IScrollListLayout used to display item renderers.
  193. * @return IScrollListLayout
  194. */
  195. protected function getDefaultLayout():IScrollListLayout
  196. {
  197. var layout:IScrollListLayout = new ScrollListVerticalLayout();
  198. layout.target = this;
  199. return layout;
  200. }
  201. /**
  202. * @private
  203. *
  204. * Runs a refresh on the display.
  205. */
  206. protected function resetToOriginalState():void
  207. {
  208. // Reset content holder display.
  209. _currentScrollPosition = new Point( 0, 0 );
  210. _listHolder.x = _currentScrollPosition.x;
  211. _listHolder.y = _currentScrollPosition.y;
  212. // Unselect any selected item renderer instances.
  213. var selectedItemRenderer:IScrollListItemRenderer = ( _selectedIndex >= 0 ) ? _cells[_selectedIndex] : null;
  214. if( selectedItemRenderer )
  215. selectedItemRenderer.selected = false;
  216. // Run refresh on display.
  217. invalidateDisplay();
  218. }
  219. /**
  220. * @private
  221. *
  222. * Validates the new size applied to this instance.
  223. */
  224. override protected function invalidateSize():void
  225. {
  226. super.invalidateSize();
  227. var horizPadding:int = ( _padding.left + _padding.right );
  228. var vertPadding:int = ( _padding.top + _padding.bottom );
  229. // Set new scroll rect area.
  230. _bounds.width = _width - horizPadding;
  231. _bounds.height = _height - vertPadding;
  232. // Apply new values to the viewport instance.
  233. _viewport.width = _width - horizPadding;
  234. _viewport.height = _height - vertPadding;
  235. _viewport.x = _padding.left;
  236. _viewport.y = _padding.top;
  237. // Update visible dimensions on scroll list holder
  238. _listHolder.visibleWidth = _width - horizPadding;
  239. _listHolder.visibleHeight = _height - vertPadding;
  240. // Run refresh on display.
  241. invalidateDisplay();
  242. }
  243. /**
  244. * @inherit
  245. */
  246. override protected function invalidateEnablement( oldValue:Boolean, newValue:Boolean ):void
  247. {
  248. super.invalidateEnablement( oldValue, newValue );
  249. _viewport.enabled = _enabled;
  250. }
  251. /**
  252. * @private
  253. *
  254. * Validate the new data provider applied to this instance.
  255. * @param oldValue Array An Array of Object. The previously applied data provider (if available).
  256. * @param newValue Array An Array of Object. The newly applied data provider.
  257. */
  258. protected function invalidateDataProvider( oldValue:Array, newValue:Array ):void
  259. {
  260. // null out previous selection.
  261. _selectedIndex = -1;
  262. invalidateSelection();
  263. // Hold easy reference to the amount of new data.
  264. _cellAmount = ( _dataProvider ) ? _dataProvider.length : 0;
  265. // Remove all renderers.
  266. while( _listHolder.numChildren > 0 )
  267. {
  268. _listHolder.removeChildAt( 0 );
  269. }
  270. // If we had no old value, fill as normal.
  271. if( oldValue == null )
  272. {
  273. // Fills the cell list with factory created item renderers based on data provider.
  274. fillRendererQueue( _cells, _dataProvider.length );
  275. }
  276. // Else if dataProvider has come in as null, clear all.
  277. else if( newValue == null )
  278. {
  279. removeFromRendererQueue( _cells, oldValue.length );
  280. }
  281. // Else if we had an old value, determine if we need to shrink or grow our pool of cells.
  282. else if( oldValue.length != newValue.length )
  283. {
  284. // If there are more data representations of cells than previously, grow our pool.
  285. if( oldValue.length < newValue.length )
  286. {
  287. addToRendererQueue( _cells, newValue.length - oldValue.length );
  288. }
  289. // Else if there are less data representation of cells than previously, shrink our pool.
  290. else
  291. {
  292. removeFromRendererQueue( _cells, oldValue.length - newValue.length );
  293. }
  294. }
  295. // Run a refresh.
  296. resetToOriginalState();
  297. _viewport.reset();
  298. }
  299. /**
  300. * @private
  301. *
  302. * Validates the new item renderer applied to this instance.
  303. */
  304. protected function invalidateItemRenderer():void
  305. {
  306. // Clean and refill with new item renderers.
  307. cleanRefill();
  308. // Refresh.
  309. invalidateDisplay();
  310. }
  311. /**
  312. * @private
  313. *
  314. * Validates the update to labelField for each item renderer.
  315. */
  316. protected function invalidateLabelField():void
  317. {
  318. var i:int = _cells.length;
  319. var renderer:IScrollListItemRenderer;
  320. while( --i > -1 )
  321. {
  322. renderer = _cells[i] as IScrollListItemRenderer;
  323. renderer.labelField = _labelField;
  324. }
  325. }
  326. /**
  327. * @private
  328. *
  329. * Validates the IScrollViewportContext implementation applied to this instance.
  330. */
  331. protected function invalidateScrollContext():void
  332. {
  333. // If we have a viewport set, apply the new context.
  334. if( _viewport != null )
  335. {
  336. _viewport.context = _scrollContext;
  337. }
  338. }
  339. /**
  340. * @private
  341. *
  342. * Validates the IScrollListLayout applied to this instance.
  343. */
  344. protected function invalidateLayout():void
  345. {
  346. // Set the target to this instance.
  347. _layout.target = this;
  348. // Run refresh.
  349. resetToOriginalState();
  350. }
  351. /**
  352. * @private
  353. *
  354. * Validates the current display.
  355. */
  356. protected function invalidateDisplay():void
  357. {
  358. // Notify the layout of update to display.
  359. _layout.updateDisplay();
  360. // Set bounds of content holder.
  361. _listHolder.height = getContentHeight();
  362. _listHolder.width = getContentWidth();
  363. // Update the visual display.
  364. updateDisplay();
  365. // Run refresh on viewport.
  366. _viewport.refresh();
  367. // Show the cells based on display properties.
  368. showCells();
  369. }
  370. /**
  371. * @private
  372. *
  373. * Validates the selected item of this instance based on selected index.
  374. */
  375. protected function invalidateSelection():void
  376. {
  377. // Unselect any previously selected item renderer(s).
  378. if( _selectedRenderer )
  379. {
  380. _selectedRenderer.selected = false;
  381. _selectedRenderer = null;
  382. }
  383. // Set selection on item renderer based on selected index.
  384. if( _selectedIndex >= 0 && _selectedIndex < _cells.length )
  385. {
  386. _selectedRenderer = _cells[_selectedIndex];
  387. _selectedRenderer.selected = true;
  388. }
  389. }
  390. /**
  391. * @private
  392. *
  393. * Validates the ability to make a selction within the list.
  394. */
  395. protected function invalidateSelectionEnablement():void
  396. {
  397. if( _tapMediator.isMediating( _listHolder ) )
  398. {
  399. if( _selectionEnabled )
  400. {
  401. _tapMediator.mediateTapGesture( _listHolder, handleListTap );
  402. }
  403. else
  404. {
  405. _tapMediator.unmediateTapGesture( _listHolder );
  406. }
  407. }
  408. }
  409. /**
  410. * @private
  411. *
  412. * Cleans display and queues of item renderers and performs a refill of those items based on dataProvider.
  413. * @see #refresh()
  414. * @see #invalidateItemRenderer()
  415. */
  416. protected function cleanRefill():void
  417. {
  418. // null out previous selection.
  419. _selectedIndex = -1;
  420. invalidateSelection();
  421. // Remove all renderers.
  422. while( _listHolder.numChildren > 0 )
  423. _listHolder.removeChildAt( 0 );
  424. // Remove cells from list.
  425. while( _cells.length > 0 )
  426. _cells.pop();
  427. // Fill cells in list.
  428. fillRendererQueue( _cells, ( _dataProvider ) ? _dataProvider.length : 0 );
  429. }
  430. /**
  431. * @private
  432. *
  433. * Factory method to create the IScrollListItemRenderer instance based on the item renderer class.
  434. * @return IScrollListItemRenderer
  435. */
  436. protected function createItemRenderer():IScrollListItemRenderer
  437. {
  438. var rendererClass:Class = getDefinitionByName( _itemRenderer ) as Class;
  439. var renderer:IScrollListItemRenderer = new rendererClass() as IScrollListItemRenderer;
  440. return renderer;
  441. }
  442. /**
  443. * @private
  444. *
  445. * Fills a list with IScrollListItemRenderer instances created from factory method on item renderer class.
  446. * @param queue Vector.<IScrolListRenderer> The list to fill with newly created instances of IScrollListItemRenderer.
  447. * @param amount int The amount to add to the list.
  448. * @see #createItemRenderer
  449. */
  450. protected function fillRendererQueue( queue:Vector.<IScrollListItemRenderer>, amount:int ):void
  451. {
  452. var i:int = amount;
  453. var renderer:IScrollListItemRenderer;
  454. while( --i > -1 )
  455. {
  456. renderer = createItemRenderer();
  457. renderer.labelField = _labelField;
  458. queue[queue.length] = renderer;
  459. }
  460. }
  461. /**
  462. * @private
  463. *
  464. * Appends item renderers to the list of IScrollListItemRenderer.
  465. * @param queue Vector.<IScrollListItemRenderer> The list to add a new instance to.
  466. * @param amount int The amount of item renderer instances to add to the list.
  467. */
  468. protected function addToRendererQueue( queue:Vector.<IScrollListItemRenderer>, amount:int ):void
  469. {
  470. var length:int = queue.length + amount;
  471. var renderer:IScrollListItemRenderer;
  472. while( queue.length < length )
  473. {
  474. renderer = createItemRenderer();
  475. renderer.labelField = _labelField;
  476. queue[queue.length] = renderer
  477. }
  478. }
  479. /**
  480. * @private
  481. *
  482. * Removes item renderes from the list of IScrollListItemRenderer.
  483. * @param queue Vector.<IScrollListItemRenderer> The list to remove instances from.
  484. * @param amount int The amount of item renderer instances to remove.
  485. */
  486. protected function removeFromRendererQueue( queue:Vector.<IScrollListItemRenderer>, amount:int ):void
  487. {
  488. var length:int = queue.length - amount;
  489. length = ( length < 0 ) ? 0 : length;
  490. while( queue.length > length )
  491. queue.pop();
  492. }
  493. /**
  494. * @private
  495. *
  496. * Returns the height of the actual content within the list. This does not represent the height of content on the display list.
  497. * This value represents the dimension vertically that can be scrolled to.
  498. * @return Number
  499. */
  500. protected function getContentHeight():Number
  501. {
  502. return ( _layout ) ? _layout.getContentHeight() : _width;
  503. }
  504. /**
  505. * @private
  506. *
  507. * Returns the width of the actual content within the list. This does not represent the width of content on the display list.
  508. * This value respresents the dimension horizontally that can be scrolled to.
  509. * @return Number
  510. */
  511. protected function getContentWidth():Number
  512. {
  513. return ( _layout ) ? _layout.getContentWidth() : _height;
  514. }
  515. /**
  516. * @private
  517. *
  518. * Shows the item renderer instances based on scroll position.
  519. */
  520. protected function showCells():void
  521. {
  522. // Invoke layout to find cells within area based on scroll position.
  523. _layout.updateScrollPosition();
  524. }
  525. /**
  526. * @inherit
  527. */
  528. override protected function addDisplayHandlers():void
  529. {
  530. super.addDisplayHandlers();
  531. if( _enabled && _selectionEnabled )
  532. _tapMediator.mediateTapGesture( _listHolder, handleListTap );
  533. }
  534. /**
  535. * @inherit
  536. */
  537. override protected function removeDisplayHandlers():void
  538. {
  539. super.removeDisplayHandlers();
  540. if( _tapMediator.isMediating( _listHolder ) )
  541. _tapMediator.unmediateTapGesture( _listHolder );
  542. }
  543. /**
  544. * Signal handler for start of scroll in viewport.
  545. * @param Position
  546. */
  547. protected function scrollViewDidStart( position:Point ):void
  548. {
  549. _currentScrollPosition = position;
  550. scrollStart.dispatch( _signalEvent );
  551. }
  552. /**
  553. * Signal handler for change in scroll from viewport.
  554. * @param Point
  555. */
  556. protected function scrollViewDidAnimate( position:Point ):void
  557. {
  558. _isScrolling = true;
  559. _currentScrollPosition = position;
  560. scrollChange.dispatch( _signalEvent );
  561. showCells();
  562. }
  563. /**
  564. * Signal handler for end of scroll from viewport.
  565. * @param Point
  566. */
  567. protected function scrollViewDidEnd( position:Point ):void
  568. {
  569. _isScrolling = false;
  570. _currentScrollPosition = position;
  571. scrollEnd.dispatch( _signalEvent );
  572. }
  573. /**
  574. * @private
  575. *
  576. * Event handler for tap gesture on content. Determines the selected index within the list.
  577. * @param evt Event
  578. */
  579. protected function handleListTap( evt:Event ):void
  580. {
  581. var tapEvent:MouseEvent = evt as MouseEvent;
  582. var index:int = _layout.getChildIndexAtPosition( tapEvent.localX, tapEvent.localY );
  583. selectedIndex = index;
  584. }
  585. /**
  586. * @copy IScrollListContainer#getRendererAt()
  587. */
  588. public function getRendererAt( index:uint ):IScrollListItemRenderer
  589. {
  590. return _cells[index];
  591. }
  592. /**
  593. * @copy IScrollListContainer#scrollPositionToIndex()
  594. */
  595. public function scrollPositionToIndex( index:uint, select:Boolean = false ):void
  596. {
  597. var position:Point = _layout.getPositionFromIndex( index );
  598. _viewport.scrollToPosition( position );
  599. // Update selection based on flag.
  600. if( select ) selectedIndex = index;
  601. }
  602. /**
  603. * Adds an item renderer to the display. The IScrollListLayout instance uses this method to add an instance to the list display.
  604. * Typically you will not call this method directly on a list unless from a IScrollListLayout instance managing the children of the display list.
  605. * @param renderer IScrollListItemRenderer
  606. */
  607. public function addRendererToDisplay( renderer:IScrollListItemRenderer ):void
  608. {
  609. // Create the list holder if it doesn't exist. the layout can start populating its display list prior to being add to the stage.
  610. createListHolderIfNotExist();
  611. if( _listHolder.contains( renderer as DisplayObject ) )
  612. ( renderer as DisplayObject ).visible = true;
  613. else
  614. _listHolder.addChild( renderer as DisplayObject );
  615. }
  616. /**
  617. * Removes an item renderer from the display. The IScrollListLayout instance uses this method to remove an instance from the list display.
  618. * Typically you will not call this method directly on a list unless from a IScrollListLayout instance managing the children of the display list.
  619. * @param renderer IScrollListItemRenderer
  620. */
  621. public function removeRendererFromDisplay( renderer:IScrollListItemRenderer ):void
  622. {
  623. // Create the list holder if it doesn't exist. the layout can start populating its display list prior to being add to the stage.
  624. createListHolderIfNotExist();
  625. if( _listHolder.contains( renderer as DisplayObject ) )
  626. ( renderer as DisplayObject ).visible = false;
  627. }
  628. /**
  629. * @copy IScrollListLayoutTarget#commitContentChange()
  630. */
  631. public function commitContentChange():void
  632. {
  633. // Set bounds of content holder.
  634. if( _listHolder )
  635. {
  636. _listHolder.height = getContentHeight();
  637. _listHolder.width = getContentWidth();
  638. }
  639. // Update the visual display.
  640. updateDisplay();
  641. // Run refresh on viewport.
  642. if( _viewport ) _viewport.refresh();
  643. // Show the cells based on display properties.
  644. if( _layout ) showCells();
  645. }
  646. /**
  647. * @copy IScrollListContainer#refresh()
  648. */
  649. public function refresh():void
  650. {
  651. // Clean and refill with new item renderer data.
  652. cleanRefill();
  653. // Reset list to original properties (ie. scroll position).
  654. resetToOriginalState();
  655. // Reset viewport to origin.
  656. _viewport.reset();
  657. }
  658. /**
  659. * @copy IScrollListContainer#startScroll
  660. */
  661. public function get scrollStart():DeluxeSignal
  662. {
  663. return _scrollStart;
  664. }
  665. /**
  666. * @copy IScrollListContainer#endScroll
  667. */
  668. public function get scrollEnd():DeluxeSignal
  669. {
  670. return _scrollEnd;
  671. }
  672. /**
  673. * @copy IScrollListContainer#scroll
  674. */
  675. public function get scrollChange():DeluxeSignal
  676. {
  677. return _scrollChange;
  678. }
  679. /**
  680. * @copy IScrollListContainer#select
  681. */
  682. public function get selectionChange():DeluxeSignal
  683. {
  684. return _selectionChange;
  685. }
  686. /**
  687. * Returns the list of IScrollListItemRenderer instances.
  688. * @return Vector.<IScrollListItemRenderer>
  689. */
  690. public function get renderers():Vector.<IScrollListItemRenderer>
  691. {
  692. return _cells;
  693. }
  694. /**
  695. * Returns the length of the list of IScrollListItemRenderer instances.
  696. * @return int
  697. */
  698. public function get rendererAmount():int
  699. {
  700. return _cells.length;
  701. }
  702. /**
  703. * Returns the current scroll position of the display list.
  704. * @return Point
  705. */
  706. public function get scrollPosition():Point
  707. {
  708. return _currentScrollPosition;
  709. }
  710. /**
  711. * @inherit
  712. */
  713. override public function dispose():void
  714. {
  715. super.dispose();
  716. // Empty list.
  717. _cells = new Vector.<IScrollListItemRenderer>();
  718. // Empty display list.
  719. while( _listHolder.numChildren > 0 )
  720. _listHolder.removeChildAt( 0 );
  721. // Unmediate on tap gesture.
  722. if( _tapMediator && _tapMediator.isMediating( _listHolder ) )
  723. _tapMediator.unmediateTapGesture( _listHolder );
  724. _tapMediator = null;
  725. // Dispose of layout manager.
  726. _layout.dispose();
  727. _layout = null;
  728. // Dispose of viewport display.
  729. _viewport.dispose();
  730. _viewport = null;
  731. // Null reference to any selected item.
  732. _selectedRenderer = null;
  733. // Null reference to signals.
  734. _scrollStart.removeAll();
  735. _scrollStart = null;
  736. _scrollEnd.removeAll();
  737. _scrollEnd = null;
  738. _scrollChange.removeAll();
  739. _scrollChange = null;
  740. _selectionChange.removeAll();
  741. _selectionChange = null;
  742. }
  743. /**
  744. * @inherit
  745. *
  746. * Override to set the display area for the list.
  747. * @param value Rectangle
  748. */
  749. public function get scrollBounds():Rectangle
  750. {
  751. return _bounds;
  752. }
  753. /**
  754. * Accessor for the background display that can be used in the skinning process.
  755. * @return Shape
  756. */
  757. public function get backgroundDisplay():Graphics
  758. {
  759. return graphics;
  760. }
  761. /**
  762. * Accessor/Modifier for the seperator size between list items.
  763. * @return int
  764. */
  765. public function get seperatorLength():int
  766. {
  767. return _seperatorLength;
  768. }
  769. public function set seperatorLength(value:int):void
  770. {
  771. if( _seperatorLength == value ) return;
  772. _seperatorLength = ( value < 0 ) ? 0 : value;
  773. invalidate( invalidateDisplay );
  774. }
  775. /**
  776. * Accessor/Modifier for the layout manager for the item renderers in the list.
  777. * @return IScrollListLayout
  778. */
  779. public function get layout():IScrollListLayout
  780. {
  781. return _layout;
  782. }
  783. public function set layout( value:IScrollListLayout ):void
  784. {
  785. if( _layout == value ) return;
  786. // Clear old layout.
  787. if( _layout != null ) _layout.dispose();
  788. _layout = value;
  789. invalidateAt( invalidateLayout, 0, null );
  790. }
  791. /**
  792. * Accessor/Modifier for the viewport context that manages user gestures and animation of display.
  793. * @return IScrollViewportContext
  794. */
  795. public function get scrollContext():IScrollViewportContext
  796. {
  797. return _scrollContext;
  798. }
  799. public function set scrollContext( value:IScrollViewportContext ):void
  800. {
  801. if( _scrollContext == value ) return;
  802. _scrollContext = value;
  803. invalidate( invalidateScrollContext );
  804. }
  805. /**
  806. * Accessor/Modifier for the item renderer instance to represent the data.
  807. * @return String The fully qualified class name of the item renderer.
  808. */
  809. public function get itemRenderer():String
  810. {
  811. return _itemRenderer;
  812. }
  813. public function set itemRenderer( value:String ):void
  814. {
  815. if( _itemRenderer == value ) return;
  816. _itemRenderer = value;
  817. invalidate( invalidateItemRenderer );
  818. }
  819. /**
  820. * @copy IScrollListContainer#selectionEnabled
  821. */
  822. public function get selectionEnabled():Boolean
  823. {
  824. return _selectionEnabled;
  825. }
  826. public function set selectionEnabled( value:Boolean ):void
  827. {
  828. if( _selectionEnabled == value ) return;
  829. _selectionEnabled = value;
  830. invalidate( invalidateSelectionEnablement );
  831. }
  832. /**
  833. * Accessor/Modifier of the selected item within the list from the data provided. This is not the selected item renderer instance.
  834. * @return Object
  835. */
  836. public function get selectedItem():Object
  837. {
  838. // Based on the selected index.
  839. return ( _selectedIndex >= 0 && _selectedIndex < _dataProvider.length ) ? _dataProvider[_selectedIndex] : null;
  840. }
  841. public function set selectedItem( value:Object ):void
  842. {
  843. // Set selected index based on the value.
  844. var index:int = _dataProvider.indexOf( value );
  845. if( _selectedIndex == index ) return;
  846. if( index > -1 ) selectedIndex = index;
  847. }
  848. /**
  849. * Accessor/Modifier for the selected index within the list.
  850. * @return int
  851. */
  852. public function get selectedIndex():int
  853. {
  854. return _selectedIndex;
  855. }
  856. public function set selectedIndex( value:int ):void
  857. {
  858. if( _selectedIndex == value ) return;
  859. _selectedIndex = value;
  860. invalidate( invalidateSelection );
  861. selectionChange.dispatch( _signalEvent );
  862. }
  863. /**
  864. * @copu IScrollListContainer#labelField
  865. */
  866. public function get labelField():String
  867. {
  868. return _labelField;
  869. }
  870. public function set labelField( value:String ):void
  871. {
  872. if( _labelField == value ) return;
  873. _labelField = value;
  874. invalidate( invalidateLabelField );
  875. }
  876. /**
  877. * Accessor/Modifier for the array of data represented.
  878. * @return Array An Array of Object-based objects.
  879. */
  880. public function get dataProvider():Array
  881. {
  882. return _dataProvider;
  883. }
  884. public function set dataProvider( value:Array ):void
  885. {
  886. if( _dataProvider == value ) return;
  887. var oldValue:Array = _dataProvider;
  888. _dataProvider = value;
  889. invalidate( invalidateDataProvider, [oldValue, _dataProvider] );
  890. }
  891. }
  892. }
  893. import flash.display.DisplayObject;
  894. import flash.display.Sprite;
  895. import flash.geom.Point;
  896. import flash.geom.Rectangle;
  897. /**
  898. * @private
  899. *
  900. * ScrollListHolder is an extension of Sprite that holds dimension values representing width and height. This is so not to scale the Sprite,
  901. * and is used as the basis for scroling in the viewport based on content dimensions.
  902. * @author toddanderson
  903. */
  904. class ScrollListHolder extends Sprite
  905. {
  906. protected var _width:Number = 0;
  907. protected var _height:Number = 0;
  908. protected var _visibleWidth:Number = 0;
  909. protected var _visibleHeight:Number = 0;
  910. protected var _rectCache:Rectangle;
  911. private static const ORIGIN:Point = new Point( 0, 0 );
  912. /**
  913. * Constructor.
  914. */
  915. public function ScrollListHolder()
  916. {
  917. _rectCache = new Rectangle();
  918. }
  919. /**
  920. * @inherit
  921. *
  922. * Override to prvide proper bounds based on visible height rather than child display height.
  923. * @param targetCoordinateSpace DisplayObject
  924. * @return Rectangle
  925. */
  926. override public function getBounds( targetCoordinateSpace:DisplayObject ):Rectangle
  927. {
  928. // Use parent positioning, as this content is scrolled within, and the point should reside at the origina of parenting container.
  929. var pt:Point = ( parent ) ? parent.localToGlobal( ScrollListHolder.ORIGIN ) : localToGlobal( ScrollListHolder.ORIGIN );
  930. var w:int = _visibleWidth * targetCoordinateSpace.scaleX;
  931. var h:int = _visibleHeight * targetCoordinateSpace.scaleY;
  932. _rectCache.x = pt.x;
  933. _rectCache.y = pt.y;
  934. _rectCache.width = w;
  935. _rectCache.height = h;
  936. return _rectCache;
  937. }
  938. /**
  939. * Accessor/Modifier for the visible width dimension of this display within the list.
  940. * @return Number
  941. */
  942. public function get visibleWidth():Number
  943. {
  944. return _visibleWidth;
  945. }
  946. public function set visibleWidth( value:Number ):void
  947. {
  948. if( _visibleWidth == value ) return;
  949. _visibleWidth = value;
  950. }
  951. /**
  952. * Accessor/Modifier for the visible height dimension of this display within the list.
  953. * @return Number
  954. */
  955. public function get visibleHeight():Number
  956. {
  957. return _visibleHeight;
  958. }
  959. public function set visibleHeight( value:Number ):void
  960. {
  961. if( _visibleHeight == value ) return;
  962. _visibleHeight = value;
  963. }
  964. /**
  965. * Accessor/Modifier for the preferred width of the display.
  966. * @return Number
  967. */
  968. override public function get width():Number
  969. {
  970. return _width;
  971. }
  972. override public function set width( value:Number ):void
  973. {
  974. if( _width == value ) return;
  975. _width = value;
  976. }
  977. /**
  978. * Accessor/Modifier for the preferred height of the display.
  979. * @return Number
  980. */
  981. override public function get height():Number
  982. {
  983. return _height;
  984. }
  985. override public function set height( value:Number ):void
  986. {
  987. if( _height == value ) return;
  988. _height = value;
  989. }
  990. }