Как установить ширину и высоту 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,Dialog
s, похоже, имеют некоторые проблемы с шириной из-за их названия (даже если вы не установили его).
Если вы не хотите использовать 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-идеальный пример радикально плохого дизайна.
В Резюме
на DialogFragment
s, что переопределить 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);
}