前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Dialog 的 Window 创建过程

Dialog 的 Window 创建过程

作者头像
Yif
发布2019-12-26 15:29:27
7860
发布2019-12-26 15:29:27
举报
文章被收录于专栏:Android 进阶Android 进阶
undefined
undefined

Dialog 的 Window 创建过程

首先在Dialog 的构造方法中创建Window实例final Window w = new PhoneWindow(mContext);

代码语言:javascript
复制
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);
    }

再初始化DecorView 并将Dialog 布局添加到DecorView中

代码语言:javascript
复制
/**
     * Set the screen content from a layout resource.  The resource will be
     * inflated, adding all top-level views to the screen.
     * 
     * @param layoutResID Resource ID to be inflated.
     */
    public void setContentView(@LayoutRes int layoutResID) {
        mWindow.setContentView(layoutResID);
    }

DecorView添加到Window中,并调用show方法进行显示

代码语言:javascript
复制
 public void show() {
 //判断是否已经显示,并且mDecor已经初始化过就直接返回,让当前view进行显示
        if (mShowing) {
            if (mDecor != null) {
                if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                    mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
                }
                mDecor.setVisibility(View.VISIBLE);
            }
            return;
        }
 
        mCanceled = false;
 
        if (!mCreated) {
            dispatchOnCreate(null);
        } else {
            // Fill the DecorView in on any configuration changes that
            // may have occured while it was removed from the WindowManager.
            final Configuration config = mContext.getResources().getConfiguration();
            mWindow.getDecorView().dispatchConfigurationChanged(config);
        }
 
        onStart();
        mDecor = mWindow.getDecorView();
 
        if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
            final ApplicationInfo info = mContext.getApplicationInfo();
            mWindow.setDefaultIcon(info.icon);
            mWindow.setDefaultLogo(info.logo);
            mActionBar = new WindowDecorActionBar(this);
        }
 
        WindowManager.LayoutParams l = mWindow.getAttributes();
        if ((l.softInputMode
                & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
            WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
            nl.copyFrom(l);
            nl.softInputMode |=
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
            l = nl;
        }
//将DecorView添加到WindowManager中
        mWindowManager.addView(mDecor, l);
        mShowing = true;
 
        sendShowMessage();
    }

Dialoghide与dismiss方法,hide只是隐藏当前窗体,但是并没有不显示它,还是存在的,只是看不见;dismiss是完全不显示,并且当前WindowManager会移除当前DecorViewmWindowManager.removeViewImmediate(mDecor);

代码语言:javascript
复制
/**
     * Hide the dialog, but do not dismiss it.
     */
    public void hide() {
        if (mDecor != null) {
            mDecor.setVisibility(View.GONE);
        }
    }
 
    /**
     * Dismiss this dialog, removing it from the screen. This method can be
     * invoked safely from any thread.  Note that you should not override this
     * method to do cleanup when the dialog is dismissed, instead implement
     * that in {@link #onStop}.
     */
    @Override
    public void dismiss() {
        if (Looper.myLooper() == mHandler.getLooper()) {
            dismissDialog();
        } else {
            mHandler.post(mDismissAction);
        }
    }
 
    void dismissDialog() {
        if (mDecor == null || !mShowing) {
            return;
        }
 
        if (mWindow.isDestroyed()) {
            Log.e(TAG, "Tried to dismissDialog() but the Dialog's window was already destroyed!");
            return;
        }
 
        try {
            mWindowManager.removeViewImmediate(mDecor);
        } finally {
            if (mActionMode != null) {
                mActionMode.finish();
            }
            mDecor = null;
            mWindow.closeAllPanels();
            onStop();
            mShowing = false;
 
            sendDismissMessage();
        }
    }

普通的Dialog只能采用Activity的Context,如果采用Application的Context就会报错。是由于没有token导致的,而token只有Activity有,所以只能采用Activity的Context,但是可以将窗体升级为系统类型的弹窗,就不会报错。 getWindow.setType(LayoutParams.TYPE_SYSTEM_ERROR); 并加入权限使用系统Window: <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年9月18日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Dialog 的 Window 创建过程
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档