淺析 Flex中的Focus

一、無焦點的困擾——組件監聽不到鍵盤事件 
原因:只有獲得焦點的組件(確切說是InteractiveObject)才能監聽到鍵盤事件的目標階段;鍵盤事件(flash.events.KeyboardEvent)參與冒泡階段,所以焦點組件的父項(以及它爸爸的爸爸的爸爸……)亦可在事件的冒泡階段監聽到該事件。 
簡單來說:只有組件本身或者其子孫項獲得焦點後,才能監聽到鍵盤事件。 

二、獲得焦點 

1、設置焦點——setFocus() 
Flex 的UIComponent 的setFocus() 方法可以設置焦點;調用此方法最終會將自身賦值給 systemManager.stage.focus 
另外還可以採用focusManager.setFocus(IFocusManagerComponent) 給組件設置焦點; 

2、 swf 獲得焦點 
如果swf嵌入到html中,首先要保證該swf在DOM中獲得焦點;[code=“JavaScript”] document.getElementById([swfId]).focus(); 爲方便起見,可直接修改 flex 的模板 index.template.html;[code=“JavaScript”] 
<body scroll="no" onload=’document.getElementById("${application}").focus();’> 
(詳見附件的模板文件) 

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

4、鼠標點擊獲得焦點 
——我更希望組件能夠像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();} 

該例子詳見附件。 
下面會介紹 IFocusManagerComponent 接口,並研究 究竟如何實現鼠標點擊獲得焦點的。 

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

三、介紹IFocusManagerComponent 

見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”添加到類定義即可。 

四、鼠標按下獲得焦點分析。 

當FocusManager被激活時,會給其管轄容器添加監聽器:[code=“ActionScript”] 
form.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler); 
監聽器代碼摘要:[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=“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; 

受FocusManger管理的組件的幾個條件: 
1、實現 IFocusManagerComponent 
2、focusEnabled、mouseFocusEnabled、enabled三個屬性皆爲true 
3、bridge情況下(還不瞭解bridge 請大俠zhijiao) 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章