更新2021
对于Kotlin用户,我设计了几个简单的扩展方法,可以将DialogFragment的宽度设置为屏幕宽度的百分比,或者接近全屏:
/**
* Call this method (in onActivityCreated or later) to set
* the width of the dialog to a percentage of the current
* screen width.
*/
fun DialogFragment.setWidthPercent(percentage: Int) {
val percent = percentage.toFloat() / 100
val dm = Resources.getSystem().displayMetrics
val rect = dm.run { Rect(0, 0, widthPixels, heightPixels) }
val percentWidth = rect.width() * percent
dialog?.window?.setLayout(percentWidth.toInt(), ViewGroup.LayoutParams.WRAP_CONTENT)
}
/**
* Call this method (in onActivityCreated or later)
* to make the dialog near-full screen.
*/
fun DialogFragment.setFullScreen() {
dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
}
然后在你的DialogFragment中或onActivityCreated之后:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setWidthPercent(85)
}
为子孙后代考虑一下这个答案的其余部分。
问题13:对话片段布局
这真的有点让人麻木。
当创建一个DialogFragment时,你可以选择覆盖onCreateView(它传递一个ViewGroup来附加你的.xml布局)或onCreateDialog,后者没有。
但是你不能同时覆盖这两个方法,因为你很可能会让Android搞不清楚你的对话框布局是否被夸大了!WTF ?
是否覆盖OnCreateView或OnCreateDialog的选择取决于你打算如何使用对话框。
如果你打算允许DialogFragment来控制它自己内部对话框的呈现,那么你需要重写OnCreateView。
如果你打算手动控制DialogFragment的对话框将如何呈现,你需要重写OnCreateDialog。
这可能是世界上最糟糕的事情了。
onCreateDialog疯狂
因此,您正在重写DialogFragment中的onCreateDialog以创建一个自定义的AlertDialog实例以显示在窗口中。酷。但是请记住,onCreateDialog没有接收ViewGroup来附加您的自定义.xml布局。没问题,您只需将null传递给充气方法。
让疯狂开始吧。
当你重写onCreateDialog时,Android完全忽略了你膨胀的.xml布局的根节点的几个属性。这包括但不限于:
background_color
layout_gravity
layout_width
layout_height
这几乎是滑稽的,因为你被要求设置每一个.xml布局的layout_width和layout_height或Android Studio将扇你一个漂亮的小红色耻辱徽章。
光是DialogFragment这个词就让我想吐。我可以写一本充满Android陷阱和混乱的小说,但这是最阴险的一个。
为了回归理智,首先,我们声明一个样式来恢复我们期望的background_color和layout_gravity:
<style name="MyAlertDialog" parent="Theme.AppCompat.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:layout_gravity">center</item>
</style>
上面的样式继承自对话框的基本主题(在本例中的AppCompat主题中)。
接下来,我们通过编程的方式应用样式来放回Android刚刚丢弃的值,并恢复标准的AlertDialog外观:
public class MyDialog extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View layout = getActivity().getLayoutInflater().inflate(R.layout.my_dialog_layout, null, false);
assert layout != null;
//build the alert dialog child of this fragment
AlertDialog.Builder b = new AlertDialog.Builder(getActivity());
//restore the background_color and layout_gravity that Android strips
b.getContext().getTheme().applyStyle(R.style.MyAlertDialog, true);
b.setView(layout);
return b.create();
}
}
上面的代码将使您的AlertDialog看起来像一个AlertDialog。也许这就足够了。
但是等等,还有更多!
如果你正在为你的AlertDialog设置一个特定的layout_width或layout_height,当它显示(很可能),然后你猜什么,你还没有完成!
有趣的是,当你意识到如果你试图在你的花哨的新样式中设置一个特定的layout_width或layout_height时,Android也会完全忽略它!:
<style name="MyAlertDialog" parent="Theme.AppCompat.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:layout_gravity">center</item>
<!-- NOPE!!!!! --->
<item name="android:layout_width">200dp</item>
<!-- NOPE!!!!! --->
<item name="android:layout_height">200dp</item>
</style>
要设置一个特定的窗口宽度或高度,你需要使用一个完整的方法来处理LayoutParams:
@Override
public void onResume() {
super.onResume();
Window window = getDialog().getWindow();
if(window == null) return;
WindowManager.LayoutParams params = window.getAttributes();
params.width = 400;
params.height = 400;
window.setAttributes(params);
}
许多人效仿Android的坏例子,使用WindowManager。LayoutParams到更通用的ViewGroup。LayoutParams,只是为了右转并施放ViewGroup。LayoutParams返回到WindowManager。几行之后的LayoutParams。有效的Java见鬼去吧,这种不必要的强制转换除了使代码更难破译之外,什么也没有提供。
旁注:在Android SDK中有大约20个重复的LayoutParams——这是一个非常糟糕的设计的完美例子。
总之
对于覆盖onCreateDialog的DialogFragments:
要恢复标准AlertDialog的外观和感觉,创建一个设置background_color = transparent和layout_gravity = center的样式,并在onCreateDialog中应用该样式。
要设置特定的layout_width和/或layout_height,可以在onResume中通过LayoutParams编程来实现
为了保持理智,尽量不要去想Android SDK。