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设置宽高会被覆盖。