zoukankan      html  css  js  c++  java
  • Andriod中Style/Theme原理以及Activity界面文件选取过程浅析

     

          通过对前面的一篇博文<从setContentView()谈起>的学习,我们掌握了Activity组件布局文件地创建过程以及

     其顶层控件DecorView,今天我们继续庖丁解牛---深入到其中的generateLayout()方法,步步为营掌握一下内容:

             1、Activity中Theme(主题)的系统定义以及使用之处;

             2、如何根据设置的Feature(属性)选择合适的布局文件。

     另外,对于下文中Theme和Style的概念进行一个简要说明:

          都是由<style />节点进行定义的。但应用在<application />和<activity />则为theme,应用在<View />则为style.

    一、关于Theme主题的使用方法以及原理分析

        通常来说,可以直接使用系统定义好的Style/Theme,毕竟,系统为我们提供了丰富地选择。当然,你也可以

     自定义Theme,前提是该Theme必须继承与某个已经存在地Theme,否则编译器会提示错误的。

      1、 应用Theme属性两种方式

          ①、在AndroidManifest.xml文件中在<application/>或者<activity />节点设置android:theme属性.

          ②、直接在代码中调用方法setTheme()设置该Activity的主题,必须得在第一次调用setContentView()前设置,

      否则,也是没有效果的(具体原因可见后面分析)。

      2、原理分析

          Android的所有系统资源定义位置存放在 frameworksasecore es 路径下,编译时会形成apk文件,即

     framework-res.apk,所有应用程序共享。

         实际上任何Style/Theme也是一组自定义属性集合,其内置在Android系统资源中,如下所示:

                文件路径:frameworksasecore es esvaluesattrs.xml

    1. <!-- The set of attributes that describe a Windows's theme. -->  
    2.   <declare-styleable name="Window">  
    3.       <!-- 常见的Window属性  -->  
    4.         
    5.       <attr name="windowBackground" />        //该界面所对应的背景图片, drawable / color  
    6.       <attr name="windowFrame" />             //该界面所对应的前景frontground图片, drawable / color  
    7.       <attr name="windowNoTitle" />           //是否带有title , boolean类型        
    8.       <attr name="windowFullscreen" />        //是否全屏  ,  boolean类型        
    9.       <attr name="windowIsFloating" />        //是否是悬浮窗类型 , boolean类型       
    10.       <attr name="windowIsTranslucent" />     //是否透明 , boolean类型       
    11.       <attr name="windowSoftInputMode" />     //设置键盘弹出来的样式 , 例如: adjustsize 等 ,其实也是int类型  
    12.         
    13.       <!-- more 更多不常见地Window属性-->  
    14.       ...  
    15.       
    16.   </declare-styleable>  

          特殊的是如果某个自定义属性如果没有指名 format属性,那么该属性必须在当前已经定义,即该属性只是一个

      别名。

          大部分Android属性定义在 name = "Theme"的属性集合下(仅列出Window attrs):   

              文件路径:frameworksasecore es esvaluesattrs.xml

    1. <!-- These are the standard attributes that make up a complete theme. -->  
    2. <declare-styleable name="Theme">  
    3.     <!-- Drawable to use as the overall window background.  There are a  
    4.          few special considerations you should use when settings this  
    5.          drawable:  
    6.     -->  
    7.     <attr name="windowBackground" format="reference" />  
    8.     <!-- Drawable to use as a frame around the window. -->  
    9.     <attr name="windowFrame" format="reference" />  
    10.     <!-- Flag indicating whether there should be no title on this window. -->  
    11.     <attr name="windowNoTitle" format="boolean" />  
    12.     <!-- Flag indicating whether this window should fill the entire screen. -->  
    13.     <attr name="windowFullscreen" format="boolean" />  
    14.     <!-- Flag indicating whether this is a floating window. -->  
    15.     <attr name="windowIsFloating" format="boolean" />  
    16.     <!-- Flag indicating whether this is a translucent window. -->  
    17.     <attr name="windowIsTranslucent" format="boolean" />  
    18.     <!-- Flag indicating that this window's background should be the  
    19.          user's current wallpaper. -->  
    20.     <attr name="windowShowWallpaper" format="boolean" />  
    21.     <!-- This Drawable is overlaid over the foreground of the Window's content area, usually  
    22.          to place a shadow below the title.  -->  
    23.     <!-- This Drawable is overlaid over the foreground of the Window's content area, usually  
    24.          to place a shadow below the title.  -->  
    25.     <attr name="windowContentOverlay" format="reference" />      
    26.     <!--more -->       
    27.  </declare-styleable>  
       

         属性定义如上,Android系统中这些属性定义了很多Style/Theme ,常见的有如下 :

    1. android:theme="Theme"            //默认地Theme  
    2. android:theme="Theme.Light"      //背景为白色    
    3. android:theme="Theme.Light.NoTitleBar"              //白色背景并无标题栏     
    4. android:theme="Theme.Light.NoTitleBar.Fullscreen"  //白色背景,无标题栏,全屏    
    5. android:theme="Theme.Black"                        //背景黑色    

         名称为"Theme"属性(系统默认的Theme)的定义为(仅copy部分关于Window属性的定义) : 

                      文件位于:frameworksasecore es esvalues hemes.xml

    1. <style name="Theme">  
    2.   <!-- Window attributes -->  
    3.   <item name="windowBackground">@android:drawable/screen_background_dark</item>  
    4.   <item name="windowFrame">@null</item>  
    5.   <item name="windowNoTitle">false</item>  
    6.   <item name="windowFullscreen">false</item>  
    7.   <item name="windowIsFloating">false</item>  
    8.   <item name="windowTitleSize">25dip</item>  
    9.   <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground</item>  
    10.   <item name="android:windowAnimationStyle">@android:style/Animation.Activity</item>  
    11.   <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>      
    12. lt;/style>  

          该Theme作为一个超元素集,所有其他的Style/Theme则继承了它。例如:我们关于自定义的Theme必须显示从

      一个父Theme继承,如下:

    1. <!--自定义Theme 必须制定parent属性-->  
    2. <style name="CustomTheme" parent="@android:style/Theme" >  
    3.    <item name="android:windowNoTitle">true</item>  
    4.    <item name="android:windowFrame">@drawable/icon</item>  
    5.    <item name="android:windowBackground">?android:windowFrame</item>  
    6. </style>  
            我们看看Android另外一个Theme.NoTitleBar属性定义,默认继承了"Theme"集合。
    1. <!-- Variant of the default (dark) theme with no title bar -->  
    2.    <style name="Theme.NoTitleBar">  
    3.        <item name="android:windowNoTitle">true</item>  
    4.    </style>  

        其实xml文件中声明的任何元素(包括属性),必须通过代码去获取他们的值,然后进行适当地逻辑运算。那么

     系统是在什么地方去解析这些Window属性,并且选择合适地布局文件?

    二、Theme主题的解析以及布局文件的选取

          如果对setContentView()调用过程不太熟悉的朋友,可以先看看前面一篇博文<从setContentView()谈起>

     今天我们深入到其中generateLayout()方法,该方法地主要作用就是解析这些Window属性,然后选择合适地

      布局文件作为我们地Activity或者Window界面地承载布局文件,即DecorView的直接子View。

        在进行具体分析之前,Android还提供了另外两种简单API让我们制定界面的风格,如下两个方法:
        
         1、requestFeature() 设定个该界面的风格Feature,例如,FEATURE_NO_TITLE(没有标题) 、 

           FEATURE_PROGRESS(标题栏带进度条) 。必须在setContentView()前调用,否则会报异常。 

                FEATURE属性定义在Window.java类
              
        2、getWindow().setFlags(),为当前的WindowManager.LayoutParams添加一些Flag。

                Flag标记定义在WindowManager.LayoutParams.java类。

          
       通过这两种方法隐藏状态栏和标题栏的例子为:

    1. @Override  
    2. public void onCreate(Bundle savedInstanceState) {  
    3.     super.onCreate(savedInstanceState);  
    4.     // hide titlebar of application  
    5.     // must be before setting the layout  
    6.     requestWindowFeature(Window.FEATURE_NO_TITLE);  
    7.     // hide statusbar of Android  
    8.     // could also be done later  
    9.     getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,  
    10.             WindowManager.LayoutParams.FLAG_FULLSCREEN);  
    11.     setContentView(R.layout.main);  
    12. }  
        完整例子,可见于博文<Android隐藏状态栏和标题栏,相当于全屏效果>

          源码分析:

             这两个方法是在Window.java类实现的,如下:

    1. public class Window {  
    2.      /** Flag for the "options panel" feature.  This is enabled by default. */  
    3.     public static final int FEATURE_OPTIONS_PANEL = 0;  
    4.     /** Flag for the "no title" feature, turning off the title at the top 
    5.      *  of the screen. */  
    6.     public static final int FEATURE_NO_TITLE = 1;      
    7.     /** Flag for the progress indicator feature */  
    8.     public static final int FEATURE_PROGRESS = 2;  
    9.     /** Flag for having an icon on the left side of the title bar */  
    10.     public static final int FEATURE_LEFT_ICON = 3;  
    11.     /** Flag for having an icon on the right side of the title bar */  
    12.     public static final int FEATURE_RIGHT_ICON = 4;  
    13.     /** Flag for indeterminate progress */  
    14.     public static final int FEATURE_INDETERMINATE_PROGRESS = 5;  
    15.     /** Flag for the context menu.  This is enabled by default. */  
    16.     public static final int FEATURE_CONTEXT_MENU = 6;      // 菜单  
    17.     /** Flag for custom title. You cannot combine this feature with other title features. */  
    18.     public static final int FEATURE_CUSTOM_TITLE = 7;  
    19.       
    20.     //默认的FEATURES FEATURE_OPTIONS_PANEL & FEATURE_CONTEXT_MENU   
    21.     protected static final int DEFAULT_FEATURES = (1 << FEATURE_OPTIONS_PANEL) |  
    22.             (1 << FEATURE_CONTEXT_MENU);  
    23.     //局部变量保存  保存设置的Feature ,按位操作。  
    24.     private int mFeatures = DEFAULT_FEATURES;  
    25.       
    26.     //设置Feature , 按位操作添加进去  
    27.     public boolean requestFeature(int featureId) {  
    28.         final int flag = 1<<featureId;      
    29.         mFeatures |= flag;    
    30.         //当该Activity是否是某个Activity的子Activity,mContainer即代表父Activity的Window对象,一般为null  
    31.         mLocalFeatures |= mContainer != null ? (flag&~mContainer.mFeatures) : flag;  
    32.         return (mFeatures&flag) != 0;  
    33.     }  
    34.       
    35.     public void addFlags(int flags) {  
    36.         setFlags(flags, flags);  
    37.     }  
    38.      
    39.     /** 
    40.      * Set the flags of the window, as per the 
    41.      * {@link WindowManager.LayoutParams WindowManager.LayoutParams} 
    42.      * flags. 
    43.      * <p>Note that some flags must be set before the window decoration is 
    44.      * created . 
    45.      * These will be set for you based on the {@link android.R.attr#windowIsFloating} 
    46.      * attribute. 
    47.      * @param flags The new window flags (see WindowManager.LayoutParams). 
    48.      * @param mask Which of the window flag bits to modify. 
    49.      */  
    50.     //mask代表对应为的掩码,设置对应位时,需要先清空对应位的掩码,然后在进行或操作。类似的函数可以见于View.java类的setFlags()方法  
    51.     public void setFlags(int flags, int mask) {  
    52.         final WindowManager.LayoutParams attrs = getAttributes(); //当前的WindowManager.LayoutParams属性  
    53.         //将设置的flags添加至attrs属性中  
    54.         attrs.flags = (attrs.flags&~mask) | (flags&mask);    
    55.         mForcedWindowFlags |= mask;  
    56.         if (mCallback != null) {    //Activity 和 Dialog 默认实现了Window.Callback接口  
    57.             mCallback.onWindowAttributesChanged(attrs);  //回调onWindowAttributesChanged()方法  
    58.         }  
    59.     }  
    60.     ...  
    61. }       

       其实也挺简单的,主要是逻辑运算符的操作。
              mFeatures  代表了当前Window的Feature值.
              flags           保存在当前WindowManager.LayoutParams.flag属性中。

      接下来具体分析generateLayout()方法.

            如果当前界面的DecorView对象为空(一般由setContentView()或者addContentView()调用),则会创建一个

       DecorView对象以及对应的装载xml布局的mContentParent对象。

        Step 1、创建DecorView对象

    1. private void installDecor() {  
    2.     if (mDecor == null) {  
    3.         mDecor = generateDecor();  //创建一个DecorView对象  
    4.         mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);  //设置焦点捕获动作  
    5.     }  
    6.       
    7.     if (mContentParent == null) { //mContentParent作为我们自定义布局的Parent.  
    8.         mContentParent = generateLayout(mDecor);  //创建mContentParent。  
    9.         ...  
    10.     }  
    11. }  

          Step 2、创建mContentParent对象
    1. protected ViewGroup generateLayout(DecorView decor) {  
    2.     // Apply data from current theme.  
    3.     TypedArray a = getWindowStyle();   //获得当前的Theme属性对应的TypedArray对象.  
    4.        
    5.     //接下来都是对Attribute值的获取...,后续继续分析  
    6.     //是否是Dialog样式的界面 , android:windowIsFloating属性  
    7.     mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);  
    8.     ...  
    9. }  

        首先获取系统自定义的Style对应的TypeArray对象,然后获取对应的属性值。我们继续分析getWindowStyle()

     方法。

          2.1、

    1. /** 
    2.  * Return the {@link android.R.styleable#Window} attributes from this 
    3.  * window's theme. 
    4.  */  
    5. public final TypedArray getWindowStyle() {  
    6.     synchronized (this) {  
    7.         if (mWindowStyle == null) {  
    8.             //调用Context类的相应方法,返回对应的TypedArray对象,参数为自定义属性集合  <declare-styleable name="Window">  
    9.             mWindowStyle = mContext.obtainStyledAttributes(com.android.internal.R.styleable.Window);  
    10.         }  
    11.         return mWindowStyle;  
    12.     }  
    13. }  
            调用Context类对应地obtainStyledAttributes()方法,参数传递的是 Window对应的自定义属性集合。

       2.2、

    1. /** 
    2.  * Retrieve styled attribute information in this Context's theme.  See 
    3.  * {@link Resources.Theme#obtainStyledAttributes(int[])} 
    4.  * for more information. 
    5.  * 
    6.  * @see Resources.Theme#obtainStyledAttributes(int[]) 
    7.  */  
    8. public final TypedArray obtainStyledAttributes(  
    9.         int[] attrs) {  
    10.     //首先获取当前Theme对应的TypedArray对象  
    11.     return getTheme().obtainStyledAttributes(attrs);  
    12. }  
               由于Activity继承至ContextThemeWapprer类,ContextThemeWapprer重写了getTheme()方法。

         2.3

    1. @Override   
    2. public Resources.Theme getTheme() {  
    3.     if (mTheme != null) {              //第一次访问时,mTheme对象为null  
    4.         return mTheme;  
    5.     }  
    6.     // Theme 资源是否已经指定,没有选取默认Theme  
    7.     if (mThemeResource == 0) {          
    8.         mThemeResource = com.android.internal.R.style.Theme;  
    9.     }  
    10.     initializeTheme();   //初始化Theme资源  
    11.     return mTheme;  
    12. }  
          首先,判断是否是第一次调用该方法,即是否创建了mTheme对象;

         其次,判断是否设置了该Theme所对应的资源ID,如果没有,则选取默认的theme style 

                即com.android.internal.R.style.Theme 。

          最后,初始化对应资源。

    1. /** 
    2.  * Called by {@link #setTheme} and {@link #getTheme} to apply a theme 
    3.  * resource to the current Theme object.  Can override to change the 
    4.  * default (simple) behavior.  This method will not be called in multiple 
    5.  * threads simultaneously. 
    6.  * 
    7.  * @param theme The Theme object being modified. 
    8.  * @param resid The theme style resource being applied to <var>theme</var>. 
    9.  * @param first Set to true if this is the first time a style is being 
    10.  *              applied to <var>theme</var>. 
    11.  */  
    12. protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {  
    13.     theme.applyStyle(resid, true);  
    14. }  
    15.   
    16. private void initializeTheme() {  
    17.     final boolean first = mTheme == null;     //是否是第一次调用  
    18.     if (first) {  
    19.         mTheme = getResources().newTheme();     
    20.         Resources.Theme theme = mBase.getTheme();  //调用ContextImpl类的getTheme(),获取默认的Theme  
    21.         if (theme != null) {  
    22.             mTheme.setTo(theme);   //将theme配置应用到mTheme属性中  
    23.         }  
    24.     }  
    25.     onApplyThemeResource(mTheme, mThemeResource, first);  
    26. }  

          如果没有手动设置mThemeResource,则选取系统中为我们提供的默认Theme。当然我们也可以手动设置Theme 

     Resource ,如开篇所述。

                方法一: Activity中调用setTheme()方法,该方法会实现在ContextThemeWrapper.java类中。

    1. @Override   
    2. public void setTheme(int resid) {  
    3.     mThemeResource = resid;    //设置mThemeResource  
    4.     initializeTheme();  
    5. }  

             方法二:在AndroidManifest文件中,为Activity节点配置android:theme属性. 当通过startActivity()启动一个

     Activity时,会调用setTheme()方法。文件路径:frameworksasecorejavaandroidappActivityThread.java

    1. private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {  
    2.     ...  
    3.     Activity activity = null;  
    4.     try {  
    5.         //创建Activity实例  
    6.         java.lang.ClassLoader cl = r.packageInfo.getClassLoader();  
    7.         activity = mInstrumentation.newActivity(  
    8.                 cl, component.getClassName(), r.intent);  
    9.     }   
    10.     ...  
    11.     try {  
    12.         ...  
    13.         if (activity != null) {  
    14.             //创建相应的信息.  
    15.             ContextImpl appContext = new ContextImpl();  
    16.             appContext.init(r.packageInfo, r.token, this);  
    17.             appContext.setOuterContext(activity);  
    18.             CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());  
    19.             ...     
    20.             activity.attach(appContext, this, getInstrumentation(), r.token,  
    21.                     r.ident, app, r.intent, r.activityInfo, title, r.parent,  
    22.                     r.embeddedID, r.lastNonConfigurationInstance,  
    23.                     r.lastNonConfigurationChildInstances, config);  
    24.             ...  
    25.             //activityInfo相关信息是由ActivityManagerService通过IPC调用而来  
    26.             //可以参考Android SDK的ActivityInfo类 API。  
    27.             int theme = r.activityInfo.getThemeResource();  
    28.             if (theme != 0) {  
    29.                 activity.setTheme(theme); //调用setTheme()方法,参见方法1  
    30.             }  
    31.       ...  
    32.         }  
    33.     }  
    34.     ...    
    35.     return activity;  
    36. }  

         总结: 如果没有为设置Theme Resource ,则会选取默认的Theme Style,否则选用我们设置的Theme。

             因为mTheme对象是相对统一的,只不过每次都通过apply一个新的Style ID,感觉Android 框架会为每个

      应用程序的资源形成一个统一的资源库,应用程序定义的所有Style都存在在该资源库中,可以通过通过Style 

      ID值显示获取对应值集合。 但由于对系统获取资源的过程不了解,目前还不清楚Android中是如何根据资源ID

      获取对应的资源甚至一组资源的。但可喜的是,老罗目前正在研究这块,希望能在老罗的文章中找到答案。

                  具体可见 <

    Android资源管理框架(Asset Manager)简要介绍和学习计划

    >

      

         另外,Dialog的构造函数也有一定启发性,创建了一个指定Theme 的ContextThemeWapper对象,然后通过它创

      建对应的Window对象。 具体过程可以自行研究下。

    1. public Dialog(Context context, int theme) {  
    2.     //创建一个ContextThemeWrapper对象,指定 Theme ID  
    3.     mContext = new ContextThemeWrapper(  
    4.         context, theme == 0 ? com.android.internal.R.style.Theme_Dialog : theme);  
    5.     mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);  
    6.     //传递该ContextThemeWrapper对象,构造指定的ID.  
    7.     Window w = PolicyManager.makeNewWindow(mContext);  
    8.     ...  
    9. }  

        PS : Android 4.0 之后默认的属性为Theme_Holo,呵呵,Holo倒挺有意思的。调用相关函数时,会判断SDK 

    版本,然后选取相应地Theme。相关函数如下:   @ Resources.java 

    1. /** @hide */  
    2. public static int selectDefaultTheme(int curTheme, int targetSdkVersion) {  
    3.     return selectSystemTheme(curTheme, targetSdkVersion,  
    4.             com.android.internal.R.style.Theme,  
    5.             com.android.internal.R.style.Theme_Holo,  
    6.             com.android.internal.R.style.Theme_DeviceDefault);  
    7. }  
    8. /** @hide */  
    9. public static int selectSystemTheme(int curTheme, int targetSdkVersion,  
    10.         int orig, int holo, int deviceDefault) {  
    11.     //是否设置了Theme  
    12.     if (curTheme != 0) {  
    13.         return curTheme;  
    14.     }  
    15.     //判断版本号 , HONEYCOMB 代表 Android 3.0 , ICE_CREAM_SANDWICH 代表 Android 4.0   
    16.     if (targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) {  
    17.         return orig;  
    18.     }  
    19.     if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {  
    20.         return holo;  
    21.     }  
    22.     return deviceDefault;  
    23. }  


      Step 3、通过前面的分析,我们获取了Window属性对应的TypeArray对象,接下来就是获取对应的属性值。

     如下代码所示:

    1.    
    2. protected ViewGroup generateLayout(DecorView decor) {  
    3.     // Apply data from current theme.  
    4.     TypedArray a = getWindowStyle();   //获得当前的Theme属性对应的TypedArray对象.  
    5.        
    6.     //是否是Dialog样式的界面 , android:windowIsFloating属性  
    7.     mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);  
    8.     int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)   
    9.         & (~getForcedWindowFlags());  
    10.     //如果是Dialog样式,则设置当前的WindowManager.LayoutParams的width和height值,代表该界面的大小由布局文件大小指定。  
    11.     // 因为默认的WindowManager.LayoutParams的width和height是MATCH_PARENT,即与屏幕大小一致.  
    12.     if (mIsFloating) {   
    13.         setLayout(WRAP_CONTENT, WRAP_CONTENT);   
    14.         setFlags(0, flagsToUpdate); //取消FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR 位标记  
    15.     } else {  
    16.         setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);  
    17.     }  
    18.     //是否是没有标题栏 , android:windowNoTitle属性  
    19.     if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {  
    20.         requestFeature(FEATURE_NO_TITLE); //添加FEATURE_NO_TITLE  
    21.     }  
    22.     //是否是全屏, android:windowFullscreen属性  
    23.     if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {  
    24.         setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));  
    25.     }  
    26.     //是否是显示墙纸, android:windowShowWallpaper属性  
    27.     if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {  
    28.         setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));  
    29.     }  
    30.     WindowManager.LayoutParams params = getAttributes(); //当前的WindowManager.LayoutParams对象  
    31.     if (!hasSoftInputMode()) {  //是否已经设置了softInputMode模式,可显示通过#setSoftInputMode()方法设定  
    32.         params.softInputMode = a.getInt(  
    33.                 com.android.internal.R.styleable.Window_windowSoftInputMode,//android:windowSoftInputMode  
    34.                 params.softInputMode);  //可以由 WindowManager.LayoutParams指定  
    35.     }  
    36.     //是否是某个Activity的子Activity,一般不是,getContainer()返回  null.  
    37.     if (getContainer() == null) {    
    38.         if (mBackgroundDrawable == null) {   //获得了指定的背景图片.  
    39.             if (mBackgroundResource == 0) {  //获得了指定的背景图片资源  
    40.                 mBackgroundResource = a.getResourceId(  //背景图片id ,  android:windowBackground  
    41.                         com.android.internal.R.styleable.Window_windowBackground, 0);  
    42.             }  
    43.         }  
    44.         ...  
    45.     }  
    46.     // Inflate the window decor.  
    47.     int layoutResource;  
    48.     int features = getLocalFeatures(); // 等同于mFeatures,由requestFeature()设定.  
    49.     if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {  
    50.         //1、判断是否为对话框样式  
    51.         if (mIsFloating) {  
    52.             layoutResource = com.android.internal.R.layout.dialog_title_icons;  
    53.         } else {  
    54.             layoutResource = com.android.internal.R.layout.screen_title_icons;  
    55.         }  
    56.     }    
    57.     else if { //2、进度条样式  ;  //3、自定义Title}  
    58.     else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {  
    59.         //4、没有标题栏  
    60.         // If no other features and not embedded, only need a title.  
    61.         // If the window is floating, we need a dialog layout  
    62.         if (mIsFloating) {  
    63.             layoutResource = com.android.internal.R.layout.dialog_title;  
    64.         } else {  
    65.             layoutResource = com.android.internal.R.layout.screen_title;  
    66.         }  
    67.         // System.out.println("Title!");  
    68.     } else {  
    69.         layoutResource = com.android.internal.R.layout.screen_simple;  
    70.     }  
    71.     View in = mLayoutInflater.inflate(layoutResource, null);  
    72.     decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));  
    73.     ...  
    74.     if (getContainer() == null) {  
    75.         Drawable drawable = mBackgroundDrawable;     
    76.         if (mBackgroundResource != 0) {        //获取背景图片资源  
    77.             drawable = getContext().getResources().getDrawable(mBackgroundResource);  
    78.         }  
    79.         mDecor.setWindowBackground(drawable); //为DecorView设置背景图片  
    80.         drawable = null;  
    81.         //判断是否需要设置WindowFrame图片,该资源代表一个前景foreground图片,相对于背景background图片,  
    82.         if (mFrameResource != 0) {        //默认为null ,<item name="windowFrame">@null</item>  
    83.             drawable = getContext().getResources().getDrawable(mFrameResource);  
    84.         }  
    85.         mDecor.setWindowFrame(drawable);  
    86.     }  
    87.     return contentParent;               
    88. }  

           依次取出对应的属性值,然后根据这些值调用不同的函数,例如:requestFeature(),以及为

      WindowMamager.LayoutParams设置Flag标记(这个掩码实现按位操作倒挺麻烦的,部分理解,有知道的朋友

      可以给我指点下。)例如:如果是对话框窗口,则不设置FLAG_LAYOUT_IN_SCREEN |   FLAG_LAYOUT_INSET_DECOR

      位标记,因为该标记代表对应的是Activity窗口。

             1、  FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR   代表的是典型的Activity窗口
             2、 FLAG_LAYOUT_IN_SCREEN                                                             代表的是典型的全屏窗口

             3、 其他则代表其他对话框窗口。

          最后,根据相应的Feature值,加载不同的布局文件。

        PS : 前些日子在论坛中看到有网友说取消/隐藏ActionBar,Android 4.0中对一个支持ActionBar的资源文件

      定义如下:    文件路径  frameworksasecore es eslayoutscreen_action_bar.xml

    1. <!--  
    2. This is an optimized layout for a screen with the Action Bar enabled.  
    3. -->  
    4.   
    5. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    6.     android:orientation="vertical"  
    7.     android:fitsSystemWindows="true">  
    8.     <!-- Action Bar 对应的 View文件 -->  
    9.     <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"  
    10.         android:layout_width="match_parent"  
    11.         android:layout_height="wrap_content"  
    12.         style="?android:attr/actionBarStyle">  
    13.         <com.android.internal.widget.ActionBarView  
    14.             android:id="@+id/action_bar"  
    15.             android:layout_width="match_parent"  
    16.             android:layout_height="wrap_content"  
    17.             style="?android:attr/actionBarStyle" />  
    18.         <com.android.internal.widget.ActionBarContextView  
    19.             android:id="@+id/action_context_bar"  
    20.             android:layout_width="match_parent"  
    21.             android:layout_height="wrap_content"  
    22.             android:visibility="gone"  
    23.             style="?android:attr/actionModeStyle" />  
    24.     </com.android.internal.widget.ActionBarContainer>  
    25.     <FrameLayout android:id="@android:id/content"  
    26.         android:layout_width="match_parent"   
    27.         android:layout_height="0dip"  
    28.         android:layout_weight="1"  
    29.         android:foregroundGravity="fill_horizontal|top"  
    30.         android:foreground="?android:attr/windowContentOverlay" />  
    31.     <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"  
    32.                   android:layout_width="match_parent"  
    33.                   android:layout_height="wrap_content"  
    34.                   style="?android:attr/actionBarSplitStyle"  
    35.                   android:visibility="gone"  
    36.                   android:gravity="center"/>  
    37. </LinearLayout>  

        具体分析依旧见于generateLayout @ PhoneWindow.java ,  4.0 的源码咯。直接设置为gone状态不知可行否?

     转载请注明出处:http://blog.csdn.net/qinjuning

  • 相关阅读:
    ORACLE创建、修改、删除序列
    mysql添加索引
    Mysql事物与Metadata lock 问题
    oracle 查询最近执行过的 SQL语句
    ORACLE 常用SQL查询
    ssh-keygen的用法
    sql之left join、right join、inner join的区别
    Linux下使用 ipset 封大量IP及ipset参数说明
    今天学习的小命令
    Linux下查看分区内目录及文件占用空间容量
  • 原文地址:https://www.cnblogs.com/116913829/p/4270028.html
Copyright © 2011-2022 走看看