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

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

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

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

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

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

22 ответов


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

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 в качестве корня файла макета вашего диалога.


Я закончил переопределение 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);
}

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

android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="1000dp"
android:minHeight="450dp"

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

фрагмент из сообщения блога Adil:

@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
}

один из способов контролировать свой 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();
}

бонус

На Старых Android API,Dialogs, похоже, имеют некоторые проблемы с шириной из-за их названия (даже если вы не установили его).
Если вы не хотите использовать 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 были причиной проблемы. Даже если они не были включены в тему my 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();
}

Гоча #13: DialogFragment макеты

это своего рода ум онемение на самом деле.

при создании DialogFragment, вы можете выбрать, чтобы переопределить onCreateView (который передает ViewGroup прикрепить .XML layout to) или onCreateDialog, который не.

вы не должны переопределять оба метода tho, потому что вы, скорее всего, запутаете Android о том, когда или если макет вашего диалога был завышен! WTF?

выбор того, следует ли переопределять OnCreateDialog или OnCreateView зависит от того, как вы собираетесь использовать диалог.

  • если вы запустите диалоговое окно (обычное поведение), вы должны переопределить OnCreateDialog.
  • если вы собираетесь внедрить фрагмент диалога в существующий макет пользовательского интерфейса (гораздо менее распространенный), то вы должны переопределить OnCreateView.

это, возможно, худшая вещь в мире.

onCreateDialog маразм

Итак, вы переопределение onCreateDialog в своем DialogFragment для создания настраиваемого экземпляра AlertDialog для отображения в окне. Прохладный. Но помни,onCreateDialog получает ViewGroup прикрепить свой заказ .макет XML to. Нет проблем, вы просто проходите null до inflate метод.

Пусть начнется безумие.

при переопределении onCreateDialog, Android ПОЛНОСТЬЮ ИГНОРИРУЕТ несколько атрибутов корневого узла .XML-макет вы раздуваете. Это включает, но, вероятно, не ограничивается:

  • background_color
  • layout_gravity
  • layout_width
  • layout_height

это почти смешно, так как вы должны установить layout_width и layout_height каждого .XML-макет или Android-студия ударят вас красивым маленьким красным значком стыда.

просто слово DialogFragment меня тошнит. Я мог бы написать роман, полный Android gotchas и snafus, но этот один из самых усердных.

чтобы вернуться к здравомыслию, во-первых, мы объявляем стиль для восстановления только 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 снова. Может, этого достаточно.

Но подождите, есть больше!

если вы хотите установить конкретные 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>

чтобы установить определенную ширину или высоту окна, вы можете перейти к целому " nuther методу и иметь дело с 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 проклята, что ненужное литье не предлагает ничего, кроме что делает код еще более трудным для расшифровки.

Примечание: есть около двадцати повторений LayoutParams по всему Android SDK-идеальный пример радикально плохого дизайна.

В Резюме

на DialogFragments, что переопределить onCreateDialog:

  • восстановить стандартный AlertDialog внешний вид, создать стиль, который устанавливает background_color = transparent и layout_gravity = center и применить этот стиль в onCreateDialog.
  • To установите определенный layout_width и/или layout_height, сделать это программно в onResume с LayoutParams
  • чтобы сохранить здравомыслие, постарайтесь не думать о Android SDK.

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

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:minWidth="320dp"
    ... />

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

<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>


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

int width = activity.getResources().getDisplayMetrics().widthPixels;
int height = activity.getResources().getDisplayMetrics().heightPixels;
content.setLayoutParams(new LinearLayout.LayoutParams(width, height));

вот способ установить ширину/высоту 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">

      .....

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

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

Я использовал тему Holo для этого примера.


Я создаю диалоговое окно с помощью AlertDialog.Строитель, поэтому я использовал ответ Родриго внутри 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));
            }

        });

работает на 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>

вы можете ниже кода установить ширину и высоту макета из 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();

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


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

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

легкий и твердый:

@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();
    }

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

лучшее решение, которое я нашел, - переопределить 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;
}

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

(убедитесь, что вы смотрите на свое решение) Это было его решение.. Нажмите Здесь Он работал, за исключением: 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);

последняя строка-это то, что действительно отличается.


@Override
public void onStart() {
    super.onStart();
    Dialog dialog = getDialog();
    if (dialog != null)
    {
        dialog.getWindow().setLayout(-1, -2);
        dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
        Window window = getDialog().getWindow();
        WindowManager.LayoutParams params = window.getAttributes();
        params.dimAmount = 1.0f;
        window.setAttributes(params);
        window.setBackgroundDrawableResource(android.R.color.transparent);
    }
}

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

установка ширины / высоты вместо этого внутри переопределенного 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 заранее.


чтобы получить диалоговое окно, которое охватывает почти всю осыпь: сначала определите класс 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);
}