Dưới đây là một số giải pháp cho tất cả các loại hộp thoại, bao gồm giải pháp cho AlertDialog.Builder sẽ hoạt động trên tất cả các cấp API (hoạt động bên dưới API 8, mà câu trả lời khác ở đây không có). Có các giải pháp cho AlertDialogs bằng AlertDialog.Builder, DialogFragment và DialogPreference.
Dưới đây là các ví dụ mã cho thấy cách ghi đè trình xử lý nút chung mặc định và ngăn hộp thoại đóng cho các dạng hộp thoại khác nhau này. Tất cả các ví dụ cho thấy làm thế nào để ngăn nút tích cực đóng hộp thoại.
Lưu ý: Mô tả về cách đóng hộp thoại hoạt động dưới mui xe cho các lớp Android cơ sở và lý do các cách tiếp cận sau được chọn sau các ví dụ, cho những ai muốn biết thêm chi tiết
AlertDialog.Builder - Thay đổi trình xử lý nút mặc định ngay sau khi hiển thị ()
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Test for preventing dialog close");
builder.setPositiveButton("Test",
new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
//Do nothing here because we override this button later to change the close behaviour.
//However, we still need this because on older versions of Android unless we
//pass a handler the button doesn't get instantiated
}
});
final AlertDialog dialog = builder.create();
dialog.show();
//Overriding the handler immediately after show is probably a better approach than OnShowListener as described below
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Boolean wantToCloseDialog = false;
//Do stuff, possibly set wantToCloseDialog to true then...
if(wantToCloseDialog)
dialog.dismiss();
//else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
}
});
DialogFragment - ghi đè onResume ()
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Test for preventing dialog close");
builder.setPositiveButton("Test",
new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
//Do nothing here because we override this button later to change the close behaviour.
//However, we still need this because on older versions of Android unless we
//pass a handler the button doesn't get instantiated
}
});
return builder.create();
}
//onStart() is where dialog.show() is actually called on
//the underlying dialog, so we have to do it there or
//later in the lifecycle.
//Doing it in onResume() makes sure that even if there is a config change
//environment that skips onStart then the dialog will still be functioning
//properly after a rotation.
@Override
public void onResume()
{
super.onResume();
final AlertDialog d = (AlertDialog)getDialog();
if(d != null)
{
Button positiveButton = (Button) d.getButton(Dialog.BUTTON_POSITIVE);
positiveButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Boolean wantToCloseDialog = false;
//Do stuff, possibly set wantToCloseDialog to true then...
if(wantToCloseDialog)
d.dismiss();
//else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
}
});
}
}
DialogPreference - ghi đè showDialog ()
@Override
protected void onPrepareDialogBuilder(Builder builder)
{
super.onPrepareDialogBuilder(builder);
builder.setPositiveButton("Test", this); //Set the button here so it gets created
}
@Override
protected void showDialog(Bundle state)
{
super.showDialog(state); //Call show on default first so we can override the handlers
final AlertDialog d = (AlertDialog) getDialog();
d.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Boolean wantToCloseDialog = false;
//Do stuff, possibly set wantToCloseDialog to true then...
if(wantToCloseDialog)
d.dismiss();
//else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false.
}
});
}
Giải thích về các phương pháp:
Nhìn qua mã nguồn Android, triển khai mặc định AlertDialog hoạt động bằng cách đăng ký trình xử lý nút chung cho tất cả các nút thực tế trong OnCreate (). Khi một nút được bấm, trình xử lý nút chung sẽ chuyển tiếp sự kiện nhấp tới bất kỳ trình xử lý nào bạn đã truyền trong setButton () sau đó gọi bỏ qua hộp thoại.
Nếu bạn muốn ngăn hộp thoại đóng lại khi nhấn một trong các nút này, bạn phải thay thế trình xử lý nút chung để xem thực tế của nút. Vì nó được gán trong OnCreate (), bạn phải thay thế nó sau khi triển khai OnCreate () mặc định được gọi. OnCreate được gọi trong quá trình của phương thức show (). Bạn có thể tạo một lớp Hộp thoại tùy chỉnh và ghi đè OnCreate () để gọi super.OnCreate () sau đó ghi đè trình xử lý nút, nhưng nếu bạn tạo một hộp thoại tùy chỉnh, bạn sẽ không nhận được Builder miễn phí, trong trường hợp đó là điểm nào ?
Vì vậy, khi sử dụng hộp thoại theo cách nó được thiết kế nhưng với việc kiểm soát khi nó bị loại bỏ, trước tiên, một cách tiếp cận là gọi hộp thoại.Show (), sau đó lấy tham chiếu đến nút bằng hộp thoại.getButton () để ghi đè trình xử lý nhấp chuột. Một cách tiếp cận khác là sử dụng setOnShowListener () và thực hiện tìm chế độ xem nút và thay thế trình xử lý trong OnShowListener. Sự khác biệt về chức năng giữa hai loại này là "gần như", tùy thuộc vào luồng nào ban đầu tạo ra thể hiện hộp thoại. Nhìn qua mã nguồn, onShowListener được gọi bởi một thông báo được gửi đến một trình xử lý chạy trên luồng đã tạo ra hộp thoại đó. Vì vậy, vì OnShowListener của bạn được gọi bởi một thông báo được đăng trên hàng đợi tin nhắn, về mặt kỹ thuật có thể việc gọi trình nghe của bạn bị trì hoãn một thời gian sau khi chương trình hoàn tất.
Do đó, tôi tin rằng cách tiếp cận an toàn nhất là cách đầu tiên: gọi show.Dialog (), sau đó ngay lập tức trong cùng một đường dẫn thực hiện thay thế các trình xử lý nút. Vì mã của bạn gọi show () sẽ hoạt động trên luồng GUI chính, điều đó có nghĩa là bất kỳ mã nào bạn theo dõi show () sẽ được thực thi trước bất kỳ mã nào khác trên luồng đó, trong khi thời gian của phương thức OnShowListener không được chấp nhận hàng đợi tin nhắn.