Adobe Flex 3 Help

Creating tab order and reading order

There are two aspects of tab indexing order--the tab order in which a user navigates through the web content, and the reading order in which things are read by the screen reader.

Flash Player uses a tab index order from left to right and top to bottom. However, if this is not the order you want to use, you can customize both the tab order and the reading order by using the InteractiveObject.tabIndex property. (In ActionScript, the tabIndex property is synonymous with the reading order.)

Tab order 

You can use the tabIndex property of every component to create a tab order that determines the order in which objects receive input focus when a user presses the Tab key.



Reading order 

You can use the tabIndex property to control the order in which the screen reader reads information about the object. To create a reading order, you assign a value to the tabIndex property for every component in your application. You should set the tabIndex property for every accessible object, not just the focusable objects. For example, you must set the tabIndex property for a Text control even though a user cannot tab to it. If you do not set the tabIndex property for every accessible object, Flash Player puts that object at the end of the tab order, rather than in its appropriate tab order location.



Scrolling to a component when tabbing

As a general rule, you should structure your application so that all components fit in the available screen area; otherwise Flex adds vertical or horizontal scroll bars as necessary. Scroll bars let users move around the application to access components outside of the screen area.

If your application uses scroll bars, tabbing through the application components does not automatically scroll the application to make the currently selected component visible. You can add logic to your application to automatically scroll to the currently selected component, as the following example shows:

<?xml version="1.0"?>
<!-- accessibility\ScrollComp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
    layout="absolute" 
    creationComplete="setupFocusViewportWatcher();">

    <mx:Script>
        <![CDATA[
        
        import mx.core.Container;
        import mx.core.EdgeMetrics;
    
        [Bindable]
        public var cards: Array = [ 
            {label:"Visa", data:1}, 
            {label:"Master Card", data:2}, 
            {label:"American Express", data:3} ];
        
        [Bindable]
        public var selectedItem:Object;
 
        [Bindable]
        public var forListDP:Array = [
            {label:'Apple', data:10.00},
            {label:'Banana', data:15.00},
            {label:'Melon', data:3.50},
            {label:'Kiwi', data:7.65},
            {label:'123', data:12.35 },
            {label:'some', data:10.01 }];
    
        // Set up the event listener for the focusIn event. 
        public function setupFocusViewportWatcher():void {
            addEventListener("focusIn", makeFocusedItemVisible);
        }
    
        public function makeFocusedItemVisible(event:FocusEvent):void {
            // Target is the actual object that has focus.
            var target:InteractiveObject = InteractiveObject(event.target);
            
            // OriginalTarget is the component that has focus as some
            // component actually delegate true focus to an internal object.
            var originalTarget:InteractiveObject = 
        InteractiveObject(focusManager.findFocusManagerComponent(target));
    
            // The viewable portion of a container
            var viewport:Rectangle = new Rectangle();
            do {
                // Cycle through all parents looking for containers.
                if (target.parent is Container) {
                    var viewportChanged:Boolean = false;
                    var c:Container = target.parent as Container;

                    // Get the viewable area in the container.
                    var vm:EdgeMetrics = c.viewMetrics;
                    viewport.x = vm.left;
                    viewport.y = vm.top;
                    viewport.width = 
                        c.width / c.scaleX - vm.left - vm.right;
                    viewport.height = 
                        c.height / c.scaleY - vm.top - vm.bottom;
                    
                    // Calculate the position of the target in the container.
                    var topLeft:Point = new Point(0, 0);
                    var bottomRight:Point = 
                new Point(originalTarget.width, originalTarget.height);
                    topLeft = originalTarget.localToGlobal(topLeft);
                    topLeft = c.globalToLocal(topLeft);
                    bottomRight = originalTarget.localToGlobal(bottomRight);
                    bottomRight = c.globalToLocal(bottomRight);
    
                    // Figure out if we have to move the scroll bars.
                    // If the scroll bar moves, the position of the component
                    // moves as well. This algorithm makes sure the top
                    // left of the component is visible if the component is
                    // bigger than the viewport.
                    var delta:Number;

                    if (bottomRight.x > viewport.right) {
                        delta = bottomRight.x - viewport.right;
                        c.horizontalScrollPosition += delta;
                        topLeft.x -= delta;
                        viewportChanged = true;
                    }

                    if (topLeft.x < viewport.left) {
                        // leave it a few pixels in from the left
                        c.horizontalScrollPosition -= 
                            viewport.left - topLeft.x + 2;
                        viewportChanged = true;
                    }
                    
                    if (bottomRight.y > viewport.bottom) {
                        delta = bottomRight.y - viewport.bottom;
                        c.verticalScrollPosition += delta;
                        topLeft.y -= delta;
                        viewportChanged = true;
                    }
                    
                    if (topLeft.y < viewport.top) {
                        // leave it a few pixels down from the top
                        c.verticalScrollPosition -= 
                            viewport.top - topLeft.y + 2;
                        viewportChanged = true;
                    }
                    
                    // You must the validateNow() method to get the 
                    // container to move the component before working 
                    // on the next parent.
                    // Otherwise, your calculations will be incorrect.
                    if (viewportChanged) {
                        c.validateNow();
                    }
                }
                
                target = target.parent;
            }
            
            while (target != this);
        }
        ]]>
    </mx:Script>
    
    <mx:Model id="statesModel" source="assets/states.xml"/>
    <mx:Panel 
            x="58" y="48" 
            width="442" height="201" 
            layout="absolute"
            title="Tab through controls to see if focus stays in view">
            
        <mx:VBox x="10" y="10" verticalScrollPolicy="off">
            <mx:TextInput/>
            <mx:TextInput/>
            <mx:TextArea width="328" height="64"/>
            <mx:ComboBox dataProvider="{cards}" width="150"/>
            <mx:DataGrid dataProvider="{forListDP}" />
            <mx:DateChooser yearNavigationEnabled="true"/>
            <mx:List id="source" 
                width="75" 
                dataProvider="{statesModel.state}"/>
        </mx:VBox>
    </mx:Panel>
</mx:Application>