web-dev-qa-db-fra.com

Empêcher DialogFragment de se fermer lorsque vous cliquez sur le bouton

J'ai un DialogFragment avec une vue personnalisée qui contient deux champs de texte où l'utilisateur doit entrer son nom d'utilisateur et son mot de passe. Lorsque le bouton positif est cliqué, je veux valider que l'utilisateur a effectivement entré quelque chose avant de fermer la boîte de dialogue.

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();
    }
}

Alors, comment puis-je empêcher la boîte de dialogue de se fermer? Y a-t-il une méthode que je devrais remplacer?

39
Groppe

Grâce à Luksprog, j'ai pu trouver une solution.

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>
5
Groppe

Remplacez les gestionnaires de boutons par défaut dans OnStart () pour ce faire.

@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.
                    }
                });
    }
}

Voir ma réponse ici https://stackoverflow.com/a/15619098/579234 pour plus d'explications et d'exemples sur d'autres types de dialogues aussi.

64
Sogger

C'est la solution "sweetspot" des réponses de Karakuri et de Sogger. Karakuri était sur la bonne voie, mais vous ne pouvez obtenir le bouton de cette façon que s'il est déjà affiché (il est nul sinon, comme indiqué dans les commentaires). C'est pourquoi la réponse de Sogger fonctionne, mais je préfère la configuration dans la même méthode, qui est onCreateDialog, et pas en plus dans onStart. La solution consiste à encapsuler la récupération des boutons dans le OnShowListener de la boîte de dialogue.

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;
}
6
Blacklight