Как установить ширину и высоту DialogFragment?

Скажем, я указываю макет моего DialogFragment в XML-файле макета с именем my_dialog_fragment.xml, и я указываю значения layout_width и layout_height его корневого представления как фиксированное значение (например, 100dp). Затем я раздуваю этот макет в моем методе DialogFragment onCreateView(...) следующим образом:

View view = inflater.inflate(R.layout.my_dialog_fragment, container, false);

К сожалению, я обнаружил, что когда появляется мой DialogFragment, он не соблюдает значения layout_width и layout_height, указанные в его файле макета xml, и поэтому он сжимается или расширяется в зависимости от его содержимого. Кто-нибудь знает, могу ли я заставить свой DialogFragment уважать значения layout_width и layout_height, указанные в его файле макета xml? На данный момент мне нужно снова указать ширину и высоту Dialog в моем методе DialogFragment onResume() следующим образом:

getDialog().getWindow().setLayout(width, height);

Проблема в том, что я должен не забывать вносить любые будущие изменения в ширину и высоту в двух местах.


person Adil Hussain    schedule 18.09.2012    source источник
comment
Подумайте о том, чтобы принять ответ jpmcosta. Это не взлом, и он действительно решает проблему.   -  person Bogdan Zurac    schedule 05.10.2015


Ответы (27)


Если вы конвертируете напрямую из значений ресурсов:

int width = getResources().getDimensionPixelSize(R.dimen.popup_width);
int height = getResources().getDimensionPixelSize(R.dimen.popup_height);        
getDialog().getWindow().setLayout(width, height);

Затем укажите match_parent в вашем макете для диалога:

android:layout_width="match_parent"
android:layout_height="match_parent"

