Conception de boîtes de dialogue Android personnalisées avec la classe Dialog

Lors du développement d'applications mobiles, il est fréquent de devoir afficher des invites contextuelles ou des vues partielles sans pour autant instancier une Activity complète qui nécessiterait une déclaration dans le fichier manifeste. Pour répondre à ce besoin d'interfaces superposées, les composants tels que PopupWindow ou Dialog sont particulièrement adaptés. Nous allons explorer ici l'implémentation d'une Dialog sur mesure, en nous affranchissant de la définition de styles XML complexes.

L'approche suivante démontre comment configurer directement les propriétés de la fenêtre et initialiser la vue personnalisée dans le code, garantissant ainsi un rendu transparent et un positionnement précis sans dépendre de thèmes globaux.

public class CustomPromptDialog extends Dialog {

    private View dialogLayout;
    private TextView promptMessage;
    private ViewGroup loadingContainer;

    public CustomPromptDialog(@NonNull Context context) {
        super(context);
    }

    /**
     * Initialisation de la vue et configuration de la fenêtre.
     * Il est recommandé de centraliser la logique de création ici.
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        configureWindowProperties();
        initializeLayout();
        setContentView(dialogLayout, new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT));
    }

    private void initializeLayout() {
        dialogLayout = LayoutInflater.from(getContext()).inflate(R.layout.layout_custom_prompt, null);
        promptMessage = dialogLayout.findViewById(R.id.txt_prompt_message);
        loadingContainer = dialogLayout.findViewById(R.id.container_loading);

        // Exemple d'interaction : affichage de l'état de chargement au clic
        promptMessage.setOnClickListener(v -> toggleLoadingState(true));
    }

    private void configureWindowProperties() {
        Window dialogWindow = getWindow();
        if (dialogWindow != null) {
            // Positionnement en haut de l'écran (valeur par défaut : centre)
            dialogWindow.setGravity(Gravity.TOP);
            // Suppression de l'assombrissement de l'arrière-plan
            dialogWindow.setDimAmount(0.0f);
            // Fond transparent pour la fenêtre elle-même (utile pour les coins arrondis personnalisés)
            dialogWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        }
    }

    public void toggleLoadingState(boolean isLoading) {
        if (loadingContainer != null) {
            loadingContainer.setVisibility(isLoading ? View.VISIBLE : View.GONE);
        }
    }
}

Le fichier de mise en page associé utilise une architecture à deux niveaux : un conteneur principal pour le contenu interactif et une superposition pour l'indicateur de porgression. L'utilisation de ConstraintLayout permet d'optimiser la hiérarchie des vues par rapport aux anciens layouts relatifs.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg_dialog_card">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp">

        <TextView
            android:id="@+id/txt_prompt_message"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Confirmer la fermeture ?"
            android:textSize="16sp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent" />

        <View
            android:id="@+id/divider_top"
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:layout_marginTop="16dp"
            android:background="#E0E0E0"
            app:layout_constraintTop_toBottomOf="@id/txt_prompt_message" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:orientation="horizontal"
            app:layout_constraintTop_toBottomOf="@id/divider_top">

            <TextView
                android:id="@+id/btn_cancel"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:gravity="center"
                android:padding="12dp"
                android:text="Annuler"
                android:textColor="#1976D2" />

            <View
                android:layout_width="1dp"
                android:layout_height="match_parent"
                android:background="#E0E0E0" />

            <TextView
                android:id="@+id/btn_confirm"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:gravity="center"
                android:padding="12dp"
                android:text="Valider"
                android:textColor="#1976D2" />
        </LinearLayout>
    </androidx.constraintlayout.widget.ConstraintLayout>

    <FrameLayout
        android:id="@+id/container_loading"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#80FFFFFF"
        android:clickable="true"
        android:focusable="true"
        android:visibility="gone">

        <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:indeterminateTint="#FFC107" />
    </FrameLayout>

</FrameLayout>

Étiquettes: Android Java XML dialog UI

Publié le 1 juillet à 21h27