ОБНОВЛЕНИЕ 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)
}
Рассмотрим оставшуюся часть этого ответа для потомков.
Gotcha #13: DialogFragment
Layouts
Это действительно ошеломляет разум.
При создании DialogFragment
вы можете выбрать переопределение onCreateView
(которое передает ViewGroup
для присоединения вашего XML-макета) или onCreateDialog
, что не делает.
Однако вы не должны переопределять оба метода, потому что вы, скорее всего, запутаете Android, когда и если макет вашего диалога был раздутым! Какого черта?
Выбор переопределения OnCreateView
или OnCreateDialog
зависит от того, как вы собираетесь использовать диалоговое окно.
- Если вы собираетесь разрешить
DialogFragment
управлять рендерингом своего внутреннего Dialog
, то ожидается, что вы переопределите OnCreateView
.
- Если вы намереваетесь вручную контролировать, как будет отображаться
DialogFragment
Dialog
, ожидается, что вы переопределите OnCreateDialog
.
Возможно, это худшее в мире.
onCreateDialog
Insanity
Итак, вы переопределяете onCreateDialog
в своем DialogFragment
, чтобы создать настраиваемый экземпляр AlertDialog
для отображения в окне. Прохладный. Но помните, onCreateDialog
не получает ViewGroup
для прикрепления вашего настраиваемого XML-макета к. Нет проблем, вы просто передаете null
методу inflate
.
Пусть начнется безумие.
Когда вы переопределяете onCreateDialog
, Android ПОЛНОСТЬЮ ИГНОРИРУЕТ несколько атрибутов корневого узла раздуваемого XML-макета. Это включает, но, вероятно, не ограничивается:
background_color
layout_gravity
layout_width
layout_height
Это почти смешно, так как вам необходимо установить layout_width
и layout_height
КАЖДОГО .xml Layout, иначе 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
. Может, этого достаточно.
But wait, there's more!
Если вы хотите установить КОНКРЕТНЫЙ layout_width
или layout_height
для своего AlertDialog
, когда он отображается (очень вероятно), то угадайте, что, вы еще не сделали!
Веселье продолжается, когда вы понимаете, что если вы попытаетесь установить конкретный 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 есть ДВАДЦАТЬ повторений LayoutParams
- прекрасный пример радикально плохого дизайна.
In Summary
Для DialogFragment
, которые заменяют onCreateDialog
:
- Чтобы восстановить стандартный
AlertDialog
внешний вид, создайте стиль, который задает background_color
= transparent
и layout_gravity
= center
, и примените этот стиль в onCreateDialog
.
- Чтобы установить конкретный
layout_width
и / или layout_height
, сделайте это программно в onResume
с помощью LayoutParams
- Чтобы сохранить рассудок, постарайтесь не думать об Android SDK.
person
rmirabelle
schedule
05.01.2017