Вам нужно беспокоиться только об одном месте (поместите его в свой DialogFragment#onResume). Это не идеально, но, по крайней мере, он работает для использования RelativeLayout в качестве корня файла макета вашего диалога.

person Blix247    schedule 16.10.2012
comment
Этот ответ не работает в моем случае (для DialogFragment). Мне пришлось использовать параметры FragmentLayout для изменения размера отображаемого окна. - person Rusfearuth; 26.12.2012
comment
Мне пришлось обернуть мой макет в RelativeLayout, и это мне помогло. Большое спасибо за решение - оно сэкономило мне много времени. - person Johnny Doe; 23.07.2013
comment
Это отлично работает для меня (Android 4.0+), как только я понял, что это должно быть в onResume(), а не в onCreateView(). (Мой корневой макет - RelativeLayout, завернутый в ScrollView.) - person Jonik; 26.02.2014
comment
В некоторых случаях полезно: использовать всю ширину экрана: int width = getResources().getDisplayMetrics().widthPixels - person Jonik; 27.02.2014
comment
вы также можете вызвать это изнутри DialogFragment.onCreateDialog() - person Richard Le Mesurier; 01.09.2014
comment
+1 для Джоника. -1 для Ричарда. Я всегда использую фрагменты поддержки и никогда не мог заставить это работать в onCreateDialog(). Должен быть в onResume(). - person MinceMan; 05.09.2014
comment
Это работает, но в родительских представлениях customView есть отступы и поля. Если я помещу ожидаемую ширину и высоту customView в getDialog().getWindow().setLayout(width, height), customView приведет к меньшему размеру. Чтобы исправить это, мне нужно просмотреть родительские представления customView и очистить их отступы и поля. - person Weekend; 22.10.2015
comment
Что, если я хочу, чтобы высота была WRAP_CONTENT, а ширина - указанным размером? Как таким образом перейти WRAP_CONTENT в высоту? - person DYS; 14.07.2016
comment
+1 для Джоника. Наконец, после одного долгого дня поиска, но так и не найденного решения. Я очень не впечатлен функциями манипулирования изображениями DialogFragment, в частности потому, что изображения растягиваются по умолчанию. Кому нужен этот дефолт? Никто. - person carl; 30.07.2016
comment
@Weekend Я столкнулся с той же проблемой, что и вы. Я хочу знать, как вы ее решили. если я установил макет (любая ширина, 568); высота меньше 568 и, следовательно, мой вид прокручивается, я хочу, чтобы в функции была установлена ​​точная высота. Каковы значения отступов и полей для диалогового окна Android по умолчанию - person Aman Verma; 18.11.2017
comment
getDialog (). getWindow (). setLayout (WRAP_CONTENT, WRAP_CONTENT) будет работать. Мы также можем передать -1 (или MATCH_PARENT) и -2 (или WRAP_CONTENT) - person JEGADEESAN S; 06.01.2018

В итоге я переопределил Fragment.onResume() и взял атрибуты из нижележащего диалогового окна, а затем установил там параметры ширины / высоты. Я установил максимальную высоту / ширину макета на match_parent. Обратите внимание, что этот код, похоже, также учитывает поля, которые я определил в макете xml.

@Override
public void onResume() {
    super.onResume();
    ViewGroup.LayoutParams params = getDialog().getWindow().getAttributes();
    params.width = LayoutParams.MATCH_PARENT;
    params.height = LayoutParams.MATCH_PARENT;
    getDialog().getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
}
person jmaculate    schedule 13.06.2014
comment
Спасибо ! Меня устраивает ! Более того, это элегантный способ сделать это. - person AntoineP; 12.11.2014
comment
@jmaculate - Быстрый вопрос: когда вы транслируете (android.view.WindowManager.LayoutParams), из чего вы его транслируете? Я был озадачен при выборе правильного импорта для LayoutParams, появляющегося в первых 3 строках функции. В итоге выбрал (android.view.WindowManager.LayoutParams). Это должно быть правильно? - person Dev-iL; 13.12.2014
comment
@ Dev-iL getAttributes () возвращает WindowManger.LayoutParams, но в моем случае я неявно привел его к ViewGroup.LayoutParams, потому что это все, что мне нужно (Эффективная Java, пункт 52) - я отредактирую вопрос, чтобы отразить это - person jmaculate; 13.12.2014
comment
Спасибо за ссылку на Блоха :) - person Dev-iL; 13.12.2014
comment
Если вам нужно снова привести его к android.view.WindowManager.LayoutParams, бесполезно использовать ViewGroup.LayoutParams тремя строчками выше ... Здесь вы не получите никакой гибкости. Как бы то ни было, спасибо за хороший ответ! - person Kevin Robatel; 07.10.2015
comment
Это лучшее решение. Вы даже можете использовать определенное значение пикселей вместе с MATCH_PARENT или WRAP_CONTENT. - person Koesh; 12.01.2016
comment
Вот сокращение для этого ... getDialog().getWindow().setLayout( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ); - person E Malik; 29.06.2016
comment
в моем случае нет разницы между params.height=ViewGroup.LayoutParams.WRAP_CONTENT и MATCH_PARENT, не могли бы вы предложить мне решение? - person sepehr; 04.09.2016
comment
Занимает все пространство. Как дать ему маржу, чтобы при щелчке вне диалога он закрывался? - person Saeed Neamati; 02.06.2017
comment
@jmaculate, если я хочу динамически изменять высоту dialogFragment, разве onResume () не слишком поздно и вызовет тупой пользовательский интерфейс? Я бы сделал это в onMeasure (), если бы это был фрагмент или действие - person Elad Benda; 26.04.2019

У меня есть DialogFragment фиксированного размера, определяющий следующее в основном макете XML (LinearLayout в моем случае):

android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="1000dp"
android:minHeight="450dp"
person Jose_GD    schedule 09.10.2012
comment
Я обнаружил, что мне нужны midWidth и minHeight в Honeycomb, но не в ICS. - person daveywc; 18.04.2013
comment
На первый взгляд это работает, но, вероятно, этого следует избегать. Просмотр будет продолжаться за пределами экрана в зависимости от ширины устройства, поэтому, если у вас есть кнопки в правом нижнем углу, они не будут отображаться. - person CodyEngel; 11.07.2018
comment
Просмотр НЕ продолжается за пределами экрана. Кажется, что система Android следит за тем, чтобы DialogFragment оставался внутри границ представления (с небольшим запасом), даже если эти границы меньше, чем указанные minWidth и minHeight. - person Lensflare; 06.08.2018

