FragmentDialog personalizado con esquinas redondeadas y sin ancho de pantalla del 100 %

10 minutos de lectura

avatar de usuario
vandus

Estoy creando un cuadro de diálogo de fragmento personalizado con esquinas redondeadas y con un diseño que no llenaría el ancho de la pantalla (preferiría si solo envolviera su contenido).

este es mi rounded_dialog.xml en la carpeta dibujable, que es llamada por mi Custom ThemeWithCorners como fondo para el diálogo. También traté de configurarlo como fondo para el diseño lineal que crea su contenido, pero nada funciona.

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" 
>
<solid android:color="@android:color/white"/>
<corners android:radius="20dp"
/>
</shape>

y así es como llamo al diálogo:

final String FTAG = "TAG_FRAGMENT_DIALOG_CALENDAR";
    dialog = (CalendarDialog) fm.findFragmentByTag(FTAG);
    ft = fm.beginTransaction();
    if (dialog != null)
    {
        ft.remove(dialog);
    }
    dialog = CalendarDialog.newInstance(this);      
    dialog.setCancelable(true);

    ft.add(dialog, FTAG);
    ft.show(dialog);
    ft.commit();

En el método onCreate del cuadro de diálogo, configuro el estilo y el tema:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setStyle(DialogFragment.STYLE_NO_TITLE, R.style.ThemeWithCorners);      
}

Este es el método onCreateView:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
getDialog().setCanceledOnTouchOutside(true);
v = (MyCalendar)inflater.inflate(R.layout.calendar_dialog, container, true)
    return v;
}

También intenté agregar esto al método onCreateDialog como sugirieron otras respuestas en SO, pero tampoco funcionó:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
    Dialog d =  super.onCreateDialog(savedInstanceState);
    LayoutParams lp=d.getWindow().getAttributes();
    d.getWindow().setBackgroundDrawable(new ColorDrawable(0));
    lp.width=-2;lp.height=-2;lp.gravity=Gravity.CENTER;
    lp.dimAmount=0;            
    lp.flags=LayoutParams.FLAG_LAYOUT_NO_LIMITS | LayoutParams.FLAG_NOT_TOUCH_MODAL;

    return d;
}

Entonces, para resumir, quiero esquinas redondeadas, no el 100% del ancho de la pantalla, preferiblemente debería envolver su contenido. Por favor, necesito ayuda, estoy realmente desesperada por esto, ¡lo he estado intentando durante días!

avatar de usuario
david miguel

Fondo de diálogo: dialog_rounded_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@android:color/white" />
    <corners android:radius="12dp" />
</shape>

Diseño de diálogo: dialog_rounded.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/dialog_rounded_bg"
    android:minWidth="260dp"
    android:orientation="vertical"
    android:padding="24dp">
    ...
</LinearLayout>

Fragmento de diálogo: RoundedDialog.java

public class RoundedDialog extends DialogFragment {
    ...
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.dialog_rounded, container, false);
        // Set transparent background and no title
        if (getDialog() != null && getDialog().getWindow() != null) {
            getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
            getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
        }
        return view;
    }
    ...
}

Diálogo redondeado

Actualizar: Si no pones la bandera Window.FEATURE_NO_TITLEaparece una línea azul en la parte superior del cuadro de diálogo en dispositivos con Android ≤ 4.4.

  • ¿Qué fuente has usado en el diálogo?

    – Anónimo

    29 de enero de 2018 a las 20:41

  • Es una fuente personalizada (Maison Neue).

    –David Miguel

    30 de enero de 2018 a las 14:07

  • Esta solución también funcionó con ConstraintLayout en lugar de un LinearLayout.

    – Michael Osofsky

    11 de junio de 2019 a las 16:26

avatar de usuario
vandus

Bueno, acabo de encontrar una solución, aunque no estoy muy contento con ella.

