2
votes

I have lots of child text inputs within a spark Scroller. How can I make the TextInput with id of "x" come into focus if I have a..z id's, also for the scrollbar to scroll automatically to that child item?

I can use x.setFocus(), but the scrollbar doesn't automatically scroll to that item? why?

<s:Scroller id="scroller" width="100%" height="100">
        <s:Group id="group" width="100%" height="100" id="content">
            <s:TextInput id="a" text="" editable="true" width="100%" height="25" />
            <s:TextInput id="b" text="" editable="true" width="100%" height="25" />
            ....
        </s:Group>
</s:Scroller>

Thanks, Philip

4

4 Answers

2
votes

The reason is that setFocus just makes the object active, it doesn't actually move change the scrollPosition of the ScrollBar. With more complex classes like a List, it's more straight forward but Scroller is pretty basic and so it's a bit tougher.

To do what you want you have to get the index of the element inside of your viewport (your group) and then manually set the scrollPosition. For a vertical layout the code would look something like this:

var index:Number = group.getElementIndex(g);
var offset:Number = group.getElementAt(index).height;
scroller.viewport.verticalScrollPosition = index * offset;

Where 'g' is the id of the element you want to move to in your Scroller.

=Ryan [email protected]

1
votes

Just check out the Flex SDK, here's a spark.components.List method, just use the same code for your DataGroup:

public function ensureIndexIsVisible(index:int):void
{
    if (!layout)
        return;

    var spDelta:Point = dataGroup.layout.getScrollPositionDeltaToElement(index);

    if (spDelta)
    {
        dataGroup.horizontalScrollPosition += spDelta.x;
        dataGroup.verticalScrollPosition += spDelta.y;
    }
}
0
votes

couple additional considerations:

  1. he items in my data group are not a constant height so if thats the case, a more accurate reference to set the scroller to would be:

    var y:int = group.getElementAt(index).y; scroller.viewport.verticalScrollPosition = y;

  2. Make sure your datagroup is not set to use virtualization. Mine was and I got errors as the elements were being added / removed at runtime.

0
votes

The getScrollPositionDeltaToElement method doesn't account for nested children. For that you can use the mx_internal method as shown below:

/**
* Focus in handler to be used on form elements inside a Scroller. If the 
* widgets are inside a FormItem, this ensures that the entire FormItem is 
* scrolled into view. Also, if there are validations triggered on focusOut
* of the elements, the default behavior in Flex 4 is to display the error 
* messages at the top of the form. Because this affects the vertical position
* of each element, the logic to scroll the item into view must be delayed 
* until the next frame using callLater()
*
* NOTE: This uses a method, in the mx_internal namespace 
*/
    protected function widgetFocusInHandler(evt:FocusEvent):void {
        //we need to delay this because we may need to account 
        //for validation errors being display above the form.
        callLater(function(field:UIComponent) : void {
            //find the form item that wraps the input and scroll 
            //it into view

            var formItem:DisplayObjectContainer = field.parent;
            while (!(formItem is FormItem) && formItem) {
                 formItem = formItem.parent;
            }

            //if this item wasn't in a form item, then just use the 
            //widget itself
            if (!formItem) {
                formItem = field;   
            }

            var pt:Point = formItem.localToGlobal(new Point(0, formItem.height));

            pt = scrollWrapper.globalToLocal(pt);
            var layout:LayoutBase = scrollWrapper.layout;           
            var delta:Point = layout.mx_internal::getScrollPositionDeltaToAnyElement(field);
            if (delta) {
                if(delta.y > 0) {
                    layout.verticalScrollPosition += delta.y + 20;
                } else if (delta.y < 0) {
                    layout.verticalScrollPosition += delta.y - 20;
                }
            }

        }, [UIComponent(evt.currentTarget)]);
   }