ОБНОВЛЕНИЕ 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
comment
Когда я читаю этот ответ, мне хочется плакать. - person Bassinator; 08.07.2017
comment
Чувак, ты описал именно то, что я сейчас испытываю. - person Mert Gülsoy; 29.09.2017
comment
Андроид - дерьмо. Я чувствую тебя, братан. необходимость в контексте для всего, прерывание процесса приложения, отсутствие библиотек поддержки для некоторых вещей, список можно продолжить - person DennisVA; 12.08.2018
comment
@rmirabelle - этот ответ действительно поможет, вы действительно можете написать блог среднего размера и может быть полезен для многих. В моем случае я использую макет ограничения и DialogFragment, поэтому в Android 9 было проигнорировано, ниже Android 9 он работает нормально. Я добавил - android: windowMinWidthMajor, android: windowMinWidthMinor в стиле, и он начал работать нормально. - person Rahul; 29.08.2019
comment
@rmirabelle Привет, Прежде всего, ваш ответ действительно помог мне решить старую проблему. Но как человек, который должен все понимать, не могли бы вы объяснить мне, почему, если я напишу код, который изменил размер окна в onCreateView вместо onResume, он не применил желаемую ширину и высоту? Это сводит меня с ума, когда я делаю что-то, не понимая причину, по которой я это делаю - person Eitanos30; 21.03.2020
comment
@ Eitanos30 Я предполагаю, что объект Window недоступен до тех пор, пока ПОСЛЕ вызова onCreateView. Если понимание вещей важно для вас (как и для меня), у меня для вас плохие новости. Android - это самая непонятная вещь, которую когда-либо задумывали люди. - person rmirabelle; 21.03.2020
comment
@rmirabelle, спасибо :) если тебя (и меня тоже) это так беспокоит, как же нам разрабатывать под Android? - person Eitanos30; 21.03.2020
comment
@ Eitanos30, да, диалоги в Андроиде - лажа. Вы можете использовать onActivityCreated вместо onResume, если вы используете onCreateView вместо onCreateDialog. onCreateView ограничен во многих действиях в диалогах. - person CoolMind; 05.06.2020
comment
@CoolMind, приятно знать. Спасибо - person Eitanos30; 07.06.2020
comment
Может ли кто-нибудь отметить этот ответ как правильный? Это мне очень помогает!!!! - person Teo; 21.05.2021

Единственное, что сработало в моем случае, - это указанное здесь решение: http://adilatwork.blogspot.mx/2012/11/android-dialogfragment-dialog-sizing.html

Фрагмент из сообщения в блоге Адила:

@Override
public void onStart()
{
  super.onStart();

  // safety check
  if (getDialog() == null)
    return;

  int dialogWidth = ... // specify a value here
  int dialogHeight = ... // specify a value here

  getDialog().getWindow().setLayout(dialogWidth, dialogHeight);

  // ... other stuff you want to do in your onStart() method
}
person Rodrigo    schedule 03.12.2013
comment
Отличное решение и очень хорошо объяснено в блоге. - person varun bhardwaj; 19.04.2016
comment
+1 getDialog().getWindow().setLayout(dialogWidth, dialogHeight); отлично работает для DialogFragment. Но я не понимаю проверки безопасности. зачем нам проверять null? - person tpk; 09.09.2016
comment
@ 2943 - просто потому, что нет гарантии, что Dialog (дочерний элемент DialogFragment) будет доступен в то время, когда он запрошен. Возможно, что Android вернет null, когда мы вызовем getDialog(). - person rmirabelle; 05.01.2017
comment
@mirabelle, если вы используете обратный вызов onStart диалога, как диалог может быть нулевым? - person rommex; 21.07.2017

Один из способов управления шириной и высотой DialogFragment - убедиться, что диалоговое окно учитывает ширину и высоту вашего представления, если их значение равно WRAP_CONTENT.

