点击上方蓝色文字关注我哦

Window在Android是一个窗口的概念,日常开发中我们和它接触的不多,我们更多接触的是View,但是View都是通过Window来呈现的,Window是View的直接管理者。而WindowManager承担者管理Window的责任。

窗口类型

Window在Android中有三种类型:

  • 应用Window:z-index在1~99之间,它往往对应着一个Activity。

  • 子Window:z-index在1000~1999之间,它往往不能独立存在,需要依附在父Window上,例如Dialog等。

  • 系统Window:z-index在2000~2999之间,它往往需要声明权限才能创建,例如Toast、状态栏、系统音量条、错误提示框都是系统Window。

z-index是Android窗口的层级的概念,z-index越大的窗口越居于顶层,

z-index对应着WindowManager.LayoutParams里的type参数,具体说来。

应用Window

  • public static final int FIRST_APPLICATION_WINDOW = 1;//1

  • public static final int TYPE_BASE_APPLICATION = 1;//窗口的基础值,其他的窗口值要大于这个值

  • public static final int TYPE_APPLICATION = 2;//普通的应用程序窗口类型

  • public static final int TYPE_APPLICATION_STARTING = 3;//应用程序启动窗口类型,用于系统在应用程序窗口启动前显示的窗口。

  • public static final int TYPE_DRAWN_APPLICATION = 4;

  • public static final int LAST_APPLICATION_WINDOW = 99;//2

子Window

  • public static final int FIRST_SUB_WINDOW = 1000;//子窗口类型初始值

  • public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;

  • public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;

  • public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;

  • public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;

  • public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4;

  • public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;

  • public static final int LAST_SUB_WINDOW = 1999;//子窗口类型结束值

系统Window

  • public static final int FIRST_SYSTEM_WINDOW = 2000;//系统窗口类型初始值

  • public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;//系统状态栏窗口

  • public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;//搜索条窗口

  • public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;//通话窗口

  • public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;//系统ALERT窗口

  • public static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4;//锁屏窗口

  • public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5;//TOAST窗口

窗口参数

在WindowManager里定义了一个LayoutParams内部类,它描述了窗口的参数信息,主要包括:

  • public int x:窗口x轴坐标

  • public int y:窗口y轴坐标

  • public int type:窗口类型

  • public int flags:窗口属性

  • public int softInputMode:输入法键盘模式

关于窗口属性,它控制着窗口的行为,举几个常见的:

  • FLAG_ALLOW_LOCK_WHILE_SCREEN_ON 只要窗口可见,就允许在开启状态的屏幕上锁屏

  • FLAG_NOT_FOCUSABLE 窗口不能获得输入焦点,设置该标志的同时,FLAG_NOT_TOUCH_MODAL也会被设置

  • FLAG_NOT_TOUCHABLE 窗口不接收任何触摸事件

  • FLAG_NOT_TOUCH_MODAL 在该窗口区域外的触摸事件传递给其他的Window,而自己只会处理窗口区域内的触摸事件

  • FLAG_KEEP_SCREEN_ON 只要窗口可见,屏幕就会一直亮着

  • FLAG_LAYOUT_NO_LIMITS 允许窗口超过屏幕之外

  • FLAG_FULLSCREEN 隐藏所有的屏幕装饰窗口,比如在游戏、播放器中的全屏显示

  • FLAG_SHOW_WHEN_LOCKED 窗口可以在锁屏的窗口之上显示

  • FLAG_IGNORE_CHEEK_PRESSES 当用户的脸贴近屏幕时(比如打电话),不会去响应此事件

  • FLAG_TURN_SCREEN_ON 窗口显示时将屏幕点亮

关于窗口类型,它对应着窗口的层级,上面我们也提到过了。

它的构造函数也主要是针对这几个参数的。

