Reference:
http://blog.csdn.net/yanbober/article/details/45970721
http://blog.csdn.net/yanbober/article/details/46361191
主要是阅读了上述两篇文章,想整理下关于Activity如何创建Window,View和Window又有什么关系,是如何增加Layout的。
一,Activity与Window,View分析图如下:
上述的图,清晰地表达了Activity和Window,View之间的关系:
1,Window是一个抽象类,提供了绘制窗口的一组通用API。
2,PhoneWindow是Window的具体继承实现类。而且该类内部包含了一个DecorView对象,该DecorView对象是所有应用窗口(Activity界面)的根View。
3,DecorView是PhoneWindow的内部类,是FrameLayout的子类,是对FrameLayout进行功能的修饰(所以叫DecorXXX),是所有应用窗口的根View。
二,从Activity中设置theme和feature(设置全屏,NoTitle等),可以通过代码requestFeature() 或者XML的Android:theme属性
通过java文件设置:
requestWindowFeature(Window.FEATURE_NO_TITLE);
通过xml文件设置:
android:theme="@android:style/Theme.NoTitleBar"
这个theme设置的属性,设置的就是phoneWindow的表现形态。
而且从这个结构图看到,这也是为什么在Java文件设置Activity属性时必须在SetContentView方法之前调用requestFeature。
二,setContentView
1,在Activity的onCreate()中,通过调用setContentView()加载layout布局。
2,可以看到PhoneWindow类的setContentView方法最后通过调用
mLayoutInflater.inflate(layoutResID, mContentParent);
或者
mContentParent.addView(view, params);
将我们的xml或者Java View插入到mContentParant() ViewGroup中。 最后setContentView还会调用一个Callback接口的成员函数onContentChanged来通知对应的Activity组件视图内容发生了变化。
3,因此在调用setConentView() 之后,Activity的各种View的findViewById()方法等都可以放到该方法中,然后系统会帮忙调用onContentChanged()通知UI界面有改变。
三,具体的LayoutInflater机制原理:
四,Window 和 WindowManager
1,Window和WindowManager的基本关系分析:
从 ViewManager接口可以看到,该接口主要是实现View的插入,更新和删除:
public interface ViewManager{
public void addView(View view,ViewGroup.LayoutParams params);
public void updateViewLayout(View view,ViewGroup.LayoutParams params);
public void removeView(View view);
}
public interface WindowManager extends ViewManager {
......
public Display getDefaultDisplay();
public void removeViewImmediate(View view);
......
public static class LayoutParams extends ViewGroup.LayoutParams
implements Parcelable {
......
}
}
同时:WindowManager内部有一个静态内部类:LayoutParams,用于控制Window窗口的显示控制。
从上面可以看到,WindowManager用来管理应用与Window之间的接口.窗口顺序,消息等的管理。
2.ViewGroup:
同时插入ViewGroup的定义如下:
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
public void addView(View child, LayoutParams params) {
addView(child, -1, params);
}
......
public void addView(View child, int index, LayoutParams params) {
......
// addViewInner() will call child.requestLayout() when setting the new LayoutParams
// therefore, we call requestLayout() on ourselves before, so that the child's request
// will be blocked at our level
requestLayout();
invalidate(true);
addViewInner(child, index, params, false);
}
......
}
可以看到:ViewGroup也是通过AddView添加View的,ViewGroup类型是整个布局的父节点,即DecorView;而该DecorView又依附于一个Window。
总结:对于一个Activity只有一个DecorView(ViewRoot),也只有一个Window。
3,Window布局属性:WindowManager.LayoutParams类
WindowManager.LayoutParams 是Window的一个静态内部类,继承于ViewGroup.Params;用于向WindowManager描述Window的管理策略。
public static class LayoutParams extends ViewGroup.LayoutParams
implements Parcelable {
//窗口的绝对XY位置,需要考虑gravity属性
public int x;
public int y;
//在横纵方向上为相关的View预留多少扩展像素,如果是0则此view不能被拉伸,其他情况下扩展像素被widget均分
public float horizontalWeight;
public float verticalWeight;
//窗口类型
//有3种主要类型如下:
//ApplicationWindows取值在FIRST_APPLICATION_WINDOW与LAST_APPLICATION_WINDOW之间,是常用的顶层应用程序窗口,须将token设置成Activity的token;
//SubWindows取值在FIRST_SUB_WINDOW和LAST_SUB_WINDOW之间,与顶层窗口相关联,需将token设置成它所附着宿主窗口的token;
//SystemWindows取值在FIRST_SYSTEM_WINDOW和LAST_SYSTEM_WINDOW之间,不能用于应用程序,使用时需要有特殊权限,它是特定的系统功能才能使用;
public int type;
//WindowType:开始应用程序窗口
public static final int FIRST_APPLICATION_WINDOW = 1;
//WindowType:所有程序窗口的base窗口,其他应用程序窗口都显示在它上面
public static final int TYPE_BASE_APPLICATION = 1;
//WindowType:普通应用程序窗口,token必须设置为Activity的token来指定窗口属于谁
public static final int TYPE_APPLICATION = 2;
//WindowType:应用程序启动时所显示的窗口,应用自己不要使用这种类型,它被系统用来显示一些信息,直到应用程序可以开启自己的窗口为止
public static final int TYPE_APPLICATION_STARTING = 3;
//WindowType:结束应用程序窗口
public static final int LAST_APPLICATION_WINDOW = 99;
//WindowType:SubWindows子窗口,子窗口的Z序和坐标空间都依赖于他们的宿主窗口
public static final int FIRST_SUB_WINDOW = 1000;
//WindowType: 面板窗口,显示于宿主窗口的上层
public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
//WindowType:媒体窗口(例如视频),显示于宿主窗口下层
public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1;
//WindowType:应用程序窗口的子面板,显示于所有面板窗口的上层
public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2;
//WindowType:对话框,类似于面板窗口,绘制类似于顶层窗口,而不是宿主的子窗口
public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3;
//WindowType:媒体信息,显示在媒体层和程序窗口之间,需要实现半透明效果
public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4;
//WindowType:子窗口结束
public static final int LAST_SUB_WINDOW = 1999;
//WindowType:系统窗口,非应用程序创建
public static final int FIRST_SYSTEM_WINDOW = 2000;
//WindowType:状态栏,只能有一个状态栏,位于屏幕顶端,其他窗口都位于它下方
public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;
//WindowType:搜索栏,只能有一个搜索栏,位于屏幕上方
public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;
//WindowType:电话窗口,它用于电话交互(特别是呼入),置于所有应用程序之上,状态栏之下
public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;
//WindowType:系统提示,出现在应用程序窗口之上
public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;
//WindowType:锁屏窗口
public static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4;
//WindowType:信息窗口,用于显示Toast
public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5;
//WindowType:系统顶层窗口,显示在其他一切内容之上,此窗口不能获得输入焦点,否则影响锁屏
public static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6;
//WindowType:电话优先,当锁屏时显示,此窗口不能获得输入焦点,否则影响锁屏
public static final int TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7;
//WindowType:系统对话框
public static final int TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8;
//WindowType:锁屏时显示的对话框
public static final int TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9;
//WindowType:系统内部错误提示,显示于所有内容之上
public static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10;
//WindowType:内部输入法窗口,显示于普通UI之上,应用程序可重新布局以免被此窗口覆盖
public static final int TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11;
//WindowType:内部输入法对话框,显示于当前输入法窗口之上
public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
//WindowType:墙纸窗口
public static final int TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13;
//WindowType:状态栏的滑动面板
public static final int TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14;
//WindowType:安全系统覆盖窗口,这些窗户必须不带输入焦点,否则会干扰键盘
public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;
//WindowType:拖放伪窗口,只有一个阻力层(最多),它被放置在所有其他窗口上面
public static final int TYPE_DRAG = FIRST_SYSTEM_WINDOW+16;
//WindowType:状态栏下拉面板
public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;
//WindowType:鼠标指针
public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;
//WindowType:导航栏(有别于状态栏时)
public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;
//WindowType:音量级别的覆盖对话框,显示当用户更改系统音量大小
public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;
//WindowType:起机进度框,在一切之上
public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;
//WindowType:假窗,消费导航栏隐藏时触摸事件
public static final int TYPE_HIDDEN_NAV_CONSUMER = FIRST_SYSTEM_WINDOW+22;
//WindowType:梦想(屏保)窗口,略高于键盘
public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;
//WindowType:导航栏面板(不同于状态栏的导航栏)
public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;
//WindowType:universe背后真正的窗户
public static final int TYPE_UNIVERSE_BACKGROUND = FIRST_SYSTEM_WINDOW+25;
//WindowType:显示窗口覆盖,用于模拟辅助显示设备
public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;
//WindowType:放大窗口覆盖,用于突出显示的放大部分可访问性放大时启用
public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;
//WindowType:......
public static final int TYPE_KEYGUARD_SCRIM = FIRST_SYSTEM_WINDOW+29;
public static final int TYPE_PRIVATE_PRESENTATION = FIRST_SYSTEM_WINDOW+30;
public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;
public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;
//WindowType:系统窗口结束
public static final int LAST_SYSTEM_WINDOW = 2999;
//MemoryType:窗口缓冲位于主内存
public static final int MEMORY_TYPE_NORMAL = 0;
//MemoryType:窗口缓冲位于可以被DMA访问,或者硬件加速的内存区域
public static final int MEMORY_TYPE_HARDWARE = 1;
//MemoryType:窗口缓冲位于可被图形加速器访问的区域
public static final int MEMORY_TYPE_GPU = 2;
//MemoryType:窗口缓冲不拥有自己的缓冲区,不能被锁定,缓冲区由本地方法提供
public static final int MEMORY_TYPE_PUSH_BUFFERS = 3;
//指出窗口所使用的内存缓冲类型,默认为NORMAL
public int memoryType;
//Flag:当该window对用户可见的时候,允许锁屏
public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001;
//Flag:让该window后所有的东西都成暗淡
public static final int FLAG_DIM_BEHIND = 0x00000002;
//Flag:让该window后所有东西都模糊(4.0以上已经放弃这种毛玻璃效果)
public static final int FLAG_BLUR_BEHIND = 0x00000004;
//Flag:让window不能获得焦点,这样用户快就不能向该window发送按键事
public static final int FLAG_NOT_FOCUSABLE = 0x00000008;
//Flag:让该window不接受触摸屏事件
public static final int FLAG_NOT_TOUCHABLE = 0x00000010;
//Flag:即使在该window在可获得焦点情况下,依旧把该window之外的任何event发送到该window之后的其他window
public static final int FLAG_NOT_TOUCH_MODAL = 0x00000020;
//Flag:当手机处于睡眠状态时,如果屏幕被按下,那么该window将第一个收到
public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;
//Flag:当该window对用户可见时,让设备屏幕处于高亮(bright)状态
public static final int FLAG_KEEP_SCREEN_ON = 0x00000080;
//Flag:让window占满整个手机屏幕,不留任何边界
public static final int FLAG_LAYOUT_IN_SCREEN = 0x00000100;
//Flag:window大小不再不受手机屏幕大小限制,即window可能超出屏幕之外
public static final int FLAG_LAYOUT_NO_LIMITS = 0x00000200;
//Flag:window全屏显示
public static final int FLAG_FULLSCREEN = 0x00000400;
//Flag:恢复window非全屏显示
public static final int FLAG_FORCE_NOT_FULLSCREEN = 0x00000800;
//Flag:开启抖动(dithering)
public static final int FLAG_DITHER = 0x00001000;
//Flag:当该window在进行显示的时候,不允许截屏
public static final int FLAG_SECURE = 0x00002000;
//Flag:一个特殊模式的布局参数用于执行扩展表面合成时到屏幕上
public static final int FLAG_SCALED = 0x00004000;
//Flag:用于windows时,经常会使用屏幕用户持有反对他们的脸,它将积极过滤事件流,以防止意外按在这种情况下,可能不需要为特定的窗口,在检测到这样一个事件流时,应用程序将接收取消运动事件表明,这样应用程序可以处理这相应地采取任何行动的事件,直到手指释放
public static final int FLAG_IGNORE_CHEEK_PRESSES = 0x00008000;
//Flag:一个特殊的选项只用于结合FLAG_LAYOUT_IN_SC
public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000;
//Flag:转化的状态FLAG_NOT_FOCUSABLE对这个窗口当前如何进行交互的方法
public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000;
//Flag:如果你设置了该flag,那么在你FLAG_NOT_TOUNCH_MODAL的情况下,即使触摸屏事件发送在该window之外,其事件被发送到了后面的window,那么该window仍然将以MotionEvent.ACTION_OUTSIDE形式收到该触摸屏事件
public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000;
//Flag:当锁屏的时候,显示该window
public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
//Flag:在该window后显示系统的墙纸
public static final int FLAG_SHOW_WALLPAPER = 0x00100000;
//Flag:当window被显示的时候,系统将把它当做一个用户活动事件,以点亮手机屏幕
public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
//Flag:消失键盘
public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
//Flag:当该window在可以接受触摸屏情况下,让因在该window之外,而发送到后面的window的触摸屏可以支持split touch
public static final int FLAG_SPLIT_TOUCH = 0x00800000;
//Flag:对该window进行硬件加速,该flag必须在Activity或Dialog的Content View之前进行设置
public static final int FLAG_HARDWARE_ACCELERATED = 0x01000000;
//Flag:让window占满整个手机屏幕,不留任何边界
public static final int FLAG_LAYOUT_IN_OVERSCAN = 0x02000000;
//Flag:请求一个半透明的状态栏背景以最小的系统提供保护
public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;
//Flag:请求一个半透明的导航栏背景以最小的系统提供保护
public static final int FLAG_TRANSLUCENT_NAVIGATION = 0x08000000;
//Flag:......
public static final int FLAG_LOCAL_FOCUS_MODE = 0x10000000;
public static final int FLAG_SLIPPERY = 0x20000000;
public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 0x40000000;
public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000;
//行为选项标记
public int flags;
//PrivateFlags:......
public static final int PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED = 0x00000001;
public static final int PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED = 0x00000002;
public static final int PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS = 0x00000004;
public static final int PRIVATE_FLAG_SHOW_FOR_ALL_USERS = 0x00000010;
public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 0x00000040;
public static final int PRIVATE_FLAG_COMPATIBLE_WINDOW = 0x00000080;
public static final int PRIVATE_FLAG_SYSTEM_ERROR = 0x00000100;
public static final int PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR = 0x00000200;
public static final int PRIVATE_FLAG_KEYGUARD = 0x00000400;
public static final int PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS = 0x00000800;
//私有的行为选项标记
public int privateFlags;
public static final int NEEDS_MENU_UNSET = 0;
public static final int NEEDS_MENU_SET_TRUE = 1;
public static final int NEEDS_MENU_SET_FALSE = 2;
public int needsMenuKey = NEEDS_MENU_UNSET;
public static boolean mayUseInputMethod(int flags) {
......
}
//SOFT_INPUT:用于描述软键盘显示规则的bite的mask
public static final int SOFT_INPUT_MASK_STATE = 0x0f;
//SOFT_INPUT:没有软键盘显示的约定规则
public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0;
//SOFT_INPUT:可见性状态softInputMode,请不要改变软输入区域的状态
public static final int SOFT_INPUT_STATE_UNCHANGED = 1;
//SOFT_INPUT:用户导航(navigate)到你的窗口时隐藏软键盘
public static final int SOFT_INPUT_STATE_HIDDEN = 2;
//SOFT_INPUT:总是隐藏软键盘
public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;
//SOFT_INPUT:用户导航(navigate)到你的窗口时显示软键盘
public static final int SOFT_INPUT_STATE_VISIBLE = 4;
//SOFT_INPUT:总是显示软键盘
public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
//SOFT_INPUT:显示软键盘时用于表示window调整方式的bite的mask
public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;
//SOFT_INPUT:不指定显示软件盘时,window的调整方式
public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;
//SOFT_INPUT:当显示软键盘时,调整window内的控件大小以便显示软键盘
public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
//SOFT_INPUT:当显示软键盘时,调整window的空白区域来显示软键盘,即使调整空白区域,软键盘还是有可能遮挡一些有内容区域,这时用户就只有退出软键盘才能看到这些被遮挡区域并进行
public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
//SOFT_INPUT:当显示软键盘时,不调整window的布局
public static final int SOFT_INPUT_ADJUST_NOTHING = 0x30;
//SOFT_INPUT:用户导航(navigate)到了你的window
public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;
//软输入法模式选项
public int softInputMode;
//窗口如何停靠
public int gravity;
//水平边距,容器与widget之间的距离,占容器宽度的百分率
public float horizontalMargin;
//纵向边距
public float verticalMargin;
//积极的insets绘图表面和窗口之间的内容
public final Rect surfaceInsets = new Rect();
//期望的位图格式,默认为不透明,参考android.graphics.PixelFormat
public int format;
//窗口所使用的动画设置,它必须是一个系统资源而不是应用程序资源,因为窗口管理器不能访问应用程序
public int windowAnimations;
//整个窗口的半透明值,1.0表示不透明,0.0表示全透明
public float alpha = 1.0f;
//当FLAG_DIM_BEHIND设置后生效,该变量指示后面的窗口变暗的程度,1.0表示完全不透明,0.0表示没有变暗
public float dimAmount = 1.0f;
public static final float BRIGHTNESS_OVERRIDE_NONE = -1.0f;
public static final float BRIGHTNESS_OVERRIDE_OFF = 0.0f;
public static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f;
public float screenBrightness = BRIGHTNESS_OVERRIDE_NONE;
//用来覆盖用户设置的屏幕亮度,表示应用用户设置的屏幕亮度,从0到1调整亮度从暗到最亮发生变化
public float buttonBrightness = BRIGHTNESS_OVERRIDE_NONE;
public static final int ROTATION_ANIMATION_ROTATE = 0;
public static final int ROTATION_ANIMATION_CROSSFADE = 1;
public static final int ROTATION_ANIMATION_JUMPCUT = 2;
//定义出入境动画在这个窗口旋转设备时使用
public int rotationAnimation = ROTATION_ANIMATION_ROTATE;
//窗口的标示符
public IBinder token = null;
//此窗口所在的包名
public String packageName = null;
//屏幕方向
public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
//首选的刷新率的窗口
public float preferredRefreshRate;
//控制status bar是否显示
public int systemUiVisibility;
//ui能见度所请求的视图层次结构
public int subtreeSystemUiVisibility;
//得到关于系统ui能见度变化的回调
public boolean hasSystemUiListeners;
public static final int INPUT_FEATURE_DISABLE_POINTER_GESTURES = 0x00000001;
public static final int INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002;
public static final int INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004;
public int inputFeatures;
public long userActivityTimeout = -1;
......
public final int copyFrom(LayoutParams o) {
......
}
......
public void scale(float scale) {
......
}
......
}
从WindowManager.LayoutParams的定义看到:
Android窗口类型可以分成三大类:
1,应用程序窗口。一般应用程序的窗口,如程序的Activity的窗口;
2,子窗口。一般在Activity里面的窗口,有些还需依附于Activity。如对话框等。
3,系统窗口。系统的窗口,如输入法,Toast,墙纸等。
而且看到,这个三个窗口定义的type值是一个递增的数值。可以看做是窗口的Z-ORDER序列(值越大显示的位置就越靠近用户,值大的覆盖着值小的)。可以通过设置type=TYPE_APPLICATION来设置窗口的类型。
实例:可以通过实现一个模仿悬浮的小圆点实例加深理解Window。