zoukankan      html  css  js  c++  java
  • Flex样式工作原理

    播放头前进到第二桢,docFrameHandler 函数开始执行。
    首先会执行很多Singleton.registerClass方法,然后执行有[Mixin]元标签的类的
    public static function init(fbs:IFlexModuleFactory):void 方法
     
    Flex编译器编译时会生成很多 有[Mixin]元标签的类 其中大部分类都与样式有关,象下面这些
     
    程序代码
    "_alertButtonStyleStyle", "_ScrollBarStyle",
    "_activeTabStyleStyle", "_textAreaHScrollBarStyleStyle",
    "_ToolTipStyle", "_advancedDataGridStylesStyle",
    "_comboDropdownStyle", "_comboDropDownStyle",
    "_ContainerStyle", "_textAreaVScrollBarStyleStyle",
    "_linkButtonStyleStyle", "_globalStyle", "_windowStatusStyle",
    "_windowStylesStyle", "_activeButtonStyleStyle",
    "_errorTipStyle", "_richTextEditorTextAreaStyleStyle",
    "_CursorManagerStyle", "_todayStyleStyle", "_dateFieldPopupStyle",
    "_plainStyle", "_dataGridStylesStyle", "_ApplicationStyle",
    "_headerDateTextStyle", "_ButtonStyle", "_VScrollBarStyle",
    "_popUpMenuStyle", "_swatchPanelTextFieldStyle",
    "_opaquePanelStyle", "_weekDayStyleStyle", "_headerDragProxyStyleStyle"

    类,他们的作用就是把样式信息注册到 StyleManager,这样在生成组件的时候组件能得到自己的样式信息。

    在flex builder 安装目录下的 sdks\3.0.0\frameworks\libs 目录有一个framework.swc 文件,你用Winrar 打开会看到 defaults.css这个文件。Defaults.css文件定义了flex组件的默认样式,这里的每一个css选择符(selector)就对应上面的一个类。其实上面的那些类是flex编译器按照这个defaults.css 文件在编译时自动生成的。
    下面就是其生成的_ButtonStyle 类:
     
    程序代码

    package
    {

    import flash.display.Sprite;
    import mx.core.IFlexModuleFactory;
    import mx.core.mx_internal;
    import mx.styles.CSSStyleDeclaration;
    import mx.styles.StyleManager;
    import mx.skins.halo.ButtonSkin;

    [ExcludeClass]

    public class _ButtonStyle
    {

        public static function init(fbs:IFlexModuleFactory):void
        {
            var style:CSSStyleDeclaration = StyleManager.getStyleDeclaration("Button");
        
            if (!style)
            {
                style = new CSSStyleDeclaration();
                StyleManager.setStyleDeclaration("Button", style, false);
            }
        
            if (style.defaultFactory == null)
            {
                style.defaultFactory = function():void
                {
                    this.paddingTop = 2;
                    this.textAlign = "center";
                    this.skin = mx.skins.halo.ButtonSkin;
                    this.paddingLeft = 10;
                    this.fontWeight = "bold";
                    this.cornerRadius = 4;
                    this.paddingRight = 10;
                    this.verticalGap = 2;
                    this.horizontalGap = 2;
                    this.paddingBottom = 2;
                };
            }
        }
    }

    }

    看完了就明白了吧,也就是说当这些类的  init(fbs:IFlexModuleFactory)方法执行完后,我们就可以通过    StyleManager.getStyleDeclaration(selector:String):CSSStyleDeclaration  方法获得在 defaluts.css文件中定义的样式信息。

    需要注意的是如果你在编译时添加了其他的主题,那么主题的样式会覆盖 defaluts.css文件中的样式。
    假如你的主题 中定义了
     
    程序代码
    Button
    {
        cornerRadius: 8;
    }

    那么你的 _ButtonStyle类中的 this.cornerRadius = 8; 而不是 this.cornerRadius = 4;
    当然你在主题中添加的新的css选择符在编译时也会生成相对应的类。比如你在主题中增加了
     
    程序代码
    .flashshe
    {
        color: #ff0000;
    }

    那么编译器编译时会生成一个
     
    程序代码
    1. package    
    2. {   
    3.   
    4. import flash.display.Sprite;   
    5. import mx.core.IFlexModuleFactory;   
    6. import mx.core.mx_internal;   
    7. import mx.styles.CSSStyleDeclaration;   
    8. import mx.styles.StyleManager;   
    9.   
    10. [ExcludeClass]   
    11.   
    12. public class _FlashsheStyle   
    13. {   
    14.   
    15.     public static function init(fbs:IFlexModuleFactory):void  
    16.     {   
    17.         var style:CSSStyleDeclaration = StyleManager.getStyleDeclaration(".flashshe");   
    18.        
    19.         if (!style)   
    20.         {   
    21.             style = new CSSStyleDeclaration();   
    22.             StyleManager.setStyleDeclaration(".flashshe", style, false);   
    23.         }   
    24.        
    25.         if (style.defaultFactory == null)   
    26.         {   
    27.             style.defaultFactory = function():void  
    28.             {   
    29.                 this.color = 0xff0000;   
    30.             };   
    31.         }   
    32.     }   
    33. }   
    34.   
    35. }  
    package { import flash.display.Sprite; import mx.core.IFlexModuleFactory; import mx.core.mx_internal; import mx.styles.CSSStyleDeclaration; import mx.styles.StyleManager; [ExcludeClass] public class _FlashsheStyle { public static function init(fbs:IFlexModuleFactory):void { var style:CSSStyleDeclaration = StyleManager.getStyleDeclaration(".flashshe"); if (!style) { style = new CSSStyleDeclaration(); StyleManager.setStyleDeclaration(".flashshe", style, false); } if (style.defaultFactory == null) { style.defaultFactory = function():void { this.color = 0xff0000; }; } } } }

    类。在执行 Main.mxml (假设我们的Flex工程的主文件为Main.mxml)类的构造函数时会调用StyleManager.mx_internal::initProtoChainRoots();方法,执行完后 StyleManager.stylesRoot属性 指向一个 Object,通过这个 Object我们就可以访问到defaults.css文件中Global css 选择符定义的样式信息,如果你的Global css 选择符中定义了  color: #0B333C;   那么StyleManager.stylesRoot[color]的值就为 0x0B333C。(注意这些都是 flex框架的内部方法,所以你不要尝试去访问,大部分情况下如果你访问的话编译器会报错,即使能访问,也不要去做)

    当我们在flex中调用 addChild(child)的时候,其中包含了下面几步:
    程序代码
    addingChild(child);
    $addChildAt(child, index);
    childAdded(child);

    看如下一个mxml文件:
    程序代码

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://uh.9ria.com/link.php?url=http://www.adobe.com%2F2006%2Fmxml"
        layout="absolute" xmlns:ns1="*">
        
        <mx:Style source="one.css"/>
        <mx:Style>
            .myBtn
            {
                color: #00ff00;
                fontSize: 14;    
            }
        </mx:Style>
        <!--  MyButton 组件 从 Button 继承 -->
        <ns1:MyButton id="testBtn" x="27" y="200" color="#0000ff" styleName="myBtn"/>
        
    </mx:Application>

    程序代码

    /* one.css */

    Button
    {
        color: #ff0000;
    }

    MyButton
    {
        fontWeight: 16;
    }

    当生成 MyButton 时 过程如下:
    首先调用 addingChild(testBtn), 在这个方法里面
    1,获得 Global css 选择符中定义的样式的一份拷贝(通过 StyleManager.stylesRoot);
    2,查找 Button css 选择符,将里面的样式添加到global拷贝中,同名的样式就覆盖;
    3,查找 MyButton css 选择符,将里面的样式添加到global拷贝中,同名的样式就覆盖;
    查找完type selector后开始查找class selector
    4, 查找 .myBtn css 选择符,将里面的样式添加到global拷贝中,同名的样式就覆盖;
    查找完 class selector 后开始查找inline style
    4,将 color="#0000ff" 样式添加到global拷贝中,同名的样式就覆盖;

    最后将这些样式信息存储到 UIComponent的inheritingStyles 和 nonInheritingStyles 属性中。这样调用UIComponent.getStyle(styleProp:String):* 就可以得到正确的样式值了。

    Flex框架通过这种方式,我们就可以在组件创建过程中得到组件的样式信息,方便我们在createChildren(),commitProperties(),layoutChrome(),measure(),updateDisplayList()方法中访问。在组件的构造函数中就不要使用 UIComponent.getStyle(styleProp:String):* 方法,因为你调用getStyle方法返回的是null。样式信息是用来渲染组件用的,所以没有必要在构造函数中使用。
     
    每当组件需要重新设置自己的样式时(比如说调用了setStyle()方法或者设置了styleName属性),组件的styleChanged(styleProp:String)方法就会被调用,然后我们在styleChanged(styleProp:String)方法体里面根据参数styleProp的值的不同来对组件的样式做出相应的处理。那么什么时候组件的styleChanged(styleProp:String)方法会触发呢?下面介绍如下:

    1,setStyle()方法
    当我们调用setStyle()方法的时候,首先会调用该组件的styleChanged(styleProp)然后判断改变的样式是否是可继承样式,如果是,则调用该组件的所有子孙的styleChanged(styleProp)方法。比如:
     
    程序代码
    <mx:Canvas id="myCanvas">
        <mx:Vbox id="box" x="0" y="10" width="200">
            <mx:Label id="text1" text="@Resource(key='name', bundle='test')" color="#ff0000"/>
            <mx:Label id="text2" text="@Resource(key='age', bundle='test')" styleName="ageLabel"/>
            <mx:Label id="text3" text="@Resource(key='sex', bundle='test')"/>
            <mx:Label id="text4" text="{resourceManager.getString('test', 'sex')}"/>
        </mx:Vbox>
        <mx:Button id="myBtn" x="27" y="100" label="change" click="changeHandler(event)"/>    
    </mx:Canvas>  

    当我们调用 myCanvas.setStyle("color", 0xff0000)的时候,首先会重新设置该组件的样式缓存(CSS style cache),
    这样调用myCanvas.getStyle("color")时就能得到值0xff0000。然后调用myCanvas.styleChanged("color"); 因为
    color是可继承样式,所以会接着调用box.styleChanged("color"),text1.styleChanged("color"),text2.styleChanged("color"),text3.styleChanged("color"),text4.styleChanged("color"),myBtn.styleChanged("color");
    当我们调用 myCanvas.setStyle("backgroundColor", 0xff0000)的时候,首先调用myCanvas.styleChanged("backgroundColor")因为backgroundColor不是可继承样式,所以myCanvas的子孙的styleChanged(styleProp)方法不会被调用。

    2. addChild(chlid)的时候
    当我们使用addChild(chlid)时,首先会重新设置该组件和该组件的子孙的样式缓存,然后调用chlid.styleChanged(null) 和chlid的子孙的styleChanged(null)方法。

    3, 设置 styleName
    当我们给一个组件(比如实例名是child)设置styleName属性时,首先会重新设置该组件和该组件的子孙的样式缓存,然后调用chlid.styleChanged("styleName")和chlid的子孙的styleChanged("styleName")方法。

    4, 运行时载入样式表单
    运行时载入样式表单我们通常会使用StyleManager.loadStyleDeclarations(url:String, update:Boolean = true, trustContent:Boolean = false, applicationDomain:ApplicationDomain = null, securityDomain:SecurityDomain = null)方法。当把参数update设置为true时表示样式表单载入完成后马上更新样式。其原理是:样式表单载入完成后程序中的所有组件会重新设置组件的样式缓存,并调用组件的styleChanged(null)方法。

    当我们建立一个ActionScript自定义组件(ActionScript Custom Components),并且该组件支持自定义样式的时候,我们的组件类里面必须要有一个

     
    程序代码
    override public function styleChanged(styleProp:String):void
    {
        // 方法体
    }
    方法。为什么呢?应为如果没有这个方法,你怎么来检测你的样式的改变呢?
    通过我上面的分析,相信你一定能设计出一个出色的适应Flex框架的支持自定义样式的组件。关于“自定义组件支持自定义样式”你可以参考Flex帮助文档里面的 ActionScript Custom Components / Custom Style Properties 一节。

    下面是 UIComponent 组件里面的styleChanged(styleProp:String):void方法的定义,和本文无关,只是方便我自己查阅而放在这里。
     
    程序代码
    1. /**  
    2.      *  Detects changes to style properties. When any style property is set,  
    3.      *  Flex calls the <code>styleChanged()</code> method,  
    4.      *  passing to it the name of the style being set.  
    5.      *  
    6.      *  <p>This is an advanced method that you might override  
    7.      *  when creating a subclass of UIComponent. When you create a custom component,  
    8.      *  you can override the <code>styleChanged()</code> method  
    9.      *  to check the style name passed to it, and handle the change accordingly.  
    10.      *  This lets you override the default behavior of an existing style,  
    11.      *  or add your own custom style properties.</p>  
    12.      *  
    13.      *  <p>If you handle the style property, your override of  
    14.      *  the <code>styleChanged()</code> method should call the  
    15.      *  <code>invalidateDisplayList()</code> method to cause Flex to execute  
    16.      *  the component's <code>updateDisplayList()</code> method at the next screen update.</p>  
    17.      *  
    18.      *  @param styleProp The name of the style property, or null if all styles for this  
    19.      *  component have changed.  
    20.      */  
    21.     public function styleChanged(styleProp:String):void  
    22.     {   
    23.         // If font changed, then invalidateProperties so   
    24.         // we can re-create the text field in commitProperties   
    25.         if (this is IFontContextComponent && hasFontContextChanged())   
    26.             invalidateProperties();   
    27.            
    28.         // Check to see if this is one of the style properties   
    29.         // that is known to affect layout.   
    30.   
    31.         If (!styleProp ||   
    32.             styleProp == "styleName" ||   
    33.             StyleManager.isSizeInvalidatingStyle(styleProp))   
    34.         {   
    35.             // This style property change may affect the layout of this   
    36.             // object. Signal the LayoutManager to re-measure the object.   
    37.             invalidateSize();   
    38.         }   
    39.   
    40.         if (!styleProp ||    
    41.             styleProp == "styleName" ||   
    42.             styleProp == "themeColor")   
    43.         {   
    44.             initThemeColor();   
    45.         }   
    46.            
    47.         invalidateDisplayList();   
    48.   
    49.         if (parent is Iinvalidating)   
    50.         {   
    51.             if (StyleManager.isParentSizeInvalidatingStyle(styleProp))   
    52.                 Iinvalidating(parent).invalidateSize();   
    53.   
    54.             if (StyleManager.isParentDisplayListInvalidatingStyle(styleProp))   
    55.                 Iinvalidating(parent).invalidateDisplayList();   
    56.         }   
    57.     }  
  • 相关阅读:
    高级特性(4)- 数据库编程
    UVA Jin Ge Jin Qu hao 12563
    UVA 116 Unidirectional TSP
    HDU 2224 The shortest path
    poj 2677 Tour
    【算法学习】双调欧几里得旅行商问题(动态规划)
    南洋理工大学 ACM 在线评测系统 矩形嵌套
    UVA The Tower of Babylon
    uva A Spy in the Metro(洛谷 P2583 地铁间谍)
    洛谷 P1095 守望者的逃离
  • 原文地址:https://www.cnblogs.com/sevenyuan/p/1661561.html
Copyright © 2011-2022 走看看