AlertDialog với Custom View (Layout tùy chỉnh)
Sử dụng AlertDialog.Builder.setView(View) để hiển thị layout tùy chỉnh hoàn toàn trong dialog (form nhập liệu, layout phức tạp, v.v.).
Bước 1: Tạo dự án mới
Khởi tạo project Android Studio.
Bước 2: Layout chính (res/layout/activity_main.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="match_parent"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/click"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click to show custom dialog"
android:textSize="24sp"
android:padding="24dp" />
</LinearLayout>
Bước 3: Custom Dialog Layout (res/layout/custom.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="24dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập tên của bạn"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="16dp" />
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Tên..."
android:inputType="textPersonName"
android:padding="12dp"
android:background="@android:drawable/editbox_background" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="16dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Tuổi: "
android:gravity="center_vertical"
android:paddingEnd="8dp" />
<EditText
android:id="@+id/editAge"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Tuổi"
android:inputType="number"
android:padding="12dp" />
</LinearLayout>
</LinearLayout>
Bước 4: MainActivity.java
package com.example.myapplication;
import android.annotation.TargetApi;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private TextView text;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = findViewById(R.id.click);
text.setOnClickListener(v -> showAlertDialog());
}
private void showAlertDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
// Inflate custom layout
final View customLayout = getLayoutInflater().inflate(R.layout.custom, null);
builder.setView(customLayout);
// Nút xác nhận - lấy dữ liệu từ custom view
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
EditText editText = customLayout.findViewById(R.id.editText);
EditText editAge = customLayout.findViewById(R.id.editAge);
String name = editText.getText().toString().trim();
String ageStr = editAge.getText().toString().trim();
if (name.isEmpty()) {
Toast.makeText(MainActivity.this, "Vui lòng nhập tên", Toast.LENGTH_SHORT).show();
return;
}
String message = "Tên: " + name;
if (!ageStr.isEmpty()) {
message += ", Tuổi: " + ageStr;
}
Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
}
});
builder.setNegativeButton("Hủy", (dialog, which) -> dialog.dismiss());
AlertDialog dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
}
Quan trọng: Truy xuất View từ Custom Layout
- Phải giữ reference đến
customLayout(final hoặc field) - Dùng
customLayout.findViewById()- KHÔNG dùngfindViewById()của Activity - Lấy dữ liệu trong callback
setPositiveButtonhoặcsetNeutralButton
Custom Dialog hoàn toàn (Không dùng AlertDialog.Builder)
// Tùy chỉnh hoàn toàn: không title, không button mặc định, animation riêng
Dialog dialog = new Dialog(this, R.style.CustomDialogTheme);
dialog.setContentView(R.layout.custom_dialog_full);
dialog.setCancelable(true);
dialog.setCanceledOnTouchOutside(true);
// Tự xử lý button trong layout
Button btnOk = dialog.findViewById(R.id.btnOk);
Button btnCancel = dialog.findViewById(R.id.btnCancel);
btnOk.setOnClickListener(v -> { /* logic */ dialog.dismiss(); });
btnCancel.setOnClickListener(v -> dialog.dismiss());
dialog.show();
Style cho Custom Dialog (res/values/styles.xml)
<style name="CustomDialogTheme" parent="Theme.AppCompat.Light.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowMinWidthMajor">90%</item>
<item name="android:windowMinWidthMinor">90%</item>
</style>
Bottom Sheet Dialog (Material Design)
// Cần dependency: implementation 'com.google.android.material:material:1.4.0+' import com.google.android.material.bottomsheet.BottomSheetDialog; BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(this); View bottomSheetView = getLayoutInflater().inflate(R.layout.bottom_sheet_layout, null); bottomSheetDialog.setContentView(bottomSheetView); bottomSheetDialog.show();
So sánh các loại Dialog
| Loại | API | Ưu điểm | Nhược điểm |
|---|---|---|---|
| AlertDialog + setView | Builder.setView() | Đơn giản, có sẵn button, title | Giới hạn tùy chỉnh UI chrome |
| Dialog tùy chỉnh | new Dialog() | Hoàn toàn kiểm soát UI | Phải tự xử lý mọi thứ |
| BottomSheetDialog | Material Components | Modern UX, swipe dismiss, drag handle | Yêu cầu Material Components lib |
| DialogFragment | FragmentManager | Phức tạp hơn |
Best Practices
- Luôn dùng
DialogFragmentcho dialog phức tạp (xử lý rotation, lifecycle) - Validate input trước khi dismiss
- Dùng
TextInputLayout(Material) cho EditText trong dialog - Cân nhắc
BottomSheetDialogcho UX hiện đại