public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {            public LayoutParams() {                super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);                type = TYPE_APPLICATION;                format = PixelFormat.OPAQUE;            }

            public LayoutParams(int _type) {                super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);                type = _type;                format = PixelFormat.OPAQUE;            }

            public LayoutParams(int _type, int _flags) {                super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);                type = _type;                flags = _flags;                format = PixelFormat.OPAQUE;            }

            public LayoutParams(int _type, int _flags, int _format) {                super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);                type = _type;                flags = _flags;                format = _format;            }

            public LayoutParams(int w, int h, int _type, int _flags, int _format) {                super(w, h);                type = _type;                flags = _flags;                format = _format;            }

            public LayoutParams(int w, int h, int xpos, int ypos, int _type,int _flags, int _format) {                super(w, h);                x = xpos;                y = ypos;                type = _type;                flags = _flags;                format = _format;            } }

窗口模式

关于窗口模式我们就比较熟悉了,我们会在AndroidManifest.xml里Activity的标签下设置android:windowSoftInputMode="adjustNothing",来控制输入键盘显示行为。

可选的有6个参数,源码里也有6个值与之对应:

  • SOFT_INPUT_STATE_UNSPECIFIED:没有指定软键盘输入区域的显示状态。

  • SOFT_INPUT_STATE_UNCHANGED:不要改变软键盘输入区域的显示状态。

  • SOFT_INPUT_STATE_HIDDEN:在合适的时候隐藏软键盘输入区域,例如,当用户导航到当前窗口时。

  • SOFT_INPUT_STATE_ALWAYS_HIDDEN:当窗口获得焦点时,总是隐藏软键盘输入区域。

  • SOFT_INPUT_STATE_VISIBLE:在合适的时候显示软键盘输入区域,例如,当用户导航到当前窗口时。

  • SOFT_INPUT_STATE_ALWAYS_VISIBLE:当窗口获得焦点时,总是显示软键盘输入区域。

当然,我们也可以通过代码设置键盘模式。

getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);

窗口回调

Window里定义了一个Callback接口,Activity实现了Window.Callback接口,将Activity关联给Window,Window就可以将一些事件交由Activity处理。

public interface Callback {

        //键盘事件分发        public boolean dispatchKeyEvent(KeyEvent event);

        //触摸事件分发        public boolean dispatchTouchEvent(MotionEvent event);

        //轨迹球事件分发        public boolean dispatchTrackballEvent(MotionEvent event);

        //可见性事件分发        public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event);

        //创建Panel View        public View onCreatePanelView(int featureId);

        //创建menu        public boolean onCreatePanelMenu(int featureId, Menu menu);

        //画板准备好时回调        public boolean onPreparePanel(int featureId, View view, Menu menu);

        //menu打开时回调        public boolean onMenuOpened(int featureId, Menu menu);

        //menu item被选择时回调        public boolean onMenuItemSelected(int featureId, MenuItem item);

        //Window Attributes发生变化时回调        public void onWindowAttributesChanged(WindowManager.LayoutParams attrs);

        //Content View发生变化时回调        public void onContentChanged();

        //窗口焦点发生变化时回调        public void onWindowFocusChanged(boolean hasFocus);

        //Window被添加到WIndowManager时回调        public void onAttachedToWindow();

        //Window被从WIndowManager中移除时回调        public void onDetachedFromWindow();

         */        //画板关闭时回调        public void onPanelClosed(int featureId, Menu menu);

        //用户开始执行搜索操作时回调        public boolean onSearchRequested();    }

窗口实现

Window是一个抽象类,它的唯一实现类是PhoneWindow,PhoneWindow里包含了以下内容:

  • private DecorView mDecor:DecorView是Activity中的顶级View,它本质上是一个FrameLayout,一般说来它内部包含标题栏和内容栏(com.android.internal.R.id.content)。

  • ViewGroup mContentParent:窗口内容视图,它是mDecor本身或者是它的子View。

  • private ImageView mLeftIconView:左上角图标

  • private ImageView mRightIconView:右上角图标

  • private ProgressBar mCircularProgressBar:圆形loading条

  • private ProgressBar mHorizontalProgressBar:水平loading条

  • 其他的一些和转场动画相关的Transition与listener

看到这些,大家有没有觉得很熟悉,这就是我们日常开发中经常见到的东西,它在PhoneWindow里被创建。另外,我们在Activity里经常调用的方法,它的实际实现也是 在PhoneWindow里,我们分别来看一看。

setContentView()

这是一个我们非常熟悉的方法,只不过我们通常是在Activity里进行调用,但是它的实际实现是在PhoneWindow里。

public class PhoneWindow extends Window implements MenuBuilder.Callback {

