美文网首页Android深入
Dialog无法全屏的终极方案

Dialog无法全屏的终极方案

作者: 赛非斯 | 来源:发表于2021-10-21 09:28 被阅读0次
  • dialog作为与用户交互最简单的方式之一,不能随意放位置,不能全屏确实很恶心。有网友这样写
Dialog dialog = new Dialog(this, R.style.Dialog);
dialog.show();
LayoutInflater inflater = LayoutInflater.from(this);
View viewDialog = inflater.inflate(R.layout.adapter_list, null);
Display display = this.getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
//设置dialog的宽高为屏幕的宽高
ViewGroup.LayoutParams layoutParams = new  ViewGroup.LayoutParams(width, height);
dialog.setContentView(viewDialog, layoutParams);

这样可以是可以,但是setContentView 要放到show之后,我经常show这个dialog的话就显得代码沉余,很不爽。

  • 为什么要放到setContentView 之后呢,看dialog的构造方法,当没有传入themeid的时候用的是弹出此dialog的context 否则 ContextThemeWrapper包装themeresid 产生新的 mContext ,mContext 的重要性后面讲。
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        if (createContextThemeWrapper) {
            if (themeResId == Resources.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);
        //这里创建了PhoneWindow
        final Window w = new PhoneWindow(mContext);
        mWindow = w;
        w.setCallback(this);
        w.setOnWindowDismissedCallback(this);
        w.setOnWindowSwipeDismissedCallback(() -> {
            if (mCancelable) {
                cancel();
            }
        });
        w.setWindowManager(mWindowManager, null, null);
        //这里是dialog居中显示的原因,所以我们要改变他的位置就要在super()之后
        w.setGravity(Gravity.CENTER);

        mListenersHandler = new ListenersHandler(this);
    }

再看dialog的setContentView 方法,有人把它放到show之前,有人把它放到show之后,上面代码我们看到mWindow 就是 用context创建的PhoneWindow

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

看Phonewindow的源码

    public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }


   // installDecor 的时候会创建一个根布局,所以这个dialog能不能全屏也是它决定的
private void installDecor() {
 if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
}
    protected ViewGroup generateLayout(DecorView decor) {
        // Apply data from current theme.

        TypedArray a = getWindowStyle();

        if (false) {
            System.out.println("From style:");
            String s = "Attrs:";
            for (int i = 0; i < R.styleable.Window.length; i++) {
                s = s + " " + Integer.toHexString(R.styleable.Window[i]) + "="
                        + a.getString(i);
            }
            System.out.println(s);
        }

        mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
        int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
                & (~getForcedWindowFlags());
// 如果window的属性windowIsFloating 表示是否悬浮
        if (mIsFloating) {
            setLayout(WRAP_CONTENT, WRAP_CONTENT);
            setFlags(0, flagsToUpdate);
        } else {
            setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
        }
......
.....
}

    public void setLayout(int width, int height) {
        final WindowManager.LayoutParams attrs = getAttributes();
        attrs.width = width;
        attrs.height = height;
        dispatchWindowAttributesChanged(attrs);
    }
  • 上面的那一些都是你调用setContentView的时候完成设置的。 setLayout(WRAP_CONTENT, WRAP_CONTENT)决定了你的dialog只能由子view的大小决定。当然这样你也可以让dialog接近全屏{ 可以设置你view的大小接近屏幕宽高 },你也可以在setContentView之后设置宽高{你要考虑时机,也很容易出bug }。

终极解决方案 看dialog的style 以及注释就明白了:

 <!-- Default theme for dialog windows and activities (on API level 10 and lower),
         which is used by the
         {@link android.app.Dialog} class.  This changes the window to be
         floating (not fill the entire screen), and puts a frame around its
         contents.  You can set this theme on an activity if you would like to
         make an activity that looks like a Dialog. -->
    <style name="Theme.Dialog">
        <item name="windowFrame">@null</item>
        <item name="windowTitleStyle">@style/DialogWindowTitle</item>
        <item name="windowBackground">@drawable/panel_background</item>
        <item name="windowIsFloating">true</item>

结合源码我们知道只需要这样就可以自由设置宽高了
<item name="windowIsFloating">false</item>

dialog方便在哪:属于四大组件,不需要manifest注册;可以在任何地方弹

  • 最后提一下Dialog第二次无法弹出的现象,解决方案:
 if(mDialog!=null) {
            if (D.BUG) Log.d(TAG, "mDialog.isShowing()2="+mDialog.isShowing()+",mShowing="+mShowing);
            if(!mShowing){
                if(mDialog.isShowing()) {
                    mDialog.dismiss();
                }
                mDialog = new VomeDialog(mContext);
            }
        }
        mDialog.show();

相关文章

网友评论

    本文标题:Dialog无法全屏的终极方案

    本文链接:https://www.haomeiwen.com/subject/cpptaltx.html