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>