Giới thiệu
Ví dụ này minh họa cách tạo hộp thoại tùy chỉnh (Custom AlertDialog) với layout XML riêng biệt, cho phép thiết kế giao diện dialog phức tạp (icon, tiêu đề, nội dung, nút bấm tùy chỉnh) thay vì dùng AlertDialog.Builder mặc định.
Các bước thực hiện
Bước 1: Tạo dự án mới
Mở Android Studio, chọn File → New Project.
Bước 2: Giao diện chính (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/buttonShowDialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:backgroundTint="@color/colorPrimary"
android:padding="15dp"
android:text="Hiển thị Custom Dialog"
android:textAllCaps="false"
android:textColor="#ffffff"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Bước 3: Layout Custom Dialog (res/layout/my_dialog.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@color/colorPrimary">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerInParent="true"
android:background="@drawable/ic_success"
android:contentDescription="Success icon" />
</RelativeLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Thành công"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla eu erat tincidunt lacus fermentum rutrum."
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1" />
<Button
android:id="@+id/buttonOk"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="15dp"
android:background="@drawable/button_background"
android:text="OK"
android:textColor="@color/colorPrimary" />
</LinearLayout>
Bước 4: Drawable nút bấm (res/drawable/button_background.xml)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="https://schemas.android.com/apk/res/android">
<item>
<shape>
<stroke android:width="2dp" android:color="@color/colorPrimary" />
<solid android:color="@android:color/transparent" />
<corners android:radius="6dp" />
</shape>
</item>
</selector>
Bước 5: Vector icon thành công (res/drawable/ic_success.xml)
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="https://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="#FFFFFF"
android:pathData="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zm0-384a128 128 0 1 1 0 256 128 128 0 0 1 0-256zm100.8 168.8L208 384l-56-56 22.6-22.6 33.4 33.4 77.4-77.4 22.6 22.6z" />
</vector>
Bước 6: MainActivity (src/MainActivity.java)
package com.app.sample;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.buttonShowDialog).setOnClickListener(v -> showCustomDialog());
}
private void showCustomDialog() {
ViewGroup viewGroup = findViewById(android.R.id.content);
View dialogView = LayoutInflater.from(this).inflate(R.layout.my_dialog, viewGroup, false);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(dialogView);
AlertDialog alertDialog = builder.create();
// Tùy chọn: không cho dismiss khi click ngoài
// alertDialog.setCanceledOnTouchOutside(false);
// Xử lý nút OK trong custom layout
dialogView.findViewById(R.id.buttonOk).setOnClickListener(v -> alertDialog.dismiss());
alertDialog.show();
// Tùy chọn: điều chỉnh chiều rộng dialog
// alertDialog.getWindow().setLayout((int)(getResources().getDisplayMetrics().widthPixels * 0.9), ViewGroup.LayoutParams.WRAP_CONTENT);
}
}
Bước 7: Manifest (Manifests/AndroidManifest.xml)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.app.sample">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Chạy ứng dụng
Kết nối thiết bị, nhấn Run. Nhấn nút "Hiển thị Custom Dialog" để thấy dialog tùy chỉnh với icon, tiêu đề, nội dung và nút OK bo tròn.

Mở rộng: Các loại Dialog phổ biến khác
1. BottomSheetDialogFragment (Material Design)
public class MyBottomSheetDialog extends BottomSheetDialogFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.bottom_sheet_layout, container, false);
}
}
// Gọi: new MyBottomSheetDialog().show(getSupportFragmentManager(), "tag");
2. DialogFragment (Quản lý vòng đời tốt hơn)
public class MyDialogFragment extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View view = LayoutInflater.from(getContext()).inflate(R.layout.my_dialog, null);
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(view);
return builder.create();
}
}
3. MaterialAlertDialogBuilder (Material Components)
new MaterialAlertDialogBuilder(this)
.setTitle("Tiêu đề")
.setMessage("Nội dung")
.setPositiveButton("OK", null)
.setNegativeButton("Hủy", null)
.show();
Best Practices
- Luôn dùng
DialogFragmentcho dialog phức tạp để tự động xử lý rotation, lifecycle. - Tránh memory leak: không giữ reference Context/Activity trong dialog lâu dài.
- Sử dụng
ConstraintLayouttrong dialog layout để responsive trên mọi kích thước màn hình. - Accessibility: Đặt
contentDescriptioncho ImageView, dùngandroid:importantForAccessibilityphù hợp.