Configuré el fondo (rounded_dialog.xml) para el cuadro de diálogo de esta manera:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/transparent"/>
<corners android:radius="10dp" />
<padding android:left="10dp" android:right="10dp"/>
</shape>

Luego configuré esto en mi diálogo en su método ‘onCreateView’ de esta manera a continuación. Las esquinas redondeadas no son realmente necesarias en este fragmento de código ya que el fondo es transparente, pero el relleno es importante, porque el diálogo sigue siendo tan ancho como la pantalla, pero el relleno hace que parezca que no lo es.

getDialog().getWindow().setBackgroundDrawableResource(R.drawable.rounded_dialog);

Y al final configuré el fondo de los componentes del cuadro de diálogo en otro dibujo personalizado que hace que las esquinas se redondeen. Tengo un LinearLayout con RelativeLayout en la parte superior y TextView en la parte inferior, así que establecí @null en el LinearLayout principal y configuré dos dibujables personalizados diferentes para las dos partes, una de las cuales tiene esquinas inferiores redondeadas y la otra esquinas superiores.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" 
android:background="@drawable/title_round"  
>

<RelativeLayout
    android:id="@+id/title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"        
    android:orientation="horizontal" 
    android:background="@drawable/blue_title_round_top"
    android:paddingTop="4dp"
    android:paddingBottom="4dp"
    >
<TextView 
    android:id="@+id/calendarHint"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/rounded_bottom"
    android:layout_gravity="center"
    android:gravity="center"
        />
</LinearLayout>

Creo que hay una solución más adecuada para esto, ya que es correcta solo visualmente, no funcionalmente, pero lo suficientemente correcta para este caso.

avatar de usuario
Alon Deslizador

Respuesta actualizada de 2022 con Kotlin y View Binding –

class InternetLostDialog : DialogFragment() {

    private lateinit var binding: DialogInternetLostBinding

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        binding = DialogInternetLostBinding.inflate(LayoutInflater.from(context))
        val builder = AlertDialog.Builder(requireActivity())
        isCancelable = false
        builder.setView(binding.root)
        binding.root.setOnClickListener {
            requireActivity().finish()
        }
        val dialog = builder.create()
        dialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        return dialog
    }

}

De otra manera:

Usar setStyle() en onCreate() método para aplicar un estilo para usted DialogFragment.
Entonces, puedes usar android:background igual que siempre en el vista raíz de your_layout.xml expediente.


Pasos:

  1. estilo.xml presentar en resolución carpeta):
<style name="DialogTheme_transparent" parent="Theme.AppCompat.Dialog">
    <item name="android:windowBackground">@android:color/transparent</item>
    <!--You can set other style items also, such as animations and etc-->
</style>
  1. Crear your_layout.xml archivo en el carpeta de diseño:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="8dp"
    android:background="@drawable/bg_corner_dialog">
    ...
</LinearLayout>
  1. Crear bg_corner_dialog.xml archivo en el carpeta dibujable:
<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    android:dither="true">
    <solid android:color="#ffffff"/>
    <corners android:radius="16dp"/>
</shape>
  1. finalmente aplicar style y layout a la tuya DialogFragment:
public class CustomDialogFragment extends DialogFragment {
    ...

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(STYLE_NO_TITLE, R.style.DialogTheme_transparent);
        ...
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.your_layout, container, false);
        ButterKnife.bind(this, v);
        //init UI Elements...
        return v;
    }

}

Espero que esto te ayude.
Los mejores deseos

Una solución actualizada que funciona para mí usando Kotlin.

Configuré el fondo (rounded_dialog.xml) para el cuadro de diálogo de esta manera:

    <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="28dp" />
    <solid android:color="@color/white"/>
</shape>

luego calcule el ancho de la pantalla mediante programación y luego reste el valor del Margen, usando este fragmento de código.

val displayMetrics = DisplayMetrics()
        requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
        val width = displayMetrics.widthPixels

