Dialog与PopWindow的区别

2018-12-27  本文已影响0人  Zcurry

其中最本质的差别:
AlertDialog是非阻塞式对话框:AlertDialog弹出时,后台还可以做事情;
而PopupWindow是阻塞式对话框:PopupWindow弹出时,程序会等待,在PopupWindow退出前,程序一直等待,只有当我们调用了dismiss方法的后,PopupWindow退出,程序才会向下执行。
这两种区别的表现是:AlertDialog弹出时,背景是黑色的,但是当我们点击背景,AlertDialog会消失,证明程序不仅响应AlertDialog的操作,还响应其他操作,其他程序没有被阻塞,这说明了AlertDialog是非阻塞式对话框;PopupWindow弹出时,背景没有什么变化,但是当我们点击背景的时候,程序没有响应,只允许我们操作PopupWindow,其他操作被阻塞。

源码分析

1. Dialog

从dialog的源码可以看出,一个dialog的创建就是一个window的创建;而Activity也是一个window,所以在onCreate中调用dialog的show方法可以弹出,因为两个window是相互独立的,dialog的弹出不会触发Activity的生命周期;
并且源码中可以看出,dialog默认是点击空白取消的,并位于居中位置。
源码:

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
    if (createContextThemeWrapper) {
        if (themeResId == ResourceId.ID_NULL) {
            final TypedValue outValue = new TypedValue();
            context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
            themeResId = outValue.resourceId;
        }
        mContext = new ContextThemeWrapper(context, themeResId);
    } else {
        mContext = context;
    }

    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

    final Window w = new PhoneWindow(mContext);
    mWindow = w;
    w.setCallback(this);
    w.setOnWindowDismissedCallback(this);
    w.setOnWindowSwipeDismissedCallback(() -> {
        if (mCancelable) {
            cancel();
        }
    });
    w.setWindowManager(mWindowManager, null, null);
    w.setGravity(Gravity.CENTER);

    mListenersHandler = new ListenersHandler(this);
}

2. PopWindow

从源码来看PopWindow的DecorView是PopupDecorView,PopupDecorView是继承
FrameLayout,所以本质上PopupWindow就是一个View,需要依附一个具体的view,
默认情况下是不能够在onCreate时显示;所以如果想要在界面显示的时候就弹出PopupWindow
需要重写onWindowFocusChanged方法,判断activity完全显示,并且已经拿到焦点,此时
才能进行显示;
否则会报出异常:
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?

private void preparePopup(WindowManager.LayoutParams p) {
    ...
    mDecorView = createDecorView(mBackgroundView);
    mDecorView.setIsRootNamespace(true);
    ...
}
/**
 * Wraps a content view in a FrameLayout.
 *
 * @param contentView the content view to wrap
 * @return a FrameLayout that wraps the content view
 */
private PopupDecorView createDecorView(View contentView) {
    final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
    final int height;
    if (layoutParams != null && layoutParams.height == WRAP_CONTENT) {
        height = WRAP_CONTENT;
    } else {
        height = MATCH_PARENT;
    }

    final PopupDecorView decorView = new PopupDecorView(mContext);
    decorView.addView(contentView, MATCH_PARENT, height);
    decorView.setClipChildren(false);
    decorView.setClipToPadding(false);

    return decorView;
}

private class PopupDecorView extends FrameLayout {
       ...
}

其他

  1. PopWindow显示前需要设置宽高;Dialog不需要;
  2. PopWindow默认不会响应物理返回键;Dialog会在点击back键时消失;
  3. PopWindow不会给界面其他部分添加蒙层;Dialog会;
  4. PopWindow没有标题;Dialog默认有标题;
上一篇下一篇

猜你喜欢

热点阅读