Created
November 29, 2011 13:39
-
-
Save newtriks/1404826 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package | |
{ | |
import flash.display.DisplayObject; | |
import flash.events.Event; | |
import flash.events.MouseEvent; | |
import flash.geom.Point; | |
import mx.controls.List; | |
import mx.controls.listClasses.ListRowInfo; | |
import mx.core.mx_internal; | |
import mx.events.ScrollEvent; | |
import mx.events.ScrollEventDetail; | |
use namespace mx_internal; | |
public class CustomList extends List | |
{ | |
public function CustomList() | |
{ | |
super(); | |
offscreenExtraRowsOrColumns = 2; | |
} | |
override public function get verticalScrollPosition():Number | |
{ | |
if ( !isNaN( fudge ) ) | |
{ | |
var vsp:Number = super.verticalScrollPosition + fudge; | |
fudge = NaN; | |
return vsp; | |
} | |
return Math.floor( super.verticalScrollPosition ); | |
} | |
protected function getMeasuredHeight( maxHeight:int ):Number | |
{ | |
/*if the collection has only one row, we ignore the | |
maxHeight by setting it back to its default. One row | |
cannot scroll, setting a max on that for one very | |
large row (that is more than maxHeight pixels long) | |
will force the row to be clipped */ | |
var count:int = ( collection )?collection.length:0; | |
if( count < 0 ) count = 0; | |
if( collection && count == 1 ) maxHeight = DEFAULT_MAX_HEIGHT; | |
if( contentHeight >= maxHeight ) return maxHeight; | |
var hh:int = 0; | |
if( !rowInfo || rowInfo.length == 0 ) | |
{ | |
if( collection ) | |
contentHeight = Math.min(maxHeight,count * 20); | |
else | |
contentHeight = 0; | |
return contentHeight; | |
} | |
/* keep on increasing the height until either we run out | |
of rows to draw or maxHeight is reached */ | |
var len:int = Math.min( rowInfo.length, count ); | |
for( var i:int=0;i<len;i++ ) | |
{ | |
if( rowInfo[i] && ListRowInfo( rowInfo[i]).uid ) | |
hh += ListRowInfo( rowInfo[i] ).height; | |
} | |
/* if hh is less than maxHeight and we still have rows to | |
show, increase the height */ | |
if( hh < maxHeight && rowInfo.length < count ) | |
{ | |
/* if we have already drawn all the rows without | |
hitting the maxHeight, we are good to go */ | |
hh = Math.min( maxHeight,hh + ( count - rowInfo.length ) * 20 ); | |
} | |
contentHeight = Math.min( maxHeight, hh ); | |
return contentHeight; | |
} | |
protected function measureHeight():void | |
{ | |
var buffer:int = (this.horizontalScrollBar!=null ) ? this.horizontalScrollBar.height : 0; | |
var maxContentHeight:int = maxHeight - buffer; | |
var listContentHeight:int = buffer + getMeasuredHeight( maxContentHeight ); | |
var hh:int = listContentHeight + 2; | |
if( hh == this.height ) return; | |
listContent.height = listContentHeight; | |
this.height = hh; | |
if( height >= maxHeight ) | |
this.verticalScrollPolicy = "auto"; | |
else | |
this.verticalScrollPolicy = "off"; | |
} | |
/** | |
* Override of the corresponding method in mx.controls.ListGrid. | |
* After drawing the rows, it calls measureHeight to figure out | |
* if the height of the grid still needs to be adjusted. | |
*/ | |
protected override function makeRowsAndColumns( left:Number, top:Number, right:Number, bottom:Number, firstCol:int, firstRow:int, byCount:Boolean=false, rowsNeeded:uint=0.0 ):Point | |
{ | |
var p:Point = super.makeRowsAndColumns( left, top, right, bottom, firstCol, firstRow, byCount, rowsNeeded ); | |
measureHeight(); | |
return p; | |
} | |
/** | |
* Override of the method from ListBase.configureScrollBars. | |
* We copy the method but make one significant change - we comment | |
* out the code that pushes the scroll bar up if any filler rows | |
* are present. With our variableRowHeights, this code sometimes | |
* pushes up the vertical scroll when the user is trying to scroll | |
* down. In the worst case, it doesn't allow the user to see the | |
* last few rows. | |
*/ | |
override protected function configureScrollBars():void | |
{ | |
var rowCount:int = listItems.length; | |
if( rowCount == 0 ) return; | |
// ignore nonvisible rows off the top | |
var yy:Number; | |
var i:int; | |
var n:int = listItems.length; | |
// if there is more than one row and it is a partial row we dont count it | |
while( rowCount > 1 && rowInfo[n - 1].y + rowInfo[n-1].height > listContent.height - listContent.bottomOffset ) | |
{ | |
rowCount--; | |
n--; | |
} | |
/* offset, when added to rowCount, is the index of the dataProvider | |
item for that row. IOW, row 10 in listItems is showing dataProvider | |
item 10 + verticalScrollPosition - lockedRowCount - 1; */ | |
var offset:int = verticalScrollPosition - lockedRowCount - 1; | |
// don't count filler rows at the bottom either. | |
var fillerRows:int = 0; | |
// don't count filler rows at the bottom either. | |
while( rowCount && listItems[rowCount - 1].length == 0 ) | |
{ | |
if( collection && rowCount + offset >= collection.length ) | |
{ | |
rowCount--; | |
++fillerRows; | |
} | |
else | |
{ | |
break; | |
} | |
} | |
if( listContent.topOffset ) | |
{ | |
yy = Math.abs( listContent.topOffset ); | |
i = 0; | |
while( rowInfo[i].y + rowInfo[i].height <= yy ) | |
{ | |
rowCount--; | |
i++; | |
if( i == rowCount ) | |
break; | |
} | |
} | |
var colCount:int = listItems[0].length; | |
var oldHorizontalScrollBar:Object = horizontalScrollBar; | |
var oldVerticalScrollBar:Object = verticalScrollBar; | |
var roundedWidth:int = Math.round(unscaledWidth); | |
var length:int = collection ? collection.length - lockedRowCount: 0; | |
var numRows:int = rowCount - lockedRowCount; | |
setScrollBarProperties( ( isNaN( _maxHorizontalScrollPosition ) ) ? | |
Math.round( listContent.width ) : | |
Math.round( _maxHorizontalScrollPosition + roundedWidth ), | |
roundedWidth, length, numRows ); | |
maxVerticalScrollPosition = Math.max( length - numRows, 0 ); | |
} | |
/** | |
* displayWidth is a private variable in mx.controls.ListBase. We | |
* need to create it here so that we can use it | |
*/ | |
protected var displayWidth:Number; | |
/** | |
* We need to override the updateDisplayList so that we can set the | |
* displayWidth. | |
* See the displayWidth variable in mx.controls.ListBase | |
*/ | |
protected override function updateDisplayList( unscaledWidth:Number, unscaledHeight:Number ):void | |
{ | |
if( displayWidth != unscaledWidth - viewMetrics.right - viewMetrics.left ) | |
displayWidth = unscaledWidth - viewMetrics.right - viewMetrics.left + 5; | |
super.updateDisplayList( unscaledWidth, unscaledHeight ); | |
} | |
override protected function mouseDownHandler( event:MouseEvent ):void | |
{ | |
// Stop RB deselection by cancelling this event | |
if( event.target is mx.controls.listClasses.ListBaseContentHolder ) | |
event.stopImmediatePropagation(); | |
else super.mouseDownHandler( event ); | |
} | |
override protected function scrollHandler( event:Event ):void | |
{ | |
/** | |
* Going backward is trickier. When you cross from, for instance 2.1 to 1.9, you need to | |
* convince the superclass that it is going from 2 to 1 so the delta is -1 and not -.2. | |
* We do this by adding a fudge factor to the first return from verticalScrollPosition | |
* which is used by the superclass logic. | |
*/ | |
var last:Number = super.verticalScrollPosition; | |
var vsp:Number = verticalScrollBar.scrollPosition; | |
if ( vsp < last ) | |
{ | |
if ( last != Math.floor( last ) || vsp != Math.floor( vsp ) ) | |
{ | |
if ( Math.floor( vsp ) < Math.floor( last ) ) | |
{ | |
fudge = Math.floor( last ) - Math.floor( verticalScrollBar.scrollPosition ); | |
} | |
} | |
} | |
super.scrollHandler( event ); | |
var pos:Number = super.verticalScrollPosition; | |
/** | |
* If we get a THUMB_TRACK, then we need to calculate the position | |
* because it gets rounded to an int by the ScrollThumb code, and | |
* we want fractional values. | |
*/ | |
if ( event is ScrollEvent ) | |
{ | |
var se:ScrollEvent = ScrollEvent( event ); | |
if ( se.detail == ScrollEventDetail.THUMB_TRACK ) | |
{ | |
if ( verticalScrollBar.numChildren == 4 ) | |
{ | |
var downArrow:DisplayObject = verticalScrollBar.getChildAt( 3 ); | |
var thumb:DisplayObject = verticalScrollBar.getChildAt( 2 ); | |
pos = ( thumb.y - downArrow.height ) / ( downArrow.y - thumb.height - downArrow.height ) * maxVerticalScrollPosition; | |
// round to nearest lineScrollSize; | |
pos /= verticalScrollBar.lineScrollSize; | |
pos = Math.round( pos ); | |
pos *= verticalScrollBar.lineScrollSize; | |
} | |
} | |
} | |
var fraction:Number = pos - verticalScrollPosition; | |
fraction *= rowHeight; | |
listContent.move( listContent.x, viewMetrics.top + listContent.topOffset - fraction ); | |
} | |
protected var fudge:Number; | |
protected var contentHeight:int = 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment