8_理解Window和WindowManager

理解Window和WindowManager

1、Window和WindowManager

某些特殊的时候,我们需要在桌面上显示一个类似悬浮窗的东西,那么这种效果就需要用到Window来实现。

Window是一个抽象类,它的具体实现是phoneWindow。创建一个Window是很简单的事,只需要通过WindowManager即可完成。WindowManager是外界访问Window的入口,Window的具体实现位于WindowManagerService中,WindowManager和WindowManagerService的交互是一个IPC的过程。

Android中所有的视图都是通过Window来呈现的,不管是Activity、Dialog还是Toast,它们的视图实际上都是附加在Window上,因此,Window实际上是View的直接管理者。

单击事件由Window传递给DecorView,然后再由DecorView传递给我们的View,就连Activity的设置视图的方法setContentView在底层也是Window来完成的。

①、使用WindowManager添加一个Window,代码示例:

 public void onButtonClick(View v) {
        if (v == mCreateWindowButton) {
            mFloatingButton = new Button(this);
            mFloatingButton.setText("click me");
            mLayoutParams = new WindowManager.LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0,
                    PixelFormat.TRANSPARENT);
            mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | LayoutParams.FLAG_NOT_FOCUSABLE
                    | LayoutParams.FLAG_SHOW_WHEN_LOCKED;
            mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR;
            mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
            mLayoutParams.x = 100;
            mLayoutParams.y = 300;
            mFloatingButton.setOnTouchListener(this);
            mWindowManager.addView(mFloatingButton, mLayoutParams);
        }
    }

上述代码可以将一个Button添加到屏幕坐标为(100,300)的位置上。WindowManager.LayoutParams中的flags和type这两个参数比较重要。

Flags参数表示Window的属性,它有很多选项,通过这些选项可以控制Window的显示特性:

FLAG_NOT_FOCUSABLE:表示window不需要获取焦点,也不需要接收各种输入事件,此标记同时启用FLAG_NOT_TOUCH_MODAL,最终事件会直接传到给下层具有焦点的Window。

FLAG_NOT_TOUCH_MODAL:此模式下,系统会将当前Window区域以外的单击事件传递给底层的Window,当前Window区域以内的单击事件这自己处理。这标记一般需要开启,否则其他Window将无法收到单击事件。

FLAG_SHOW_WHEN_LOCKED:开启此模式可以让Window显示在锁屏的界面上。

Type参数表示Window的类型,Window有三种类型,分别是Window、子Window和系统Window。应用型Window对应着一个Activity;子Window不能单独存在,它需要附属在指定的父Window之中,比如常见的一些Dialog就是一个子Window;系统Window是需要声明权限在能创建的Window,比如Toast和系统状态栏都是Window。

Window是分层的,每个Window都有对应的z-ordered,层级大的会覆盖在层级小的Window上面。在三类Window中,应用Window的层级为1--99,子Window的层级范围是1000--1999,系统Window的层级范围是2000---2999,这些层级范围对应着WindowManager.layoutParams的type参数。

WindowManager所提供的功能很简单,常用的只有三个方法,即添加View、更新View、删除View

package android.view;

/** Interface to let you add and remove child views to an Activity. To get an instance
  * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
  */
public interface ViewManager
{
    /**
     * Assign the passed LayoutParams to the passed View and add the view to the window.
     * <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming
     * errors, such as adding a second view to a window without removing the first view.
     * <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a
     * secondary {@link Display} and the specified display can't be found
     * (see {@link android.app.Presentation}).
     * @param view The view to be added to this window.
     * @param params The LayoutParams to assign to view.
     */
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

对于开发者来说,WindowManger常用的就只有这三个功能而已,但是这三个功能已经足够我们使用了。

它可以创建一个Window并向其添加View,还可以更新Window中的View,另外如果想要删除一个Window,那么只需要删除它里面的View即可,由此看来,WindowManager操作Window的过程更像是操作Window中的View。

我们常见的那种拖动Window的效果,代码示例:

 @Override
    public boolean onTouch(View v, MotionEvent event) {
        int rawX = (int) event.getRawX();
        int rawY = (int) event.getRawY();
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            break;
        }
        case MotionEvent.ACTION_MOVE: {
            int x = (int) event.getX();
            int y = (int) event.getY();
            mLayoutParams.x = rawX;
            mLayoutParams.y = rawY;
            mWindowManager.updateViewLayout(mFloatingButton, mLayoutParams);
            break;
        }
        case MotionEvent.ACTION_UP: {
            break;
        }
        default:
            break;
        }

        return false;
    }

2、Window内部机制

Window是一个抽象的概念,每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,因此Window并不是实际存在的,它是以View的形式存在的。这点可以从WindowManager的定义也可以看出,它提供了三个接口方法addView、updateViewLayout以及removeView都是针对View的,这说明View才是Window存在的实体。在实际使用中无法直接访问Window,对Window的访问必须通过WindowManager。

为了分析Window的内部机制,那么就从Window的添加、删除以及更新说起。

1)、Window的添加过程

2)、Window的删除过程

3)、Window的更新过程

3、Window创建过程

Android中可以提供视图的地方有Activity、Dialog、Toast,除此之外,还有一些依托Window而实现的视图,比如PopupWindow、菜单,它们也是视图,有视图的地方就有Window,因此Activity、Dialog、Toast等视图都对应着一个Window。

1)、Activity的Window创建过程

2)、Dialog的Window创建过程

3)、Toast的Window创建过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值