Использование ThemeOverlay.AppCompat.Dialog

Один из простых способов добиться этого - использовать стиль ThemeOverlay.AppCompat.Dialog, включенный в библиотеку поддержки Android.

DialogFragment с Dialog:

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    Dialog dialog = new Dialog(getContext(), R.style.ThemeOverlay_AppCompat_Dialog);
    dialog.setContentView(view);
    return dialog;
}

DialogFragment с AlertDialog (предупреждение: minHeight="48dp"):

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    AlertDialog.Builder builder = new AlertDialog.Builder(getContext(), R.style.ThemeOverlay_AppCompat_Dialog);
    builder.setView(view);
    return builder.create();
}

Вы также можете установить ThemeOverlay.AppCompat.Dialog в качестве темы по умолчанию при создании диалогов, добавив ее к теме xml вашего приложения.
Будьте осторожны, так как многим диалоговым окнам требуется минимальная ширина по умолчанию, чтобы хорошо выглядеть.

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- For Android Dialog. -->
    <item name="android:dialogTheme">@style/ThemeOverlay.AppCompat.Dialog</item>

    <!-- For Android AlertDialog. -->
    <item name="android:alertDialogTheme">@style/ThemeOverlay.AppCompat.Dialog</item>

    <!-- For AppCompat AlertDialog. -->
    <item name="alertDialogTheme">@style/ThemeOverlay.AppCompat.Dialog</item>

    <!-- Other attributes. -->
</style>

DialogFragment с Dialog, используя android:dialogTheme:

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    Dialog dialog = new Dialog(getContext());
    dialog.setContentView(view);
    return dialog;
}

DialogFragment с AlertDialog, используя android:alertDialogTheme или alertDialogTheme (предупреждение: minHeight="48dp"):

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
    builder.setView(view);
    return builder.create();
}

Бонус

В более старых API Android у Dialog есть проблемы с шириной из-за их заголовка (даже если вы его не задали).
Если вы не хотите использовать стиль ThemeOverlay.AppCompat.Dialog и ваш Dialog не нуждается в заголовке (или есть собственный), вы можете отключить его:

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    LayoutInflater inflater = LayoutInflater.from(getContext());
    View view = inflater.inflate(R.layout.dialog_view, null);

    Dialog dialog = new Dialog(getContext());
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.setContentView(view);
    return dialog;
}

Устаревший ответ, в большинстве случаев не сработает

Я пытался заставить диалог уважать ширину и высоту моего макета, не задавая программный фиксированный размер.

Я подумал, что android:windowMinWidthMinor и android:windowMinWidthMajor были причиной проблемы. Несмотря на то, что они не были включены в тему моего Activity или Dialog, они каким-то образом все равно применялись к теме Activity.

Я предложил три возможных решения.

Решение 1. создайте настраиваемую тему диалогового окна и используйте ее при создании диалогового окна в DialogFragment.

<style name="Theme.Material.Light.Dialog.NoMinWidth" parent="android:Theme.Material.Light.Dialog">
    <item name="android:windowMinWidthMinor">0dip</item>
    <item name="android:windowMinWidthMajor">0dip</item>
</style>
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new Dialog(getActivity(), R.style.Theme_Material_Light_Dialog_NoMinWidth);
}

Решение 2: создайте настраиваемую тему, которая будет использоваться в ContextThemeWrapper, который будет служить Context для диалогового окна. Используйте это, если вы не хотите создавать настраиваемую тему диалогового окна (например, если вы хотите использовать тему, указанную в android:dialogTheme).

<style name="Theme.Window.NoMinWidth" parent="">
    <item name="android:windowMinWidthMinor">0dip</item>
    <item name="android:windowMinWidthMajor">0dip</item>
</style>
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new Dialog(new ContextThemeWrapper(getActivity(), R.style.Theme_Window_NoMinWidth), getTheme());
}

Решение 3 (с AlertDialog): применить android:windowMinWidthMinor и android:windowMinWidthMajor в ContextThemeWrapper, созданном AlertDialog$Builder.

<style name="Theme.Window.NoMinWidth" parent="">
    <item name="android:windowMinWidthMinor">0dip</item>
    <item name="android:windowMinWidthMajor">0dip</item>
</style>
@Override
public final Dialog onCreateDialog(Bundle savedInstanceState) {
    View view = new View(); // Inflate your view here.
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setView(view);
    // Make sure the dialog width works as WRAP_CONTENT.
    builder.getContext().getTheme().applyStyle(R.style.Theme_Window_NoMinWidth, true);
    return builder.create();
}
person jpmcosta    schedule 03.04.2015
comment
Я действительно не знаю, почему, черт возьми, это не принятый ответ. Это буквально единственный ответ, который работает, и не является взломом (я говорю в основном о вашем 1-м решении). - person Bogdan Zurac; 05.10.2015
comment
к сожалению, нашел это только после того, как потратил час на размышления, как решить! - person brainvision; 04.03.2016
comment
Решение 3 спасает мне жизнь. Большое спасибо - person Simon; 30.01.2017
comment
Мне удалось воспроизвести вашу проблему на более старых API Android. Добавлены альтернативы, которые могут вам помочь. - person jpmcosta; 15.12.2017
comment
Решение 1 сработало для меня. Я просто использовал Theme.MaterialComponents.Light.Dialog как родительский и использовал этот стиль в конструкторе MaterialAlertDialogBuilder. Наткнулся на ваш ответ после 1 часа исследования. Спасибо и палец вверх. - person Shahood ul Hassan; 15.07.2020

Когда мне нужно сделать DialogFragment немного шире, я устанавливаю minWidth:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:minWidth="320dp"
    ... />
person Andrew    schedule 03.09.2015
comment
Лучшее решение на мой взгляд! - person Fabian Knapp; 25.06.2016
comment
что, если вы хотите сделать его уже? - person Daniel; 01.06.2018

Я не вижу веских причин для переопределения onResume или onStart, чтобы установить ширину и высоту Window в DialogFragment Dialog - эти конкретные методы жизненного цикла могут вызываться многократно и без необходимости выполнять этот код изменения размера более одного раза из-за таких вещей, как многооконность переключение, фоновый режим, затем перевод приложения на передний план и т. д. Последствия такого повторения довольно тривиальны, но зачем на это соглашаться?

Установка ширины / высоты вместо этого в переопределенном методе onActivityCreated() будет улучшением, потому что этот метод реально вызывается только один раз для каждого экземпляра вашего DialogFragment. Например:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    Window window = getDialog().getWindow();
    assert window != null;

    WindowManager.LayoutParams layoutParams = window.getAttributes();
    layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
    window.setAttributes(layoutParams);
}

Выше я просто установил ширину match_parent независимо от ориентации устройства. Если вы хотите, чтобы диалоговое окно с альбомной ориентацией не было таким широким, вы можете заранее проверить getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT.

person N1hk    schedule 23.09.2018

Размер в самой внешней компоновке не работает в диалоге. Вы можете добавить макет, где установите размер ниже самого крайнего.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<LinearLayout
    android:layout_width="xxdp"
    android:layout_height="xxdp"
    android:orientation="vertical">

</LinearLayout>

person Kelly    schedule 26.11.2015

Я исправил это установив параметры макета корневого элемента.

int width = activity.getResources().getDisplayMetrics().widthPixels;
int height = activity.getResources().getDisplayMetrics().heightPixels;
content.setLayoutParams(new LinearLayout.LayoutParams(width, height));
person Erdem OLKUN    schedule 23.08.2013

Вот способ установить ширину / высоту DialogFragment в xml. Просто оберните вашу viewHierarchy в Framelayout (любой макет будет работать) с прозрачным фоном.

Прозрачный фон кажется особым флагом, потому что он автоматически центрирует дочерний элемент frameLayout в окне, когда вы это делаете. Вы по-прежнему будете затемнять весь экран позади вашего фрагмента, указывая, что ваш фрагмент является активным элементом.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/transparent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:background="@color/background_material_light">

      .....
