在为List编写自定义布局时,需要考虑在LayoutBase类本身上使用horizontalScrollPosition / verticalScrollPosition属性(而不是layoutTarget上的相应属性)
以HorizontalLayout
类为例,它始终引用并更新layoutTarget.horizontalScrollPosition
。是否引用/使用了LayoutBase类的horizontalScrollPosition?
澄清: 我在这里问的是: 布局实例上的属性与layoutTarget实例上的属性之间的关系是什么,以及何时应该使用它们?
答案 0 :(得分:0)
是否曾引用/使用过LayoutBase类的horizontalScrollPosition?
是的,可以使用它。
代码中的please look!找到horizontalScrollPosition,这个param使用了至少3个函数。
如果你能告诉你究竟想用它做什么会更好吗?
答案 1 :(得分:0)
<强> 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只是一个Base类,但它有另一个调用为public function updateDisplayList(width:Number, height:Number):void
但它是空的。 / p>
所以,如果我们试着想一想所有这些函数做了什么,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系统的人会更广泛地解释,而且我很乐意帮助你找到正确的答案。
问候
尤金