Dialog、AlertDialog如何实现全屏

1、全屏Dialog实现方式

public class FullScrreenDialog extends Dialog {
    public FullScrreenDialog(Context context) {
        super(context);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        <!--关键点1-->
        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
        View view = LayoutInflater.from(getContext()).inflate(R.layout.fragment_full_screen, null);
        <!--关键点2-->
        setContentView(view);
        <!--关键点3-->
        getWindow().setBackgroundDrawable(new ColorDrawable(0x00000000));
        <!--关键点4-->
        getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
    }
}
  • 1、getWindow().requestFeature(Window.FEATURE_NO_TITLE);必须在setContent(View view)之后。
  • 2、关键点3和4必须通知设置才能达到全屏的效果。
    这又是为什么呢?这里先分析下关键点1。

1.1、关键点1

先看下setContentView()

@Override
    public void setContentView(int layoutResID) {
        //...省略部分就是创建DecorView,把id为android.R.id.content的ContentParent添加到DecorView中。
        mContentParentExplicitlySet = true;
    }

在setContentView()方法的最后mContentParentExplicitlySet = true;,接下看下getWindow().requestFeature()

@Override
    public boolean requestFeature(int featureId) {
        if (mContentParentExplicitlySet) {
            throw new AndroidRuntimeException("requestFeature() must be called before adding content");
        }
        //省略代码...
        return super.requestFeature(featureId);
    }

代码很简单,mContentParentExplicitlySet为true时,直接抛出异常,所以
getWindow().requestFeature()必须在setContentView()之前调用,对于Activity也是一样的。

1.2、关键点3和关键点4

为什么getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);不能实现全屏呢?
这是因为如果不设置background的话就会使用默认的背景,默认背景是含有inset标签构建的,并且四周设置了边距,所以不能达到全屏。
其实也可以在创建Dialog时,传入theme来实现全屏,只需设置windowIsFloating为false(Activity主题默认就是false),并设置windowBackground即可。

<style name="BaseDialog" parent="Theme.AppCompat.Dialog">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowIsFloating">false</item>
    </style>

1.3、windowIsFloating的作用

具体原因可查看PhoneWindow中的generateLayout()方法

protected ViewGroup generateLayout(DecorView decor) {
      //....
        mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
        int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
                & (~getForcedWindowFlags());
        if (mIsFloating) {
            setLayout(WRAP_CONTENT, WRAP_CONTENT);
            setFlags(0, flagsToUpdate);
        } else {
            setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
        }
}

mIsFloating为true时,则调用setLayout(WRAP_CONTENT, WRAP_CONTENT),所以设置mIsFloating为false可实现全屏。
2、AlertDialog全屏实现方式
其实AlertDialog的全屏实现方式和Dialog基本是类似的,不过需要注意的是getWindow.setLayout()需要在show()方法之后才生效。

AlertDialog alertDialog = new AlertDialog.Builder(this)
                .setView(R.layout.layout_dialog_small)
                .create();
        alertDialog.show();
        alertDialog.getWindow().setBackgroundDrawable(new ColorDrawable(0xffffffff));
        alertDialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT,WindowManager.LayoutParams.MATCH_PARENT);

看下AlertDialog的show()到底做了什么操作。

public AlertDialog show() {
            final AlertDialog dialog = create();
            dialog.show();
            return dialog;
        }

代码很简单就是创建AlertDialog并show(),主要的逻辑处理在show()中,AlertDialog.show()最终会调用Dialog中的show()

public void show() {
       //....
        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();
      //.....
        mWindowManager.addView(mDecor, l);
   //....
        mShowing = true;

        sendShowMessage();
    }

由于首次创建所以mCreated=false,则调用Dialog的dispatchOnCreate()

void dispatchOnCreate(Bundle savedInstanceState) {
        if (!mCreated) {
            onCreate(savedInstanceState);
            mCreated = true;
        }
    }

onCreate(savedInstanceState)的真正实现在AlertDialog中的

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAlert.installContent();
    }

在onCreate中会调用AlertController的installContent(),最终会调用mWindow.setContentView(),在分析windowIsFloating时,如果windowIsFloating=false,则会调用setLayout(WRAP_CONTENT,WRAP_CONTENT)所以如果在show之前调用setLayout设置宽高会被覆盖。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。