Android 源码解析之WindowManager添加窗口

本文探讨了如何使用WindowManager在Android设备上添加并显示View,详细解析了LayoutParams的type和flag属性,以及它们对窗口层级和触摸事件的影响。通过源码分析,揭示了WindowManager添加窗口的具体实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一,写在前面       

 这篇文章先介绍如何使用WindowManager向设备窗口里添加View,并显示View,然后从源码角度分析这一过程。

二,WindowManager的使用

WindowManager的使用,先来看看效果,如下所示:


代码如下:

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
		
		//创建WindowManager的布局参数对象
		WindowManager.LayoutParams params = new WindowManager.LayoutParams(
		LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0, PixelFormat.TRANSPARENT);
		
		params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
	      //params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
		params.type = WindowManager.LayoutParams.TYPE_APPLICATION;
		
		params.gravity = Gravity.TOP | Gravity.LEFT;
		params.x = 50;
		params.y = 400;
		
		//创建一个View
		final TextView view = new TextView(this);
		view.setText("window_demo");
		view.setTextSize(24);
		view.setTextColor(Color.RED);
		view.setOnTouchListener(new OnTouchListener() {
			
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				view.setTextColor(Color.BLUE);
				return false;
			}
		});

		//在窗口添加View
		wm.addView(view, params);		
	}
}

分析:

       1,LayoutParams是WindowManager中的一个内部类,它继承至ViewGroup.LayoutParams,并实现了Parcelable接口,public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable{...}。需要重点关注LayoutParams中的两个字段:type,flag。

       type:决定了窗口的类型,Android给窗口设置了三个层级,抽象来说分为:应用程序窗口,子窗口,系统窗口。具体来说对应int值的范围,分别为1~99,1000~1999,2000~2999。上面代码中TYPE_SYSTEM_OVERLAY是系统窗口类型的一种,TYPE_APPLICATION是应用程序窗口的一种。窗口层级越大,该窗口会在比它层级小的窗口上面显示,也就是层级大的窗口会覆盖层级较小的窗口。因此,若想让窗口处在所有窗口上面显示,可以将type设置为系统窗口。一般可以设置系统窗口的type值有:TYPE_SYSTEM_OVERLAY,TYPE_SYSTEM_ERROR。


      特别需要注意的是:若将type设置为系统窗口层级时,需要在AndroidManifest.xml文件中配置权限“android.permission.SYSTEM_ALERT_WINDOW”,否则会报异常信息。

如下所示:


        

        flag:决定窗口的显示特性,上面代码中的FLAG_NOT_TOUCH_MODAL指:可以处理窗口区域里的事件,区域外的事件传给底层的Window。flag有很多值可以选择,并使窗口显示不同的特性,有兴趣哥们可以自己去研究。

        另外,LayoutParams还提供gravity,x,y三个属性,gravity:决定窗口的重心位置,如果gravity不设置,窗口默认在屏幕中间。值得一提的是,x,y均是相对于设置好gravity后的偏移量。


        2,上例中给TextView设置了触摸的监听,点击TextView后修改其颜色为蓝色。若设置窗口类型为TYPE_SYSTEM_OVERLAY,无法响应触摸动作,颜色不会改变。这是为什么呢?因为系统窗口不接收焦点,否则会干扰键盘窗口的输入。翻看Android给TYPE_SYSTEM_OVERLAY的注释便知,如下:

/**
         * Window type: system overlay windows, which need to be displayed
         * on top of everything else.  These windows must not take input
         * focus, or they will interfere with the keyguard.
         * In multiuser systems shows only on the owning user's window.
         */
        public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;
       值得一提的是,即使设备当前显示界面不是这个主界面,而是显示桌面,系统窗口仍然显示(有些手机需要手动设置悬浮框开启,才可以看到效果)。

效果如下:


     上面介绍了WindowManager的一个简单使用,将TextView添加到窗口中并显示,下面分析WindowManager源码角度的分析。


三,WindowManager源码分析

     上面调用wm.addView(view,params)方法添加窗口,并没有涉及到Window,有木有觉得很奇怪,下面来解惑。
      1,首先,了解Window,public abstract class Window。Window是一个抽象类,提取了窗口需要的一些方法,并不是一个真实意义上的窗口。Window有且只有一个子类PhoneWindow,public class PhoneWindow extends Window implements MenuBuilder.Callback,Window的实例化的体现由PhoneWindow来完成。任何一个View都对应一个Window,也就是说View不能孤立存在的显示,需要依靠一个Window。
 
    ,2,然后了解接口ViewManager,接口WindowManager,类WindowManagerImpl之间的关系:ViewManager是爷爷,WindowManager是爸爸,WindowManagerImpl是孩子。
     ViewManager如下:
public interface ViewManager
{
    /**
     * Assign the passed LayoutParams to the passed View and add the view to the window.
     * &
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值