Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Cách triển khai Custom AlertDialog View trong Android

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.

Cách triển khai Custom AlertDialog View trong Android

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 DialogFragment cho 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 ConstraintLayout trong dialog layout để responsive trên mọi kích thước màn hình.
  • Accessibility: Đặt contentDescription cho ImageView, dùng android:importantForAccessibility phù hợp.