List的LayoutBase中xxScrollPosition的用途是什么?

时间:2010-09-01 15:56:36

标签: flex

在为List编写自定义布局时,需要考虑在LayoutBase类本身上使用horizo​​ntalScrollPosition / verticalScrollPosition属性(而不是layoutTarget上的相应属性)

HorizontalLayout类为例,它始终引用并更新layoutTarget.horizontalScrollPosition。是否引用/使用了LayoutBase类的horizo​​ntalScrollPosition?

澄清: 我在这里问的是: 布局实例上的属性与layoutTarget实例上的属性之间的关系是什么,以及何时应该使用它们?

2 个答案:

答案 0 :(得分:0)

  

是否曾引用/使用过LayoutBase类的horizo​​ntalScrollPosition?

是的,可以使用它。

代码中的

please look!找到horizo​​ntalScrollPosition,这个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);
}

<强> horizo​​ntalScrollPosition的

/**
 *  @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和Horizo​​ntalLayout中讨论这些参数的差异怎么办?

在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系统的人会更广泛地解释,而且我很乐意帮助你找到正确的答案。

问候
尤金