Как установить ширину и высоту 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? В настоящий момент мне нужно снова задать ширину и высоту моего диалога в моем методе DialogFragment onResume() следующим образом...

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

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

Ответ 1

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

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

Ответ 2

В итоге я переопределил 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);
}

Ответ 3

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

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

Ответ 4

Единственное, что сработало в моем случае, - это решение, указанное здесь: 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
}

Ответ 5

Один из способов контроля ширины и высоты 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 (caveat: 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 (caveat: 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();
}

Bonus

В старых 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();
}

Ответ 6

Gotcha # 13: DialogFragment Макеты

На самом деле это ошеломляет.

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

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

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

  • Если вы запустите диалог в окне (нормальное поведение), вы должны переопределить onCreateDialog.
  • Если вы намерены встраивать фрагмент диалога в существующий макет пользовательского интерфейса (FAR менее распространенный), тогда ожидается, что вы переопределите onCreateView.

Это, возможно, самое худшее в мире.

onCreateDialog Безумие

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

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

Когда вы переопределяете onCreateDialog, Android ПОЛНОСТЬЮ IGNORES несколько атрибутов корня node макета .xml, который вы раздуваете. Это включает, но, возможно, не ограничивается:

  • background_color
  • layout_gravity
  • layout_width
  • layout_height

Это почти комично, так как вы должны установить layout_width и layout_height КАЖДОГО .xml Layout или Android Studio, чтобы пощекотать вас красивым красным значком стыда.

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

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

Этот стиль наследуется от базовой темы для Dialogs (в теме 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. Возможно, это достаточно хорошо.

Но подождите, там еще!

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

Чтобы установить ширину или высоту окна SPECIFIC, вы можете перейти к целому '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 - прекрасный пример радикально плохого дизайна.

В резюме

Для DialogFragment, которые переопределяют onCreateDialog:

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

Ответ 7

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

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

Ответ 8

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

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

Ответ 9

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

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

Ответ 10

Здесь можно установить ширину/высоту DialogFragment в xml. Просто заверните свою иерархию view в 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">

      .....

Ответ 11

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

Ответ 12

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

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

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

Ответ 13

Я не вижу веской причины переопределять 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.

Ответ 14

Я создаю диалог, используя 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));
            }

        });

Ответ 15

Работа с 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>

Ответ 16

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

Ответ 17

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

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

Ответ 18

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

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

Ответ 19

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

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

Ответ 20

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

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

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

Ответ 21

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

Ответ 22

Добавьте к 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();
}

Ответ 23

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

    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
    }

Ответ 24

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