防止单击button时DialogFragment解散

我有一个自定义视图的DialogFragment,其中包含两个文本字段,用户将input他们的用户名和密码。 当单击肯定button时,我想validation用户在解除对话之前实际上是否input了某些内容。

public class AuthenticationDialog extends DialogFragment { public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); LayoutInflater inflater = getActivity().getLayoutInflater(); builder.setView(inflater.inflate(R.layout.authentication_dialog, null)) .setPositiveButton(getResources().getString(R.string.login), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO } }) .setNegativeButton(getResources().getString(R.string.reset), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO } }); return builder.create(); } } 

那么我怎样才能防止对话被解雇呢? 有什么方法我应该重写?

覆盖OnStart()中的默认button处理程序来执行此操作。

 @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(); } @Override public void onStart() { super.onStart(); //super.onStart() is where dialog.show() is actually called on the underlying dialog, so we have to do it after this point 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) dismiss(); //else dialog stays open. Make sure you have an obvious way to close the dialog especially if you set cancellable to false. } }); } } 

有关其他对话框types的更多解释和示例,请参阅我的答案https://stackoverflow.com/a/15619098/579234

感谢Luksprog,我find了一个解决scheme。

AuthenticationDialog.java

 public class AuthenticationDialog extends DialogFragment implements OnClickListener { public interface AuthenticationDialogListener { void onAuthenticationLoginClicked(String username, String password); void onAuthenticationResetClicked(String username); } private AuthenticationDialogListener mListener; private EditText mUsername; private EditText mPassword; private Button mReset; private Button mLogin; public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.authentication_dialog, container); this.getDialog().setTitle(R.string.login_title); mUsername = (EditText) view.findViewById(R.id.username_field); mPassword = (EditText) view.findViewById(R.id.password_field); mReset = (Button) view.findViewById(R.id.reset_button); mLogin = (Button) view.findViewById(R.id.login_button); mReset.setOnClickListener(this); mLogin.setOnClickListener(this); return view; } public void onAttach(Activity activity) { super.onAttach(activity); // Verify that the host activity implements the callback interface try { // Instantiate the NoticeDialogListener so we can send events to the host mListener = (AuthenticationDialogListener) activity; } catch (ClassCastException e) { // The activity doesn't implement the interface, throw exception throw new ClassCastException(activity.toString() + " must implement AuthenticationDialogListener"); } } public void onClick(View v) { if (v.equals(mLogin)) { if (mUsername.getText().toString().length() < 1 || !mUsername.getText().toString().contains("@")) { Toast.makeText(getActivity(), R.string.invalid_email, Toast.LENGTH_SHORT).show(); return; } else if (mPassword.getText().toString().length() < 1) { Toast.makeText(getActivity(), R.string.invalid_password, Toast.LENGTH_SHORT).show(); return; } else { mListener.onAuthenticationLoginClicked(mUsername.getText().toString(), mPassword.getText().toString()); this.dismiss(); } } else if (v.equals(mReset)) { mListener.onAuthenticationResetClicked(mUsername.getText().toString()); } } } 

authentication_dialog.xml

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <EditText android:id="@+id/username_field" android:inputType="textEmailAddress" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_marginLeft="4dp" android:layout_marginRight="4dp" android:layout_marginBottom="4dp" android:hint="@string/username" /> <EditText android:id="@+id/password_field" android:inputType="textPassword" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="4dp" android:layout_marginLeft="4dp" android:layout_marginRight="4dp" android:layout_marginBottom="12dp" android:fontFamily="sans-serif" android:hint="@string/password" /> <View android:layout_width="fill_parent" android:layout_height="1dip" android:background="?android:attr/dividerVertical" /> <LinearLayout style="?android:attr/buttonBarStyle" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:paddingTop="0dp" android:measureWithLargestChild="true" > <Button android:id="@+id/reset_button" style="?android:attr/buttonBarButtonStyle" android:layout_height="wrap_content" android:layout_width="0dp" android:layout_weight="1.0" android:text="@string/reset" /> <Button android:id="@+id/login_button" style="?android:attr/buttonBarButtonStyle" android:layout_height="wrap_content" android:layout_width="0dp" android:layout_weight="1.0" android:text="@string/login" /> </LinearLayout> </LinearLayout> 

这是Karakuri和Sogger的答案的“甜点”解决scheme。 Karakuri是在正确的轨道上,但是如果已经显示,你只能按这样的方式获得button(否则为空,如评论中所述)。 这就是为什么Sogger的答案有效,但我更喜欢在onCreateDialog相同的方法,而不是onStart 。 解决方法是将button的提取包装到对话框的OnShowListener中。

 public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); // your dialog setup, just leave the OnClick-listeners empty here and use the ones below final AlertDialog dialog = builder.create(); dialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override public void onShow(final DialogInterface dialog) { Button positiveButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE); positiveButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View v) { // TODO - call 'dismiss()' only if you need it } }); Button negativeButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_NEGATIVE); // same for negative (and/or neutral) button if required } }); return dialog; } 

你可以再次popup对话框。 或者,您可以保持禁用正面button,直到在两个字段中都有input。 如果您在onCreateVew()中创build布局,这很容易。 如果您使用AlertDialog.Builder类,则可以像这样获取button的句柄:

 AlertDialog.Builder builder = new AlertDialog.Builder(context); /* ... */ Dialog dialog = builder.create(); Button positiveButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE); /* now you can affect the button */