Как установить ширину и высоту 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);
}