天天看點

淺析 Flex中的Focus

關鍵字:focus、 setFocus、 IFocusManager、KeyboardEvent

焦點、設定焦點、獲得焦點、鍵盤事件

[size=medium]一、無焦點的困擾——元件監聽不到鍵盤事件[/size]

原因:隻有獲得焦點的元件(确切說是InteractiveObject)才能監聽到鍵盤事件的目标階段;鍵盤事件(flash.events.KeyboardEvent)參與冒泡階段,是以焦點元件的父項(以及它爸爸的爸爸的爸爸……)亦可在事件的冒泡階段監聽到該事件。

簡單來說:隻有元件本身或者其子孫項獲得焦點後,才能監聽到鍵盤事件。

[size=medium]二、獲得焦點[/size]

[size=small][color=blue]1、設定焦點——setFocus()[/color][/size]

Flex 的UIComponent 的setFocus() 方法可以設定焦點;調用此方法最終會将自身指派給 systemManager.stage.focus

另外還可以采用focusManager.setFocus(IFocusManagerComponent) 給元件設定焦點;

[size=small][color=blue]2、 swf 獲得焦點[/color][/size]

如果swf嵌入到html中,首先要保證該swf在DOM中獲得焦點;[code=“JavaScript”] document.getElementById([swfId]).focus(); [/code]為友善起見,可直接修改 flex 的模闆 index.template.html;[code=“JavaScript”]

<body scroll="no" οnlοad=’document.getElementById("${application}").focus();’>

[/code](詳見附件的模闆檔案)

[size=small][color=blue]3、注意焦點轉移[/color][/size]

需要注意的時,随着swf與使用者的互動 或者 彈出Alert窗框或者Popup元件、抑或是某些代碼執行 都有可能引起焦點的轉移;如果有需要便要采用setFocus() 重設焦點。

[size=small][color=blue]4、滑鼠點選獲得焦點[/color][/size]

——我更希望元件能夠像TextInput那樣滑鼠點選即可獲得焦點

——很簡單監聽 MouseEvent.MOUSE_DOWN 然後setFoucus() 即可;

——不!有更簡單的,隻需讓你的元件實作 IFocusManagerComponent 接口即可。

UIComponent 已經實作了 IFocusManagerComponent 接口,隻是沒有顯示的标明而已,是以需要某元件具有滑鼠點選獲得焦點的功能時,隻需 顯示聲明 implements IFocusManagerComponent 即可。當然有特殊需求的還要覆寫某些方法,比方TextInput 就覆寫了 setFocus() 方法。(具體見源碼。)

例如:讓圖檔具有點選獲得焦點特性:[code=“ActionScript”]

public class MyImage extends Image implements IFocusManagerComponent {

public function MyImage() { super();}

}

[/code]該例子詳見附件。

下面會介紹 IFocusManagerComponent 接口,并研究 究竟如何實作滑鼠點選獲得焦點的。

[size=small][color=blue]5、例外[/color][/size]

如果隻監聽整個應用的鍵盤事件,不需具體到某個元件,可以考慮用給 stage添加監聽,這樣就不用考慮煩人的焦點問題。

[size=medium]三、介紹IFocusManagerComponent[/size]

見API文檔,從focusManager.setFocus(IFocusManagerComponent) 順藤摸瓜,某些元件已經實作了IFocusManagerComponent 接口。

包 mx.managers.IFocusManagerComponent

Interface public interface IFocusManagerComponent

實作器 Accordion, AdvancedListBase, Button, ButtonBar, ChartBase, ComboBase, DateChooser, DateField, HTML, ListBase, MenuBar, NumericStepper, TabNavigator, TextArea, TextInput, UIMovieClip

IFocusManagerComponent 接口用于定義一些接口,可獲得焦點的元件必須實作這些接口才能從 FocusManager 獲得焦點。UIComponent 類中提供了此接口的基本實作,但 UIComponent 并不實作完整的 IFocusManagerComponent 接口,因為部分 UIComponent 無需獲得焦點。是以,要使 UIComponent 派生的元件成為一個可獲得焦點的有效元件,隻需将“implements IFocusManagerComponent”添加到類定義即可。

[size=medium]四、滑鼠按下獲得焦點分析。[/size]

當FocusManager被激活時,會給其管轄容器添加監聽器:[code=“ActionScript”]

form.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);

[/code]監聽器代碼摘要:[code=“ActionScript”]

private function mouseDownHandler(event:MouseEvent):void {

if (event.isDefaultPrevented()) return;

//從事件目标開始查找頂級的實作可設定焦點的元件

var o:DisplayObject = getTopLevelFocusTarget(

InteractiveObject(event.target));

if (!o) return;

if ((o != _lastFocus || lastAction == "ACTIVATE") && !(o is TextField))

setFocus(IFocusManagerComponent(o));

}

[/code][code=“ActionScript”]

private function getTopLevelFocusTarget (o:InteractiveObject):InteractiveObject {

//此處可以看到可設定焦點的元件需要滿足的幾個條件:

while (o != InteractiveObject(form)) {

if (o is IFocusManagerComponent &&

IFocusManagerComponent(o).focusEnabled &&

IFocusManagerComponent(o).mouseFocusEnabled &&

(o is IUIComponent ? IUIComponent(o).enabled : true))

return o;

// if we cross a boundry into a bridged application, then return null so

// the target is only processed at the lowest level

if (o.parent is ISWFLoader) {

if (ISWFLoader(o.parent).swfBridge)

return null;

}

o = o.parent;

if (o == null)

break;

}

return null;

}

[/code]受FocusManger管理的元件的幾個條件:

[size=small][color=blue]1、實作 IFocusManagerComponent[/color][/size]

[size=small][color=blue]2、focusEnabled、mouseFocusEnabled、enabled三個屬性皆為true[/color][/size]

[size=small][color=blue]3、bridge情況下(還不了解bridge 請大俠zhijiao)[/color][/size]