    @Override    public void setContentView(int layoutResID) {        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window        // decor, when theme attributes and the like are crystalized. Do not check the feature        // before this happens.        if (mContentParent == null) {            //1. 如果没有DecorView则创建它,并将创建好的DecorView赋值给mContentParent            installDecor();        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {            mContentParent.removeAllViews();        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,                    getContext());            transitionTo(newScene);        } else {            //2. 将Activity传入的布局文件生成View并添加到mContentParent中            mLayoutInflater.inflate(layoutResID, mContentParent);        }        mContentParent.requestApplyInsets();        final Callback cb = getCallback();        if (cb != null && !isDestroyed()) {            //3. 回调Window.Callback里的onContentChanged()方法,这个Callback也被Activity            //所持有,因此它实际回调的是Activity里的onContentChanged()方法,通知Activity            //视图已经发生改变。            cb.onContentChanged();        }        mContentParentExplicitlySet = true;    }    }

这个方法主要做了两件事情:

  1. 如果没有DecorView则创建它,并将创建好的DecorView赋值给mContentParent

  2. 将Activity传入的布局文件生成View并添加到mContentParent中

  3. 回调Window.Callback里的onContentChanged()方法,这个Callback也被Activity所持有,因此它实际回调的是Activity里的onContentChanged()方法,通知Activity视图已经发生改变。

创建DecorView是通过installDecor()方法完成的,它的逻辑也非常简单,就是创建了一个ViewGroup然后返回给了mDecor和mContentParent。

public class PhoneWindow extends Window implements MenuBuilder.Callback {

 public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;

  private void installDecor() {         mForceDecorInstall = false;         if (mDecor == null) {             //生成DecorView             mDecor = generateDecor(-1);             mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);             mDecor.setIsRootNamespace(true);             if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {                 mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);             }         } else {             mDecor.setWindow(this);         }         if (mContentParent == null) {             mContentParent = generateLayout(mDecor);             ...             } else {                ...             }            ...         }     }

 protected ViewGroup generateLayout(DecorView decor) {        //读取并设置主题颜色、状态栏颜色等信息        ...        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);        //设置窗口参数等信息        ...        return contentParent;    }    }

通过以上这些流程,DecorView已经被创建并初始化完毕,Activity里的布局文件也被成功的添加到PhoneWindow的mContentParent(实际上就是DecorView,它是Activity的顶层View) 中,但是这个时候DecorView还没有真正的被WindowManager添加到Window中,它还无法接受用户的输入信息和焦点事件,这个时候就相当于走到了Activity的onCreate()流程,界面还 未展示给用户。

直到走到Activity的onResume()方法,它会调用Activity的makeVisiable()方法,DecorView才真正的被用户所看到。

public class Activity extends ContextThemeWrapperimplements LayoutInflater.Factory2,Window.Callback, KeyEvent.Callback,OnCreateContextMenuListener, ComponentCallbacks2,Window.OnWindowDismissedCallback, WindowControllerCallback {

    void makeVisible() {        if (!mWindowAdded) {            ViewManager wm = getWindowManager();            wm.addView(mDecor, getWindow().getAttributes());            mWindowAdded = true;        }        mDecor.setVisibility(View.VISIBLE);    }}

通常以上的分析,我们理解了setContentView的工作原理,另外还有addContentView、clearContentView,正如它们的名字那样,setContentView是替换View,addContentView是添加View。实现原理相同。

推荐阅读

Android窗口管理框架概述

Android应用视图的载体View

关注教程

您看此文用

 · 

秒,转发只需1秒呦~

android int 首位值_Android应用视图的管理者Window相关推荐

  1. android int 首位值_Android中数值的精确计算

    Android中数值计算的精度 在平常的开发中,会经常进行数值的计算,而如何才能更加准确的得到计算结果是最重要的,最近在做一个金融类的项目,其中涉及到黄金的计算,所以写这篇文章来总结一下,如何对数值的 ...

  2. android dialog 隐藏状态栏_Android应用视图的管理者Window

    点击上方蓝色文字关注我哦 Window在Android是一个窗口的概念,日常开发中我们和它接触的不多,我们更多接触的是View,但是View都是通过Window来呈现的,Window是View的直接管 ...

  3. 安卓视线可锁定首行和首列的表格视图

    如上图所示效果,整体视图构成已标记,联动效果通过两个CustomHorizontalScrollView的setOnScrollChangeListener方法绑定实现. 表格里面数据通过动态添加te ...

  4. android 调出键盘表情_android高仿微信表情输入与键盘输入代码(详细实现分析)

    表情与键盘的切换输入大部分IM都会需要到,之前自己实现了一个,还是存在些缺陷,比如说键盘与表情切换时出现跳闪问题,这个困扰了我些时间,不过所幸在Github(其代码整体结构很不错)并且在论坛上找些解决 ...

  5. Android实现首字母导航条(仿微信)

    本博客介绍Android实现首字母导航条,先看张效果图,具体怎么实现看代码吧 具体的步骤 1.整体布局的显示 2. 实现A-Z的分组 3. 自定义A-Z的导航条 4. 中间显示/隐藏触摸到导航条具体的 ...

  6. android设置滚动条样式,Android零基础入门|滚动视图ScrollView-设置滚动条样式

    前面几期学习了ProgressBar系列组件.ViewAnimator系列组件.Picker系列组件和时间日期系列组件,接下来几期继续来学习常见的其他组件. 一.ScrollView概述 从前面的学习 ...

  7. android edittext限制字节_android EditText输入限制

    zyz 发表于 2012-5-30 18:19:03 android EditText输入限制 android:digits="1234567890.+-*/%\n()" 限制输入 ...

  8. Android View体系(一)视图坐标系

    http://blog.csdn.net/itachi85/article/details/50708391 前言 Android View体系是界面编程的核心,他的重要性不亚于Android四大组件 ...

  9. android int与String的转换

     今天,简单讲讲  int与String的转换. 一.int -> String 第一种方法:String的valueOf方法, int i=5; String s=String.val ...

最新文章

  1. 在室内停车场使用道路标记语义进行厘米级建图和定位
  2. php 接口 2.0,YII 2.0 API接口开发
  3. Python之compiler:compiler库的简介、安装、使用方法之详细攻略
  4. MAT之SA:利用SA算法解决TSP(数据是14个虚拟城市的横纵坐标)问题
  5. ffmpeg 配置与编译
  6. mongodb如何根据字段(数组类型)的长度排序_大数据存储技术选型(七)——MongoDB设计模式及索引优化...
  7. 从Pycharm说起
  8. you just 飞鸽传书2007绿色版 ever day for two years
  9. phpcmsV9 如何开启wap手机站点
  10. linux sed写文件内容,Linux学习——文本处理:sed
  11. 写个买卖小游戏,第1天(昨天)
  12. PHP毕业设计源码带论文和答辩、大作业、实例程序源码下载合集【21套】
  13. window系统在cmd窗口中直接使用sqlmap命令进行sql注入测试
  14. uni-app自定义二维码扫描及本地图片扫描
  15. 蓝湖(切图工具)插件的安装和使用
  16. (原創) 如何設計除頻器? (SOC) (Verilog) (MegaCore)
  17. 华为云服务器更换操作系统,云服务器更换操作系统
  18. python刷视频挣钱_薅羊毛--使用python+adb实现自动刷视频点赞
  19. C语言教程(四):基础知识(最后一续)
  20. layui数据表格与后台交互进行渲染

热门文章

  1. LSTM(序列标注,自实现)
  2. 数字化转型知识方法系列之五:数字化转型战略
  3. [KMP]一本通(http://ybt.ssoier.cn:8088) 1698:字符串匹配
  4. [转载]用消息队列和消息应用状态表来消除分布式事务
  5. iOS开发-多层嵌套block中如何使用__weak和__strong
  6. path环境变量丢失恢复
  7. C#中break,continue,return,,goto,throw的区别(转)
  8. nginx的学习(配置文件,以及部署的疑惑)
  9. Facebook190亿美元收购WhatsApp
  10. php根据分类生成网址,PHP实现无限极分类生成分类树的方法