android int 首位值_Android应用视图的管理者Window

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

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

窗口类型

5423944203ab3bb23a65b3913afb9183.png

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

关注教程

47743786243978bd1c1c3ed25ac9a58d.gif

您看此文用

 e859fbf69f1ab5a0a3a07b3ba87593bd.gif 8a7a24272ae57fa1ab620c9f3dd7e04b.gif·fd1b55b2d296e165c7827bb8f777da43.gif 62cde647489c7e85aa8c1a22afa30699.gif

秒,转发只需1秒呦~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499030.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java正则匹配英文句号_Scala 正则表达式 0411

Scala 正则表达式Scala 通过 scala.util.matching 包中的 Regex 类来支持正则表达式。以下实例演示了使用正则表达式查找单词 Scala :import scala.util.matching.Regexobject Test {def main(args: Array[String]) {val pattern "Scala".rval str "Scala is …

撤销前进快捷键_电脑win7系统的快捷键大全

电脑在日常工作中经常需要使用到系统自带的快捷键,这样能够大大提高工作效率,比使用鼠标去点击查找方便省事多了,比如常用的复制(Ctrlc)粘贴(Ctrlv),今天就来给大家讲讲Windows系统的快捷键,可以说是快捷键大全啦。一、…

jedis依赖_SpringBoot整合Jedis实现redis缓存

我是一个java开发者,我的文章,没有华丽的言辞,没有666的版式,这些都是我自己工作中用到的解决方案,很多都是直接粘贴的源码,在这里与君分享。如果喜欢这里文章可以关注我,我回继续发的&#xff…

软件文档 服务器上,服务器上需要什么软件

服务器上需要什么软件 内容精选换一换华为云帮助中心,为用户提供产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题、视频帮助等技术文档,帮助您快速上手使用华为云服务。MindStudio所在的环境为开发环境,开发人员可以进…

服务器补丁 系统,操作系统补丁服务器

操作系统补丁服务器 内容精选换一换北京时间1月3日,Intel处理器芯片被曝出存在严重的Meltdown和Spectre安全漏洞,漏洞详情如下:漏洞名称:Intel处理器存在严重芯片级漏洞漏洞编号:CVE-2017-5753、CVE-2017-5715、CVE-20…

matlab 周立功can_隐藏在CAN协议底层的编码方式——到底是大端还是小端?

当我们想要讨论CAN协议底层发送到数据线上的二进制信号的编码方式时,最值得关注的两点是:字节编码(Endianness)和比特顺序(Bit Numbering)。先一句话揭晓答案:CAN协议的字节编码是大端编码&…

samba服务器新建文件权限,Ubuntu中安装samba服务器创建文件共享的方法及普通用户设置共享的问题解析...

Ubuntu中安装samba服务器创建文件共享的方法及普通用户设置共享的问题解析发布时间:2011-01-04 19:10:00 作者:佚名 我要评论本文是基于ubuntu桌面版进行操作说明的。前面的设置都是管理员进行的,这里说的管理员就是可以使用sudo命令&am…

flashpaper打印机没有被正确安装_没有正确保存与安装,可导致80%的轴承提早失效...

轴承损坏可谓司空见惯,可您是否知道,80%的轴承提早失效是因为没有正确地安装。轴承的正确安装,不仅可以增加轴承的使用寿命,降低成本,还可以大大提高生产效益。轴承安装与常规其他部件安装有很大区别,为了实…

rabbitmq实例_RabbitMQ不得不知道的点

RabbitMQ的优缺点优点这边的流量削峰功能主要应用在秒杀活动中,在秒杀活动中一般因为流量过大,导致应用挂掉,为了解决这个问题,在应用前端、库存系统前端加入消息队列,在订单系统中,服务器收到用户的请求后…

图片优化_网站里的图片应该如何优化

我们一直都在做网站关键词、内页关键词、标签等。但很多朋友都忽略了网站里的图片如何优化。近年来百度图片识别、360图片识别都在不断升级功能上已经很完善了,所以我们应该对网站图片进行优化,应该做seo的朋友们重视起来, 下面笔者跟大家分享…

rabbitmq 取消消息_mall整合RabbitMQ实现延迟消息

本文主要讲解mall整合RabbitMQ实现延迟消息的过程,以发送延迟消息取消超时订单为例。项目使用框架介绍RabbitMQRabbitMQ是一个被广泛使用的开源消息队列。它是轻量级且易于部署的,它能支持多种消息协议。RabbitMQ可以部署在分布式和联合配置中&#xff0…

vue 将行转换成对象_Vue简化版实现

Vue整体结构Vue: 把data中的成员注入到Vue实例,并且把data中的成员转换成getter, setterObserver: 劫持对象的所有属性, 如有变动可拿最新的值, 通知DepCompiler:解析每一个元素中的指令/插值表达式, 替换成相应的数据Dep: 发布者…

python 如何修改字典的key值_如何使用python技术完成数据集缺失值多种应用场景的滤除或填充?...

前言在数据处理的过程中,我们应该都有这样的体会,本质上数据处理与分析是相互协作,彼此成就的过程。比如,我们会用数据分析统计数据集中的缺失值、异常值,更直观的也会进阶到数据可视化的部分(到达该部分一般是成了文章…

python graphics 清空 图_【手把手教你】使用Python玩转金融时间序列模型

01引言上一篇推文【Python量化基础】时间序列的自相关性与平稳性着重介绍了时间序列的一些基础概念,包括自相关性、偏自相关性、白噪声和平稳性,以及Python的简单实现。本文在此基础上,以沪深300指数收益率数据为例,探讨如何使用P…

postman linux_Postman使用

postman简介官网https://learning.getpostman.com/用户在开发或者调试网络程序或者是网页B/S模式的程序的时候是需要一些方法来跟踪网页请求的,用户可以使用一些网络的监视工具比如著名的Firebug等网页调试工具。今天给大家介绍的这款网页调试工具不仅可以调试简单的…

java与MySQL做购物系统_java Swing mysql实现简单的购物系统项目源码附带指导视频教程...

大家好,今天给大家演示一下由Java swing实现的一款简单的购物程序,数据库采用的是mysql,该项目非常简单,实现了管理员对商品类型和商品的管理及用户注册登录后浏览商品、加入购物车、购买商品等功能,旨在学习Java 图形…

mysql pdm_mysql 生成pdm

1.条件1.1 工具powerDesigner16.51.2 mysql数据库地址或脚本1.3 mysql-connector-odbc-5.3.4-winx64.msi2.操作步骤2.1 database > change DBMS 选择Mysql5.02.2 打开powerDesigner16.5工具, file > reverse Engineer > database确定,则生成对应的pdm.3.图形列表中展示…

java 调用htm中js函数_从 node.js Web应用中调用 WASM 函数 | WebAssembly 入门教程

文中所有的代码都可以在 https://github.com/second-state/wasm-learning/tree/master/nodejs/hello 中找到在之前的教程中,我们讨论了如何从 Web 浏览器中的 JavaScript 应用程序访问 WebAssembly 函数。WebAssembly 快问快答从 Rust 开始入门 WebAssembly | WebAs…

vba cad 读取宏的路径_openpyxl 第三篇 lt;工作表的读取和写入gt;

1、打开表格文件from openpyxl import load_workbook wb load_workbook(r"文件路径工作簿文件全名")2. 查看有哪些sheet页sheet_names wb.sheetnames print(sheet_names)3. 读取指定的sheet页sheet1 wb[指定工作表的名字]4.单元格的使用#写 sheet1.cell(row3,colu…

mysql 一致性读_MySQL半一致性读原理解析-从源码角度解析

1、什么是半一致性读A type of read operation used for UPDATE statements, that is a combination of read committed and consistent read. When an UPDATE statement examines a row that is already locked, InnoDB returns the latest committed version to MySQL so tha…