person NameSpace    schedule 06.07.2015
comment
Я собираюсь попробовать, потому что, если он работает последовательно, это ОЧЕНЬ превосходный подход к кодированию части макета в XML и части в коде. Спасибо - person rmirabelle; 05.01.2017
comment
Мне нравится идея этого подхода, но при тестировании он дает другой макет, чем простое изменение высоты и ширины программным способом. Например, общая ширина принудительно уменьшается до максимальной ширины, предоставляемой AlertDialog (предположительно из-за стилей Android). Когда я просто устанавливаю w и h с помощью кода, стиль AlertDialog отменяется. Однако это может удовлетворить многие потребности, и это прекрасная идея. Да здравствует худший SDK в истории. - person rmirabelle; 05.01.2017
comment
Отлично работал с onCreateView, пока я не захотел изменить внутреннюю ширину на match_parent ... - person tudor; 05.04.2019

Вы можете использовать процент для ширины.

<style name="Theme.Holo.Dialog.MinWidth">
<item name="android:windowMinWidthMajor">70%</item>

I used Holo Theme for this example.

person StefanoM5    schedule 23.08.2016

Вот версия котлина

    override fun onResume() {
        super.onResume()

        val params:ViewGroup.LayoutParams = dialog.window.attributes
        params.width = LinearLayout.LayoutParams.MATCH_PARENT
        params.height = LinearLayout.LayoutParams.MATCH_PARENT
        dialog.window.attributes = params as android.view.WindowManager.LayoutParams
    }
person Qadir Hussain    schedule 01.10.2019

В моем случае DialogFragment занимал полный размер активности, как Fragment. DialogFragment был основан на XML-макете, а не на AlertDialog. Моя ошибка заключалась в добавлении фрагмента диалога в FragmentManager как обычный фрагмент:

fragmentManager?.beginTransaction()?.run {
    replace(R.id.container, MyDialogFragment.newInstance(), MyDialogFragment.TAG)
    addToBackStack(MyDialogFragment.TAG)
}?.commitAllowingStateLoss()

Вместо этого мне нужно show фрагмент диалога:

val dialogFragment = MyDialogFragment.newInstance()
fragmentManager?.let { dialogFragment.show(it, MyDialogFragment.TAG) }

После некоторого редактирования (у меня в макете ViewPager2) фрагмент диалога стал слишком узким:

введите описание изображения здесь

Я использовал решение N1hk:

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    dialog?.window?.attributes?.width = ViewGroup.LayoutParams.MATCH_PARENT
    dialog?.window?.attributes?.height = ViewGroup.LayoutParams.MATCH_PARENT
}

Теперь он определил ширину и высоту, а не полный размер активности.

Хочу сказать о onCreateView и onCreateDialog. Если у вас есть фрагмент диалога на основе макета, вы можете использовать любой из этих двух методов.

  1. Если вы используете onCreateView, тогда вы должны использовать onActivityCreated для установки ширины.

  2. Если вы используете onCreateDialog вместо onCreateView, вы можете установить там параметры. onActivityCreated не понадобится.

    переопределить удовольствие onCreateDialog (savedInstanceState: Bundle?): Dialog {super.onCreateDialog (savedInstanceState)

     val view = activity?.layoutInflater?.inflate(R.layout.your_layout, null)
    
     val dialogBuilder = MaterialAlertDialogBuilder(context!!).apply { // Or AlertDialog.Builder(context!!).apply
         setView(view)
         // setCancelable(false)
     }
    
     view.text_view.text = "Some text"
    
     val dialog = dialogBuilder.create()
     // You can access dialog.window here, if needed.
    
     return dialog
    

    }

