Posición de DialogFragment en Android
-
13-12-2019 - |
Pregunta
tengo un DialogFragment
para mostrar un View
como una pantalla emergente.La ventana aparece siempre en el medio de la pantalla.¿Hay alguna manera de establecer la posición del DialogFragment
¿ventana?He mirado en el código fuente pero no pude encontrar nada todavía.
Solución
Pruebe algo como esto:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
getDialog().getWindow().setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
WindowManager.LayoutParams p = getDialog().getWindow().getAttributes();
p.width = ViewGroup.LayoutParams.MATCH_PARENT;
p.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE;
p.x = 200;
...
getDialog().getWindow().setAttributes(p);
...
u otros métodos para getDialog().getWindow()
.
asegúrese de establecer la posición después de llamar a set-content.
Otros consejos
Bien, me golpeé la cabeza contra la pared durante una o dos horas con esto, antes de finalmente conseguirlo. DialogFragment
posicionado como quería.
estoy construyendo sobre La respuesta de Steelight aquí.Este es el enfoque más simple y confiable que encontré.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle b) {
Window window = getDialog().getWindow();
// set "origin" to top left corner, so to speak
window.setGravity(Gravity.TOP|Gravity.LEFT);
// after that, setting values for x and y works "naturally"
WindowManager.LayoutParams params = window.getAttributes();
params.x = 300;
params.y = 100;
window.setAttributes(params);
Log.d(TAG, String.format("Positioning DialogFragment to: x %d; y %d", params.x, params.y));
}
Tenga en cuenta que params.width
y params.softInputMode
(usados en la respuesta de Steelight) son irrelevantes para esto.
A continuación se muestra un ejemplo más completo.Lo que realmente necesitaba era alinear un DialogFragment de "cuadro de confirmación" junto a una Vista "fuente" o "principal", en mi caso un ImageButton.
Elegí usar DialogFragment, en lugar de cualquier Fragmento personalizado, porque le brinda funciones de "diálogo" de forma gratuita (cerrar el diálogo cuando el usuario hace clic fuera de él, etc.).
Ejemplo de ConfirmBox encima de su ImageButton "fuente" (papelera)
/**
* A custom DialogFragment that is positioned above given "source" component.
*
* @author Jonik, https://stackoverflow.com/a/20419231/56285
*/
public class ConfirmBox extends DialogFragment {
private View source;
public ConfirmBox() {
}
public ConfirmBox(View source) {
this.source = source;
}
public static ConfirmBox newInstance(View source) {
return new ConfirmBox(source);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(STYLE_NO_FRAME, R.style.Dialog);
}
@Override
public void onStart() {
super.onStart();
// Less dimmed background; see https://stackoverflow.com/q/13822842/56285
Window window = getDialog().getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.dimAmount = 0.2f; // dim only a little bit
window.setAttributes(params);
// Transparent background; see https://stackoverflow.com/q/15007272/56285
// (Needed to make dialog's alpha shadow look good)
window.setBackgroundDrawableResource(android.R.color.transparent);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Put your dialog layout in R.layout.view_confirm_box
View view = inflater.inflate(R.layout.view_confirm_box, container, false);
// Initialise what you need; set e.g. button texts and listeners, etc.
// ...
setDialogPosition();
return view;
}
/**
* Try to position this dialog next to "source" view
*/
private void setDialogPosition() {
if (source == null) {
return; // Leave the dialog in default position
}
// Find out location of source component on screen
// see https://stackoverflow.com/a/6798093/56285
int[] location = new int[2];
source.getLocationOnScreen(location);
int sourceX = location[0];
int sourceY = location[1];
Window window = getDialog().getWindow();
// set "origin" to top left corner
window.setGravity(Gravity.TOP|Gravity.LEFT);
WindowManager.LayoutParams params = window.getAttributes();
// Just an example; edit to suit your needs.
params.x = sourceX - dpToPx(110); // about half of confirm button size left of source view
params.y = sourceY - dpToPx(80); // above source view
window.setAttributes(params);
}
public int dpToPx(float valueInDp) {
DisplayMetrics metrics = getActivity().getResources().getDisplayMetrics();
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
}
Es bastante fácil hacer que lo anterior sea de uso más general agregando parámetros de constructor o definidores según sea necesario.(Mi final ConfirmBox
tiene un botón con estilo (dentro de algunos bordes, etc.) cuyo texto y View.OnClickListener
se puede personalizar en código.)
getDialog().getWindow()
no funcionará para un DialogFragment
como getWindow()
devolverá nulo si la actividad de alojamiento no es visible, lo cual no es así si estás escribiendo una aplicación basada en fragmentos.Obtendrás un NullPointerException
cuando lo intentas getAttributes()
.
Recomiendo la respuesta de Mobistry.Si ya tiene una clase DialogFragment, no es demasiado difícil cambiarla.Simplemente reemplace el método onCreateDialog con uno que construya y devuelva una ventana emergente.Entonces deberías poder reutilizar la Vista que proporcionas AlertDialog.builder.setView()
, y llama (PopupWindow object).showAtLocation()
.
Debe anular el método onResume() en su DialogFragment de la siguiente manera:
@Override
public void onResume() {
final Window dialogWindow = getDialog().getWindow();
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
lp.x = 100; // set your X position here
lp.y = 200; // set your Y position here
dialogWindow.setAttributes(lp);
super.onResume();
}
Estoy usando la clase PopupWindow para este propósito porque puedes especificar la ubicación y el tamaño de la vista.
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = new Dialog(mActivity, R.style.BottomDialog);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); //
dialog.setContentView(R.layout.layout_video_live);
dialog.setCanceledOnTouchOutside(true);
Window window = dialog.getWindow();
assert window != null;
WindowManager.LayoutParams lp = window.getAttributes();
lp.gravity = Gravity.BOTTOM; //psotion
lp.width = WindowManager.LayoutParams.MATCH_PARENT; // fuill screen
lp.height = 280;
window.setAttributes(lp);
return dialog;
}
estoy usando AppCompatDialogFragment
de android.support.v7.app.AppCompatDialogFragment
y quiero alinear el fragmento de diálogo con la parte inferior de la pantalla y también eliminar todos los bordes, especialmente necesitaba establecer el ancho del contenido para que coincida con el principal.
Entonces, quería de esto (el fondo amarillo proviene del diseño raíz del fragmento de diálogo):
Toma esto:
Ninguna de las soluciones anteriores funcionó.Entonces, logré hacer esto:
fun AppCompatDialogFragment.alignToBottom() {
dialog.window.apply {
setGravity(Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
decorView.apply {
// Get screen width
val displayMetrics = DisplayMetrics().apply {
windowManager.defaultDisplay.getMetrics(this)
}
setBackgroundColor(Color.WHITE) // I don't know why it is required, without it background of rootView is ignored (is transparent even if set in xml/runtime)
minimumWidth = displayMetrics.widthPixels
setPadding(0, 0, 0, 0)
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
invalidate()
}
}
}