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.     }  
  • 相关阅读:
    STL: merge
    STL: rotate
    javascript的prototype继承问题
    日期正则表达式
    有关linq的一系列学习的文章,值得收藏
    EF读取关联数据
    jQuery UI中的日期选择插件Datepicker
    LINQ的基本语法中八个关键字用法说明
    Shell变量内容的删除、替代与替换
    Shell命令别名与历史命令
  • 原文地址:https://www.cnblogs.com/sevenyuan/p/1661561.html
Copyright © 2011-2022 走看看