person CoolMind    schedule 05.06.2020
comment
Вы спасли мне день, установка ширины в onActivityCreated сработала для меня. - person Hagar Magdy; 24.06.2020
comment
Я использую фрагменты, для меня я использовал onViewCreated как: override fun onViewCreated(view: View, savedInstanceState: Bundle?) { dialog?.window?.attributes?.width = ViewGroup.LayoutParams.MATCH_PARENT dialog?.window?.attributes?.height = ViewGroup.LayoutParams.MATCH_PARENT И без высоты тоже не сработало бы - person C. Hellmann; 21.09.2020
comment
@ C.Hellmann, спасибо! Согласитесь, возможно это поведение изменилось в API 30, я обновлю ответ. - person CoolMind; 22.09.2020

Вы можете под кодом установить ширину и высоту макета из java.

final AlertDialog alertDialog  = alertDialogBuilder.create();
final WindowManager.LayoutParams WMLP = alertDialog.getWindow().getAttributes();

WMLP.gravity = Gravity.TOP;
WMLP.y = mActionBarHeight;
WMLP.x = getResources().getDimensionPixelSize(R.dimen.unknown_image_width);

alertDialog.getWindow().setAttributes(WMLP);
alertDialog.show();
person Ruchit Mittal    schedule 13.11.2012

Я создаю диалог с помощью AlertDialog.Builder, поэтому я использовал ответ Родриго внутри OnShowListener.

dialog.setOnShowListener(new OnShowListener() {

            @Override
            public void onShow(DialogInterface dialogInterface) {
                Display display = getWindowManager().getDefaultDisplay();
                DisplayMetrics outMetrics = new DisplayMetrics ();
                display.getMetrics(outMetrics);
                dialog.getWindow().setLayout((int)(312 * outMetrics.density), (int)(436 * outMetrics.density));
            }

        });
person Jorge Garcia    schedule 28.01.2014
comment
(В основном для будущих читателей :) См. Комментарий Snicolas в обсуждении DialogFragment vs AlertDialog в stackoverflow.com/a/7979823/3372061. - person Dev-iL; 13.12.2014

Работая на Android 6.0, столкнулся с той же проблемой. AlertDialog по умолчанию будет использовать предопределенный width, установленный в теме, независимо от фактического width, установленного в корне пользовательского представления Layout. Я смог заставить его правильно настроить width из loading_message TextView. Без дальнейших исследований кажется, что определение размеров фактических элементов и обертывание их корнем Layout заставляет его работать так, как ожидалось. Ниже приведен XML-макет диалогового окна загрузки, который правильно устанавливает width диалогового окна. Использование этой библиотеки для анимации.

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@color/custom_color"
    android:padding="@dimen/custom_dimen">
    <com.github.rahatarmanahmed.cpv.CircularProgressView
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/progress_view"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_centerHorizontal="true"
        app:cpv_color="@color/white"
        app:cpv_animAutostart="true"
        app:cpv_indeterminate="true" />
    <TextView
        android:id="@+id/loading_message"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_below="@+id/progress_view"
        android:layout_centerHorizontal="true"
        android:gravity="center"
        android:textSize="18dp"
        android:layout_marginTop="@dimen/custom_dimen"
        android:textColor="@color/white"
        android:text="@string/custom_string"/>
</RelativeLayout>
person C0D3LIC1OU5    schedule 23.11.2015

Установите для родительского макета настраиваемого макета диалогового окна значение RelativeLayout, чтобы автоматически получить стандартную ширину и высоту.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
person vishnuc156    schedule 17.03.2017
comment
Это сработало для меня. Я хотел использовать ConstraintLayout для размещения элементов управления в моем диалоговом окне, поэтому я использовал RelativeLayout для корневого макета, а затем поместил ConstraintLayout непосредственно внутри него. Это дало мне диалог нормального размера. Когда я помещаю ConstraintLayout в качестве корня, ничего не меняя, ширина диалогового окна становится не очень широкой! - person leafcutter; 08.11.2019

Легко и надежно:

@Override
    public void onResume() {
        // Sets the height and the width of the DialogFragment
        int width = ConstraintLayout.LayoutParams.MATCH_PARENT;
        int height = ConstraintLayout.LayoutParams.MATCH_PARENT;
        getDialog().getWindow().setLayout(width, height);

        super.onResume();
    }
person SANAL CAMBAZ    schedule 21.01.2018

В моем случае это было вызвано align_parentBottom="true" данным представлением внутри RelativeLayout. Удалил все alignParentBottom и изменил все макеты на вертикальные LinearLayouts, и проблема исчезла.

person mehmet6parmak    schedule 31.01.2015

Одно из предыдущих решений почти сработало. Я попробовал что-то немного другое, и это сработало для меня.

(Убедитесь, что вы посмотрите на его решение) Это было его решение .. Нажмите здесь Это работал, кроме: builder.getContext (). getTheme (). applyStyle (R.style.Theme_Window_NoMinWidth, true);

Я изменил это на

 @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {


        // Use the Builder class for convenient dialog construction
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

        // Get layout inflater
        LayoutInflater layoutInflater = getActivity().getLayoutInflater();

        // Set layout by setting view that is returned from inflating the XML layout
        builder.setView(layoutInflater.inflate(R.layout.dialog_window_layout, null));


        AlertDialog dialog = builder.create();

        dialog.getContext().setTheme(R.style.Theme_Window_NoMinWidth);

Последняя строка на самом деле совсем другая.

person TheAppFoundry    schedule 05.06.2017

Это самое простое решение

Лучшее решение, которое я нашел, - переопределить onCreateDialog() вместо onCreateView(). setContentView () установит правильные размеры окна перед надуванием. Это устраняет необходимость хранить / устанавливать размер, цвет фона, стиль и т. Д. В файлах ресурсов и устанавливать их вручную.

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    Dialog dialog = new Dialog(getActivity());
    dialog.setContentView(R.layout.fragment_dialog);

    Button button = (Button) dialog.findViewById(R.id.dialog_button);
    // ...
    return dialog;
}
person parkgrrr    schedule 01.12.2017

Добавьте в свой FragmentDialog:

public void onResume() {
    Window window = getDialog().getWindow();
    Point size = new Point();
    Display display = window.getWindowManager().getDefaultDisplay();
    display.getSize(size);
    window.setLayout( (int)(size.x * 0.9), WindowManager.LayoutParams.WRAP_CONTENT );
    window.setGravity( Gravity.CENTER );
    super.onResume();
}
person RonTLV    schedule 07.08.2019

Это будет отлично работать.

@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);
}
person Kishore Reddy    schedule 07.01.2020
comment
Это в значительной степени то, о чем говорится в принятом ответе более 3 лет назад. - person Adil Hussain; 07.01.2020

