layoutTarget
/**
* @private
* Work-around the Player globalToLocal and scrollRect changing before
* a frame is updated.
*/
private function globalToLocal(x:Number, y:Number):Point
{
var layoutTarget:GroupBase = target;
var parent:DisplayObject = layoutTarget.parent;
var local:Point = parent.globalToLocal(new Point(x, y));
local.x -= layoutTarget.x;
local.y -= layoutTarget.y;
var scrollRect:Rectangle = getScrollRect();
if (scrollRect)
{
local.x += scrollRect.x;
local.y += scrollRect.y;
}
return local;
}
и это тоже
/**
* Calculates how much to scroll for the specified <code>dropLocation</code>
* during a drag and drop gesture.
*
* Called by the <code>showDropIndicator()</code> method to calculate the scroll
* during drag-scrolling.
*
* @param context A valid DropLocation object previously obtained
* by calling the <code>calculateDropLocation()</code> method.
*
* @param elapsedTime The duration, in milliseconds, since the drag scrolling start.
*
* @return How much to drag scroll, or null if drag-scrolling is not needed.
*
* @see spark.layouts.supportClasses.DropLocation
* @see #calculateDropIndex()
* @see #calculateDropIndicatorBounds()
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
protected function calculateDragScrollDelta(dropLocation:DropLocation, elapsedTime:Number):Point
{
var layoutTarget:GroupBase = target;
if (layoutTarget.numElements == 0)
return null;
var scrollRect:Rectangle = getScrollRect();
if (!scrollRect)
return null;
// Make sure that the drag-scrolling regions don't overlap
var x:Number = dropLocation.dropPoint.x;
var y:Number = dropLocation.dropPoint.y;
var horizontalRegionSize:Number = Math.min(dragScrollRegionSizeHorizontal, layoutTarget.width/2);
var verticalRegionSize:Number = Math.min(dragScrollRegionSizeVertical, layoutTarget.height/2);
// Return early if the mouse is outside of the drag-scroll region.
if (scrollRect.left + horizontalRegionSize < x && x < scrollRect.right - horizontalRegionSize &&
scrollRect.top + verticalRegionSize < y && y < scrollRect.bottom - verticalRegionSize )
return null;
if (elapsedTime < dragScrollInitialDelay)
return new Point(); // Return zero point to continue firing events, but not actually scroll.
elapsedTime -= dragScrollInitialDelay;
// Speedup based on time elapsed
var timeSpeedUp:Number = Math.min(elapsedTime, 2000) / 2000;
timeSpeedUp *= 3;
timeSpeedUp += 1;
timeSpeedUp *= timeSpeedUp * dragScrollSpeed * dragScrollInterval / 50;
var minDeltaX:Number = -scrollRect.left;
var minDeltaY:Number = -scrollRect.top;
var maxDeltaY:Number = target.contentHeight - scrollRect.bottom;
var maxDeltaX:Number = target.contentWidth - scrollRect.right;
var deltaX:Number = 0;
var deltaY:Number = 0;
if (minDeltaX != 0 && x - scrollRect.left < horizontalRegionSize)
{
// Scroll left
deltaX = 1 - (x - scrollRect.left) / horizontalRegionSize;
deltaX *= deltaX * timeSpeedUp;
deltaX = -Math.round(deltaX) - 1;
}
else if (maxDeltaX != 0 && scrollRect.right - x < horizontalRegionSize)
{
// Scroll right
deltaX = 1 - (scrollRect.right - x) / horizontalRegionSize;
deltaX *= deltaX * timeSpeedUp;
deltaX = Math.round(deltaX) + 1;
}
if (minDeltaY != 0 && y - scrollRect.top < verticalRegionSize)
{
// Scroll up
deltaY = 1 - (y - scrollRect.top) / verticalRegionSize;
deltaY *= deltaY * timeSpeedUp;
deltaY = -Math.round(deltaY) - 1;
}
else if (maxDeltaY != 0 && scrollRect.bottom - y < verticalRegionSize)
{
// Scroll down
deltaY = 1 - (scrollRect.bottom - y) / verticalRegionSize;
deltaY *= deltaY * timeSpeedUp;
deltaY = Math.round(deltaY) + 1;
}
deltaX = Math.max(minDeltaX, Math.min(maxDeltaX, deltaX));
deltaY = Math.max(minDeltaY, Math.min(maxDeltaY, deltaY));
if (deltaX == 0 && deltaY == 0)
return null;
return new Point(deltaX, deltaY);
}
HorizontalScrollPosition
/**
* @private
* Updates the scroll position and dispatches a DragEvent.
*/
private function dragScroll(event:TimerEvent):void
{
// Scroll the target
horizontalScrollPosition += _dragScrollDelta.x;
verticalScrollPosition += _dragScrollDelta.y;
// Validate target before dispatching the event
target.validateNow();
// Re-dispatch the event so that the drag initiator handles it as if
// the DragProxy is dispatching in response to user input.
// Always switch over to DRAG_OVER, don't re-dispatch DRAG_ENTER
var dragEvent:DragEvent = new DragEvent(DragEvent.DRAG_OVER,
_dragScrollEvent.bubbles,
_dragScrollEvent.cancelable,
_dragScrollEvent.dragInitiator,
_dragScrollEvent.dragSource,
_dragScrollEvent.action,
_dragScrollEvent.ctrlKey,
_dragScrollEvent.altKey,
_dragScrollEvent.shiftKey);
dragEvent.draggedItem = _dragScrollEvent.draggedItem;
dragEvent.localX = _dragScrollEvent.localX;
dragEvent.localY = _dragScrollEvent.localY;
dragEvent.relatedObject = _dragScrollEvent.relatedObject;
_dragScrollEvent.target.dispatchEvent(dragEvent);
}
и это тоже:
public function set horizontalScrollPosition(value:Number):void
{
if (value == _horizontalScrollPosition)
return;
_horizontalScrollPosition = value;
scrollPositionChanged();
}
давайте посмотрим тоже scrollPositionChanged();
/**
* Called when the <code>verticalScrollPosition</code> or
* <code>horizontalScrollPosition</code> properties change.
*
* <p>The default implementation updates the target's <code>scrollRect</code> property by
* calling <code>updateScrollRect()</code>.
* Subclasses can override this method to compute other values that are
* based on the current <code>scrollPosition</code> or <code>scrollRect</code>.</p>
*
* @see #updateScrollRect()
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
protected function scrollPositionChanged():void
{
var g:GroupBase = target;
if (!g)
return;
updateScrollRect(g.width, g.height);
}
также давайте посмотрим на эту часть кода
/**
* Computes the <code>verticalScrollPosition</code> and
* <code>horizontalScrollPosition</code> deltas needed to
* scroll the element at the specified index into view.
*
* <p>This method attempts to minimize the change to <code>verticalScrollPosition</code>
* and <code>horizontalScrollPosition</code>.</p>
*
* <p>If <code>clipAndEnableScrolling</code> is <code>true</code>
* and the element at the specified index is not
* entirely visible relative to the target's scroll rectangle, then
* return the delta to be added to <code>horizontalScrollPosition</code> and
* <code>verticalScrollPosition</code> that scrolls the element completely
* within the scroll rectangle's bounds.</p>
*
* @param index The index of the element to be scrolled into view.
*
* @return A Point that contains offsets to horizontalScrollPosition
* and verticalScrollPosition that will scroll the specified
* element into view, or null if no change is needed.
* If the specified element is partially visible and larger than the
* scroll rectangle, meaning it is already the only element visible, then
* return null.
* If the specified index is invalid, or target is null, then
* return null.
* If the element at the specified index is null or includeInLayout
* false, then return null.
*
* @see #clipAndEnableScrolling
* @see #verticalScrollPosition
* @see #horizontalScrollPosition
* @see #udpdateScrollRect()
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function getScrollPositionDeltaToElement(index:int):Point
и так, что если мы поговоримо разнице этих параметров в LayoutBase и HorizontalLayout?
в HL он использовался в private function updateDisplayListVirtual():void
, но в LayoutBase такой функции нет, потому что LayoutBase просто базовый класс, как есть, но у него есть другой, который называетсякак public function updateDisplayList(width:Number, height:Number):void
, но оно пустое.
Итак, если мы попытаемся понять, что делают все эти функции, imho, HL просто расширяет стандарт updateDisplayList
на две функции, одна такая же, а другая виртуальная.
Зачем HL нужен виртуальный?Давайте посмотрим:
override public function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
var layoutTarget:GroupBase = target;
if (!layoutTarget)
return;
if ((layoutTarget.numElements == 0) || (unscaledWidth == 0) || (unscaledHeight == 0))
{
setColumnCount(0);
setIndexInView(-1, -1);
if (layoutTarget.numElements == 0)
layoutTarget.setContentSize(paddingLeft + paddingRight, paddingTop + paddingBottom);
return;
}
if (useVirtualLayout)
updateDisplayListVirtual();
else
updateDisplayListReal();
}
так что все вещи useVirtualLayout , но это из LayoutBase и позволяет увидеть:
/**
* A container can hold any number of children.
* However, each child requires an instance of an item renderer.
* If the container has many children, you might notice performance degradation
* as you add more children to the container.
*
* <p>Instead of creating an item renderer for each child,
* you can configure the container to use a virtual layout.
* With virtual layout, the container reuses item renderers so that it only creates
* item renderers for the currently visible children of the container.
* As a child is moved off the screen, possible by scrolling the container,
* a new child being scrolled onto the screen can reuse its item renderer. </p>
*
* <p>To configure a container to use virtual layout, set the <code>useVirtualLayout</code> property
* to <code>true</code> for the layout associated with the container.
* Only the DataGroup or SkinnableDataContainer with the VerticalLayout,
* HorizontalLayout, and TileLayout supports virtual layout.
* Layout subclasses that do not support virtualization must prevent changing
* this property.</p>
*
* <p><b>Note: </b>The BasicLayout class throws a run-time error if you set
* <code>useVirtualLayout</code> to <code>true</code>.</p>
*
* <p>When <code>true</code>, layouts that support virtualization must use
* the <code>target.getVirtualElementAt()</code> method,
* rather than <code>getElementAt()</code>, and must only get the
* elements they anticipate will be visible given the value of <code>getScrollRect()</code>.</p>
*
* <p>When <code>true</code>, the layout class must be able to compute
* the indices of the layout elements that overlap the <code>scrollRect</code> in its
* <code>updateDisplayList()</code> method based exclusively on cached information, not
* by getting layout elements and examining their bounds.</p>
*
* <p>Typically virtual layouts update their cached information
* in the <code>updateDisplayList()</code> method,
* based on the sizes and locations computed for the elements in view.</p>
*
* <p>Similarly, in the <code>measure()</code> method, virtual layouts should update the target's
* measured size properties based on the <code>typicalLayoutElement</code> and other
* cached layout information, not by measuring elements.</p>
*
* <p>Containers cooperate with layouts that have <code>useVirtualLayout</code> = <code>true</code> by
* recycling item renderers that were previously constructed, but are no longer in use.
* An item is considered to be no longer in use if its index is not
* within the range of <code>getVirtualElementAt()</code> indices requested during
* the container's most recent <code>updateDisplayList()</code> invocation.</p>
*
* @default false
*
* @see #getScrollRect
* @see #typicalLayoutElement
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
так что это ваш ответ, я думаю,Также я думаю, что люди, которые написали эту систему Spark, объяснят более широко, и я только с небольшим удовольствием помогу вам получить правильные ответы.
С уважением
Евгений