一,写在前面
这篇文章先介绍如何使用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源码分析
public interface ViewManager
{
/**
* Assign the passed LayoutParams to the passed View and add the view to the window.
* &