Ни один из других ответов не помог мне. Для меня было решено только создать стиль, в котором вы можете выбрать процент экрана, который должен занимать ваш диалог:

<style name="RelativeDialog" parent="android:style/Theme.Dialog">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowIsFloating">true</item>
    <item name="windowNoTitle">true</item>
    <item name="windowActionBar">false</item>
    <item name="windowFixedWidthMajor">90%</item>
    <item name="windowFixedWidthMinor">90%</item>
    <item name="android:windowMinWidthMajor">90%</item>
    <item name="android:windowMinWidthMinor">90%</item>
    <item name="android:colorBackgroundCacheHint">@null</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowAnimationStyle">@android:style/Animation</item>
</style>

Затем просто установите этот стиль в диалоге, например:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setStyle(STYLE_NO_TITLE, R.style.RelativeDialog)
}
person bmilovanovic    schedule 14.04.2021

Используйте RelativeLayout в качестве родительского для DialogFragment.

person Sohaib Khan    schedule 16.07.2021
comment
Пожалуйста, не публикуйте один и тот же ответ дважды. - person Adrian Mole; 16.07.2021

Чтобы получить диалоговое окно, охватывающее почти всю осыпь: сначала определите класс ScreenParameter

public class ScreenParameters
{
    public static int Width;
    public static  int Height;

    public ScreenParameters()
    {
        LayoutParams l = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
        Width= l.width;
        Height = l.height;
    }
}

Затем вы должны вызвать ScreenParamater перед вашим методом getDialog.getWindow (). SetLayout ()

@Override
public void onResume()
{
    super.onResume();
    ScreenParameters s = new ScreenParameters();
    getDialog().getWindow().setLayout(s.Width , s.Height);
}
person Toye_Brainz    schedule 24.09.2014