luego, dentro de la devolución de llamada onStart, apliqué ese ancho menos Margen. aquí está el código completo.

@AndroidEntryPoint
class CancelDialogFragment : DialogFragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        if (dialog != null && dialog?.window != null) {
            dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT));
            dialog?.window?.requestFeature(Window.FEATURE_NO_TITLE);
        }
        return inflater.inflate(R.layout.fragment_cancel_dialog, container, false)
    }

    override fun onStart() {
        super.onStart()
        val displayMetrics = DisplayMetrics()
        requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)

        val width = displayMetrics.widthPixels
        val height = displayMetrics.heightPixels

        dialog?.window?.setLayout(width-64, ViewGroup.LayoutParams.WRAP_CONTENT)
    }


}

Diseño XML fragment_cancel_dialog

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingVertical="32dp"
    android:padding="8dp"
    android:layout_marginHorizontal="8dp"
    android:background="@drawable/rounded_dialog"
    tools:context=".ui.orders.CancelDialogFragment">


    <TextView
        android:id="@+id/textView9"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="Reason of cancellation"
        android:textSize="16sp"
        app:layout_constraintStart_toStartOf="@+id/firstNameTIL"
        app:layout_constraintTop_toTopOf="parent" />


    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/firstNameTIL"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginHorizontal="24dp"
        android:layout_marginTop="16dp"
        app:hintAnimationEnabled="false"
        app:hintEnabled="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView9">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/firstNameET"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/edit_text_bg"
            android:drawablePadding="12dp"
            android:inputType="textPersonName"
            android:paddingHorizontal="16dp"
            android:paddingVertical="16dp"
            android:textAlignment="viewStart"
            android:textColor="@color/textColor"
            android:textColorHint="@color/black" />
    </com.google.android.material.textfield.TextInputLayout>


    <Button
        android:id="@+id/signUpButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="16dp"
        android:layout_marginBottom="32dp"
        android:background="@drawable/button_bg"
        android:paddingHorizontal="56dp"
        android:text="@string/confirmStr"
        android:textAllCaps="false"
        android:inputType="text"
        android:textColor="@color/black"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/firstNameTIL" />


</androidx.constraintlayout.widget.ConstraintLayout>

ingrese la descripción de la imagen aquí

avatar de usuario
waheed shah

Para cualquiera que quiera usar AlertDialogBuilder y transparente el fondo y establecer el Drawable en el archivo XML.

<style name="DialogStyle" parent="ThemeOverlay.MaterialComponents.Dialog.Alert">

<item name="android:background">@drawable/dialog_background</item>
<item name="android:windowBackground">@android:color/transparent</item>

Establezca este tema en Builder como se muestra a continuación

private val builder: AlertDialog.Builder = AlertDialog.Builder(context,R.style.DialogStyle)
    .setView(dialogView)

donde está R.drawable.dialog_background

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
    <shape android:shape="rectangle" android:padding="10dp">
        <solid
            android:color="@color/dialog_bg_color"/>
        <corners
            android:radius="30dp" />
    </shape>
</item>

Hay una solución rápida para DialogFragment. Por ejemplo, en el método onCreateDialog() añadir estilo en AlertDialog.Builder (contexto, estilo):

@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
    View view = LayoutInflater.from(getActivity()).inflate(R.layout.custom_dialog_lauout, null);
    return new AlertDialog.Builder(getActivity(), R.style.custom_alert_dialog)
            .setView(view)
            .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int i) {
                    // do something
                }
            })
            .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            })
            .create();
}

En la carpeta de estilos custom_alert_dialog

<style name="custom_alert_dialog" parent="Theme.AppCompat.Light.Dialog.Alert">
    <item name="android:windowBackground">@drawable/corner_background</item>
</style>

En carpeta dibujable corner_background.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF" />
<corners android:radius="8dp" />

ingrese la descripción de la imagen aquí

Está probado para API> = 21

¿Ha sido útil esta solución?