Popupwindow和Dialog

3,097 阅读2分钟
  • 相同点

    都是弹框;  
    都有默认背景,都可以通过setBackgroundDrawable(new ColorDrawable(android.R.color.transparent))去掉
    
  • 不同点

    基本不同:  
        1. popupwindow需要在显示之前设置宽高,Dialog则不需要。  
        2. popupwindow默认不会响应物理键盘,除非显示设置了popup.setFocusable(true),Dialog在点击back键时会消失。   
        3. popupwindow不会给界面其他部分添加蒙版,Dialog会。    
        4. popupwindow没有标题,dialog有默认标题。  
        5. 二者显示的时候都要设置Gravity。如果不设置,Dialog默认是Gravity.CENTER。  
    
    核心不同:  
        差别
           Dialog是非阻塞式对话框:Dialog弹出时,后台还可以做事情。
           PopupWindow是阻塞式对话框:PopupWindow弹出时,程序会等待,在PopupWindow退出前,程序一直等待,只有当我们调用了dismiss方法的后,PopupWindow退出后程序才会继续执行。
           
        表现:
           Dialog弹出时,背景是黑色的,当我们点击背景Dialog会消失,程序不仅响应了Dialog的操作,也响应了其他的操作,因此其他程序没有被阻塞,所以Dialog是非阻塞式对话框。
           PopupWindow弹出时,背景没有什么变化,但是当我们点击背景的时候,程序没有响应,只允许我们操作PopupWindow,其他操作被阻塞。
        
        原理:
            从dialog的源码可以看出,一个dialog的创建就是一个window的创建;而Activity也是一个window,所以在onCreate中调用dialog的show方法可以弹出,因为两个window是相互独立的,dialog的弹出不会触发Activity的生命周期;
            PopupWindow的DecorView是PopupDecorView,PopupDecorView是继承FrameLayout,所以本质上PopupWindow就是一个View,需要依附一个具体的view,默认情况下是不能够在onCreate时显示;所以如果想要在界面显示的时候就弹出PopupWindow需要重写onWindowFocusChanged方法,判断activity完全显示,并且已经拿到焦点,此时才能进行显示
        
    
  • 源码
    Dialog
    核心: final Window w = new PhoneWindow(mContext)

 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);
    }

popupWindow
在createDecorView方法中,需要传递一个View对象

/** View that handles event dispatch and content transitions. */
private PopupDecorView mDecorView;
private class PopupDecorView extends FrameLayout
 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;
    }
  • 使用场景
    popupwindow特点是定位更加准确,对于宽高和边界的限制更加清晰,所以比较适合用作于一个Tips的提示。
    Dialog相对于更加独立,相当于一个新的界面,或者是用作应用程序中的Loading界面