Wednesday, February 22, 2012

Flex 4 Spark Auto Scrolling Form

I had an interesting request today to make sure when tabbing through all of our forms, that the vertical scroll bar adjusts to make sure the focused field is in view. I went back and forth on this and it's not built in to flex so some reason, but a colleague came across a piece of code from flex 3 and converted it over to flex 4. This worked well for tabbing down a page but not up so we doctored it up a little and it now scrolls up and down. I found it so easy and helpful that I thought i'd share

public class ScrollUtil
 {
  // this method is specifically written for the Scroller component
  // to use this on other scroller components will need modification or
  // another method
  public static function autoScroll(event:FocusEvent):void
  {
   var scroller:Scroller = event.currentTarget as Scroller;
   var focusItem:DisplayObject = DisplayObject(scroller.focusManager.getFocus());

   // if no scrollbar or focused item, nothing to do
   if (scroller.verticalScrollBar && focusItem)
   {
    // is the current focus item inside our container?
    if (focusItem == scroller || !scroller.contains(focusItem))
    {
     return;
    }

    // find the focusItem’s y coord in the scrolled container
    // by summing the y offsets of the item and all parent containers in the tree
    // between the target and the scrolled container
    ensureFocusItemIsVisible(focusItem, scroller);
   }
  }

  public static function ensureFocusItemIsVisible(focusItem:DisplayObject, scroller:Scroller):void
  {
   var focusTopEdge:int = focusItem.y;
   var thisItem:DisplayObjectContainer = focusItem.parent;

   while (thisItem != scroller)
   {
    focusTopEdge += thisItem.y;
    thisItem = thisItem.parent;
   }

   var focusBottomEdge:int = focusTopEdge + focusItem.height;
   var scrollbarRange:int = scroller.verticalScrollBar.maxHeight;
   var visibleWindowHeight:int = scroller.height;
   var firstVisibleY:int = scroller.viewport.verticalScrollPosition;
   var lastVisibleY:int = visibleWindowHeight + scroller.viewport.verticalScrollPosition;
   var newPos:int;

   if (scroller.horizontalScrollBar)
   {
    // remove the horiz scrollbar height from lastVisibleY
    lastVisibleY -= scroller.horizontalScrollBar.height;
   }

   if (focusTopEdge == scroller.viewport.verticalScrollPosition)
   {
    trace("Bar not moved, already at top edge of focus item.");
   }
   else if (focusTopEdge > lastVisibleY)
   {
    newPos = Math.min(scrollbarRange, scroller.viewport.verticalScrollPosition + (focusBottomEdge - lastVisibleY));
    scroller.viewport.verticalScrollPosition = newPos;
    trace("Moved bar down to " + newPos);
   }
   else if (focusTopEdge < firstVisibleY)
   {
    scroller.viewport.verticalScrollPosition = focusTopEdge;
    trace("Moved bar up to " + focusTopEdge);
   }
   else
   {
    trace("Bar not moved.");
    ;
   }
  }
 }

1 comment: