Andriod中Style/Theme原理以及Activity界面文件选取过程浅析

AD620仪表放大器模组实战:从调零到信号放大的完整指南 本文详细介绍了AD620仪表放大器模组的实战应用,从调零到信号放大的完整指南。AD620模组以其专业级性能和易用性成为微弱信号放大的首选,集成了AD620芯片、LM358运放和7660电源转换芯片。文章提供了调零技巧、增益设置方法以及单端与差分输入的正确连接方案,并通过心电信号采集和称重传感器等实际案例展示了其广泛应用。 阅读详情

                                                                

       

                                                                                          转载请注明出处:http://blog.youkuaiyun.com/qinjuning     



      通过对前面的一篇博文<从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的所有系统资源定义位置存放在 frameworks\base\core\res\ 路径下,编译时会形成apk文件,即

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

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

            文件路径:frameworks\base\core\res\res\values\attrs.xml

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

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

  别名。

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

          文件路径:frameworks\base\core\res\res\values\attrs.xml

    <!-- These are the standard attributes that make up a complete theme. -->
    <declare-styleable name="Theme">
        <!-- Drawable to use as the overall window background.  There are a
             few special considerations you should use when settings this
             drawable:
        -->
        <attr name="windowBackground" format="reference" />
        <!-- Drawable to use as a frame around the window. -->
        <attr name="windowFrame" format="reference" />
        <!-- Flag indicating whether there should be no title on this window. -->
        <attr name="windowNoTitle" format="boolean" />
        <!-- Flag indicating whether this window should fill the entire screen. -->
        <attr name="windowFullscreen" format="boolean" />
        <!-- Flag indicating whether this is a floating window. -->
        <attr name="windowIsFloating" format="boolean" />
        <!-- Flag indicating whether this is a translucent window. -->
        <attr name="windowIsTranslucent" format="boolean" />
        <!-- Flag indicating that this window's background should be the
        	 user's current wallpaper. -->
        <attr name="windowShowWallpaper" format="boolean" />
        <!-- This Drawable is overlaid over the foreground of the Window's content area, usually
             to place a shadow below the title.  -->
        <!-- This Drawable is overlaid over the foreground of the Window's content area, usually
             to place a shadow below the title.  -->
        <attr name="windowContentOverlay" format="reference" />    
        <!--more -->     
     </declare-styleable>
   

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

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

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

                  文件位于:frameworks\base\core\res\res\values\themes.xml

      <style name="Theme">
        <!-- Window attributes -->
        <item name="windowBackground">@android:drawable/screen_background_dark</item>
        <item name="windowFrame">@null</item>
        <item name="windowNoTitle">false</item>
        <item name="windowFullscreen">false</item>
        <item name="windowIsFloating">false</item>
        <item name="windowTitleSize">25dip</item>
        <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground</item>
        <item name="android:windowAnimationStyle">@android:style/Animation.Activity</item>
        <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>    
     </style>

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

  一个父Theme继承,如下:

   <!--自定义Theme 必须制定parent属性-->
   <style name="CustomTheme" parent="@android:style/Theme" >
      <item name="android:windowNoTitle">true</item>
      <item name="android:windowFrame">@drawable/icon</item>
      <item name="android:windowBackground">?android:windowFrame</item>
   </style>
         我们看看Android另外一个Theme.NoTitleBar属性定义,默认继承了 "Theme"集合。

 <!-- Variant of the default (dark) theme with no title bar -->
    <style name="Theme.NoTitleBar">
        <item name="android:windowNoTitle">true</item>
    </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类。

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

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

      源码分析:

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

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

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

 

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

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

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

 

    Step 1、创建DecorView对象

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

       Step 2 、创建 mContentParent 对象

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

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

 方法。

      2.1、

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

   2.2、

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

     2.3

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

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

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

      最后,初始化对应资源。

    /**
     * Called by {@link #setTheme} and {@link #getTheme} to apply a theme
     * resource to the current Theme object.  Can override to change the
     * default (simple) behavior.  This method will not be called in multiple
     * threads simultaneously.
     *
     * @param theme The Theme object being modified.
     * @param resid The theme style resource being applied to <var>theme</var>.
     * @param first Set to true if this is the first time a style is being
     *              applied to <var>theme</var>.
     */
    protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {
        theme.applyStyle(resid, true);
    }

    private void initializeTheme() {
        final boolean first = mTheme == null;     //是否是第一次调用
        if (first) {
            mTheme = getResources().newTheme();   
            Resources.Theme theme = mBase.getTheme();  //调用ContextImpl类的getTheme(),获取默认的Theme
            if (theme != null) {
                mTheme.setTo(theme);   //将theme配置应用到mTheme属性中
            }
        }
        onApplyThemeResource(mTheme, mThemeResource, first);
    }

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

 Resource ,如开篇所述。

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

     @Override 
     public void setTheme(int resid) {
         mThemeResource = resid;    //设置mThemeResource
         initializeTheme();
     }

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

 Activity时,会调用setTheme()方法。文件路径:frameworks\base\core\java\android\app\ActivityThread.java

    private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        Activity activity = null;
        try {
        	//创建Activity实例
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
        } 
        ...
        try {
        	...
            if (activity != null) {
            	//创建相应的信息.
                ContextImpl appContext = new ContextImpl();
                appContext.init(r.packageInfo, r.token, this);
                appContext.setOuterContext(activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                ...   
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstance,
                        r.lastNonConfigurationChildInstances, config);
                ...
                //activityInfo相关信息是由ActivityManagerService通过IPC调用而来
                //可以参考Android SDK的ActivityInfo类 API。
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme); //调用setTheme()方法,参见方法1
                }
          ...
            }
        }
        ...  
        return activity;
    }

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

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

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

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

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

              具体可见 <

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

>

  

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

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

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

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

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

    /** @hide */
    public static int selectDefaultTheme(int curTheme, int targetSdkVersion) {
        return selectSystemTheme(curTheme, targetSdkVersion,
                com.android.internal.R.style.Theme,
                com.android.internal.R.style.Theme_Holo,
                com.android.internal.R.style.Theme_DeviceDefault);
    }
    /** @hide */
    public static int selectSystemTheme(int curTheme, int targetSdkVersion,
            int orig, int holo, int deviceDefault) {
    	//是否设置了Theme
        if (curTheme != 0) {
            return curTheme;
        }
        //判断版本号 , HONEYCOMB 代表 Android 3.0 , ICE_CREAM_SANDWICH 代表 Android 4.0 
        if (targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) {
            return orig;
        }
        if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            return holo;
        }
        return deviceDefault;
    }



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

 如下代码所示:

     
    protected ViewGroup generateLayout(DecorView decor) {
        // Apply data from current theme.
        TypedArray a = getWindowStyle();   //获得当前的Theme属性对应的TypedArray对象.
         
        //是否是Dialog样式的界面 , android:windowIsFloating属性
        mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);
        int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR) 
            & (~getForcedWindowFlags());
        //如果是Dialog样式,则设置当前的WindowManager.LayoutParams的width和height值,代表该界面的大小由布局文件大小指定。
        // 因为默认的WindowManager.LayoutParams的width和height是MATCH_PARENT,即与屏幕大小一致.
        if (mIsFloating) { 
            setLayout(WRAP_CONTENT, WRAP_CONTENT); 
            setFlags(0, flagsToUpdate); //取消FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR 位标记
        } else {
            setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
        }
        //是否是没有标题栏 , android:windowNoTitle属性
        if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {
            requestFeature(FEATURE_NO_TITLE); //添加FEATURE_NO_TITLE
        }
        //是否是全屏, android:windowFullscreen属性
        if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
            setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));
        }
        //是否是显示墙纸, android:windowShowWallpaper属性
        if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
            setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));
        }
        WindowManager.LayoutParams params = getAttributes(); //当前的WindowManager.LayoutParams对象
        if (!hasSoftInputMode()) {  //是否已经设置了softInputMode模式,可显示通过#setSoftInputMode()方法设定
            params.softInputMode = a.getInt(
                    com.android.internal.R.styleable.Window_windowSoftInputMode,//android:windowSoftInputMode
                    params.softInputMode);  //可以由 WindowManager.LayoutParams指定
        }
        //是否是某个Activity的子Activity,一般不是,getContainer()返回  null.
        if (getContainer() == null) {  
            if (mBackgroundDrawable == null) {   //获得了指定的背景图片.
                if (mBackgroundResource == 0) {  //获得了指定的背景图片资源
                    mBackgroundResource = a.getResourceId(  //背景图片id ,  android:windowBackground
                            com.android.internal.R.styleable.Window_windowBackground, 0);
                }
            }
            ...
        }
        // Inflate the window decor.
        int layoutResource;
        int features = getLocalFeatures(); // 等同于mFeatures,由requestFeature()设定.
        if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
        	//1、判断是否为对话框样式
            if (mIsFloating) {
                layoutResource = com.android.internal.R.layout.dialog_title_icons;
            } else {
                layoutResource = com.android.internal.R.layout.screen_title_icons;
            }
        }  
        else if { //2、进度条样式  ;  //3、自定义Title}
        else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
        	//4、没有标题栏
            // If no other features and not embedded, only need a title.
            // If the window is floating, we need a dialog layout
            if (mIsFloating) {
                layoutResource = com.android.internal.R.layout.dialog_title;
            } else {
                layoutResource = com.android.internal.R.layout.screen_title;
            }
            // System.out.println("Title!");
        } else {
            layoutResource = com.android.internal.R.layout.screen_simple;
        }
        View in = mLayoutInflater.inflate(layoutResource, null);
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        ...
        if (getContainer() == null) {
            Drawable drawable = mBackgroundDrawable;   
            if (mBackgroundResource != 0) {        //获取背景图片资源
                drawable = getContext().getResources().getDrawable(mBackgroundResource);
            }
            mDecor.setWindowBackground(drawable); //为DecorView设置背景图片
            drawable = null;
            //判断是否需要设置WindowFrame图片,该资源代表一个前景foreground图片,相对于背景background图片,
            if (mFrameResource != 0) {        //默认为null ,<item name="windowFrame">@null</item>
                drawable = getContext().getResources().getDrawable(mFrameResource);
            }
            mDecor.setWindowFrame(drawable);
        }
        return contentParent;             
    }

       依次取出对应的属性值,然后根据这些值调用不同的函数,例如: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的资源文件

  定义如下:    文件路径  frameworks\base\core\res\res\layout\screen_action_bar.xml

<!--
This is an optimized layout for a screen with the Action Bar enabled.
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:fitsSystemWindows="true">
    <!-- Action Bar 对应的 View文件 -->
    <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="?android:attr/actionBarStyle">
        <com.android.internal.widget.ActionBarView
            android:id="@+id/action_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            style="?android:attr/actionBarStyle" />
        <com.android.internal.widget.ActionBarContextView
            android:id="@+id/action_context_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:visibility="gone"
            style="?android:attr/actionModeStyle" />
    </com.android.internal.widget.ActionBarContainer>
    <FrameLayout android:id="@android:id/content"
        android:layout_width="match_parent" 
        android:layout_height="0dip"
        android:layout_weight="1"
        android:foregroundGravity="fill_horizontal|top"
        android:foreground="?android:attr/windowContentOverlay" />
    <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  style="?android:attr/actionBarSplitStyle"
                  android:visibility="gone"
                  android:gravity="center"/>
</LinearLayout>

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



    At  Last ,下一步希望能整明白Android中对资源的获取过程,期望老罗同志给力咯。

 


      

     欢迎加入 Android联盟QQ群:55945620 ~~~~  Best Regards 


     








SAP-ABAP:SAP Open SQL 分页技术深度解析:语法、性能陷阱与最佳实践 SAP Open SQL 分页技术深度解析:语法、性能陷阱与最佳实践 阅读详情

相关推荐

手动以及使用torch.nn实现前馈神经网络实验

手动以及使用torch.nn实现前馈神经网络 手动实现前馈神经网络解决上述回归、二分类、多分类任务 利用torch.nn解决上述回归、二分类、多分类任务 在多分类任务中使用至少三种不同的激活函数 对多分类任务中的模型评估隐藏层层数和隐藏单元个数对实验结果的影响

m0_52910424的博客 9372

Android 隐式启动匹配原则

1、Intent中只能包含一个Action,可以包含多个Category; 2、清单文件中一个Activity可配置多个IntentFilter, 一个IntentFilter可包含多个Action,多个Category,但是只能包含一个data; 3、Intent若含有Action,IntentFilter中包含多个Action,只要Intent中的Action与IntentFilter中的

Henry_Alpha的博客 1756

大疆精灵3无人机2.4GHz通信系统实测:跳频扩频技术深度解析

跳频扩频(FHSS)是一种经典的扩频通信技术,其核心原理是通过让载波频率在一个宽频带上按伪随机序列快速跳变,将窄带信号的能量扩散开来。这种技术能有效对抗固定频率干扰,提升通信的可靠性和抗截获性,在无线遥控、军事通信等领域具有重要价值。在无人机、物联网等对实时性与可靠性要求高的应用场景中,FHSS技术能显著增强复杂电磁环境下的链路鲁棒性。本文以频谱分析仪实测大疆精灵3无人机为例,深入剖析其2.4GHz频段遥控与图传系统的工作特性,揭示了其采用的成熟FHSS方案,包括约76MHz的总跳频带宽、39个信道及约2M

weixin_33935636的博客 310

Android中Theme主题和Style样式使用介绍总结

一,Theme主题 1.1,Theme主题作用范围 Theme主要是针对应用级别的或者说窗体级别,可以设置应用主题(应用换肤效果)或者Activity的主题;主题是不能应用在某一个单独的View中; 1.2,Theme主题的定义 在AS中res/values/style.xml中定义,例如新建项目AS自动创建的Theme,是系统提供; <!-- Base application ...

ezconn的博客 2万+

2025年全国青少年信息素养大赛初赛真题(算法创意实践挑战赛C++初中组:文末附答案)

2025年全国青少年信息素养大赛初赛真题(算法创意实践挑战赛C++初中组:文末附答案)

王老师青少年编程 3396

PhotovoltaicPanelCleanlinessDetector:基于YOLOv8的光伏板清洁状态监测系统

data.yamlyaml复制编辑names:0: clean1: dust3: leaves4: shadow✅ 高精度污染识别✅ 具备实时检测与UI展示✅ 可本地化部署应用未来方向增加污染程度分级(轻度、中度、严重)加入时间序列分析(污染变化趋势预测)无人机集成巡检模块。

YOLO 276

android_基础_常见主题theme风格详解

本文出自门心叼龙的博客,转载请注明出处: https://blog.youkuaiyun.com/geduo_83/article/details/86560896 目录 1. 什么是Style,什么是Theme? 2. 在定义Theme的时候@符号和?符号有何区别? 3. 怎么通过代码给一个Activity设置主题? 4. AppTheme主题颜色colorPrimary,colorPrimaryDark,colorAccent都是什么的颜色? ​​5.常见的主题风格都有哪些? 6.ThemeOverlay使用特点

写bug的蚊子的博客 3516

手把手教你学simulink(83.2)--分布式能源场景实例:使用Simulink构建一个典型的光伏发电分布式能源系统模型

*分布式能源系统(Distributed Energy System, DES)**是指由多个小型发电单元、储能装置和负载组成的电力系统,这些组件通常分布在不同的地理位置。DES包括太阳能光伏(PV)、风力发电、微型燃气轮机、储能电池等。这种系统能够提高能源利用效率、减少传输损耗,并增强电网的稳定性和可靠性。在DES中,各组件之间的协调与控制至关重要。通过使用Simulink,我们可以模拟和优化这些系统的运行情况,研究其动态行为,并设计有效的控制策略。

MHD0815的博客 1104

android布局界面theme,Andriod中Style/Theme原理以及Activity界面文件选取过程浅析

通过对前面的一篇博文的学习,我们掌握了Activity组件布局文件地创建过程以及其顶层控件DecorView,今天我们继续庖丁解牛---深入到其中的generateLayout()方法,步步为营掌握一下内容:1、Activity中Theme(主题)的系统定义以及使用之处;2、如何根据设置的Feature(属性)选择合适的布局文件。另外,对于下文中Theme和Style的概念进行一个简要说明:都是由...

weixin_30991277的博客 591

stable-diffusion-webui的逐步部署教程

本文主要介绍了stable-diffusion-webui的逐步部署教程,希望能对使用Stable Diffusion的同学们有所帮助。 文章目录 1. 前言 2. 逐步部署教程 2.1 创建Python环境 2.2 安装依赖库 2.3 运行代码

weixin_43178406的博客 6万+

BevFusion (5):逐行代码详解

论文中给出了Bevfusion的架构图,它的输入是多视角的相机和点云图,经过两个特定的head,分别用于做检测任务和分割任务。图1 Bevfusion 结构图Bevfusion因为有两个模态的输入:多视角相机和点云,所以对应两个分支:相机分支和点云分支。相机分支:输入6个视角的图片后,提取特征,然后经VT(View Transformer)转换之后得到相机的Bev特征。激光雷达分支:输入点云数据,经过Encoder编码得到体素化Lidar特征,然后沿z方向展平,得到Lidar Bev特征。

@bangbang的博客 3714

Android——Theme和Style-由浅入深,全面讲解

Theme和Style-由浅入深,全面讲解

6897

微信小程序 - 解决报错 {“errcode“:41002,“errmsg“:“appid missing, rid: X“} 微信报错错误码errcode“:41002问题分析及解决教程(详细排查)

【微信小程序】报错{“errcode“:41002,“errmsg“:“appid missing, rid: 64e55770-67c1fb7e-027c5a70“}:【微信小程序】微信小程序登录请求出现appid missing提示,微信公众号{"errcode":41002,"errmsg":"appid missing"},微信 报错{“errcode“:41002,“errmsg“:“appid missing,微信小程序获取openid返回appid missing的问题,微信小程序提示Erro

🏆 前端领域优质创作者 5654

Android Theme和Style区别联系

sda

Caesardadi的专栏 4416

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

android 用自定义样式设计界面,Android Style开发之Theme

1概述Theme是针对窗体设计的,用以改变窗体样式;Style是针对窗体元素的,用以改变指定控件或layout的样式。Android系统的themes.xml和style.xml文件位于frameworks/base/core/res/res/values中。里面涉及到很多.9.png文件,路径位于frameworks/base/core/res/res/drawable-hdpi2 系统主题分类...

weixin_39875167的博客 555

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Android 风格与主题(style and theme)

1、什么是Style,什么是Theme?         Style 和 theme:是一个包含一种 或者 多种格式化 属性 的集合  ,并且 style和theme都是资源,存放在res/values 文件夹下 即可,android提供了很多这样的默认资源。你可以来使用它们。同时你也可以自己定义style和 theme,只需要在res/values/这个路径里面新建一个.xml文件,而且他的根

快乐&&平凡 1万+

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

android黑屏日志_Android Theme以及解决启动黑屏的方法详解

前言本文主要介绍了关于Android Theme及解决启动黑屏的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧1.修改AndroidManifest.xml 设置App的全局Theme或者Activity的界面Themeandroid:allowBackup="true"android:icon="@drawable/ipod_icon"android:label="@s...

weixin_39824033的博客 383

如何在android中利用Theme设置application 的所有listview的style?~

今天看VLC的源代码,发现一个很神奇的东西 所有listview的点击效果背景色都是橘黄色 花了点时间找了一下看看怎么实现的。 首先,定义一个<selector> like this: <selector>   <item android:state_pressed="true">           <shape android:...

aoshunjian2584的博客 283

Android中的style与theme

android UI进阶之style和theme的使用 今天来和大家分享一下android中UI设计里面常会用到的style和theme。 首先,style和theme都是资源,android提供了很多这样的默认资源。你可以来使用它们。同时你也可以自己定义style和theme。这非常的简单,只需要在res/values/这个路径里面新建一个.xml文件,而且他的根节点必须是<r...

weixin_30345577的博客 81
上一篇: 写给自己和程序员的一些话(12年末-13年初总结)
下一篇: 从源码角度简要分析ActionBar框架
qinjuning
博客等级 码龄18年 5288粉丝 43原创
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值