agarrando
Tengo un DialogFragment con una vista personalizada que contiene dos campos de texto donde el usuario debe ingresar su nombre de usuario y contraseña. Cuando se hace clic en el botón positivo, quiero validar que el usuario realmente ingresó algo antes de cerrar el cuadro de diálogo.
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();
}
}
Entonces, ¿cómo puedo evitar que se cierre el cuadro de diálogo? ¿Hay algún método que deba anular?
empapado
Anule los controladores de botones predeterminados en OnStart() para hacer esto.
@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.
}
});
}
}
Vea mi respuesta aquí https://stackoverflow.com/a/15619098/579234 para obtener más explicaciones y ejemplos sobre otros tipos de diálogo también.
-
Esto no funciona para mí.
d.getButton(Dialog.BUTTON_POSITIVE)
devuelve nulo.–Travis cristiano
18 de abril de 2013 a las 18:04
-
@Travis Christian Debes apuntar a una versión anterior de Android. También me encontré con esto antes, actualicé mi respuesta para que ahora funcione en versiones anteriores. Debe pasar un oyente de clic en blanco a la primera llamada.
– Sogger
19 de abril de 2013 a las 15:46
-
Interesante, gracias. Estoy apuntando a 15, así que esto debe haber sido un cambio reciente.
–Travis cristiano
19/04/2013 a las 19:38
-
Supongo que solo asumo que era un problema con el antiguo frente al nuevo, ya que estaba funcionando en un teléfono más nuevo (creo que ICS), pero tenía un teléfono Gigngerbread antiguo en el que no funcionaba sin definir el oyente en blanco. De todos modos, desde que se agregó el oyente en blanco, ha estado funcionando en ambos.
– Sogger
22 de abril de 2013 a las 16:29
-
Ayudó, 10x. Pero muy raro. ¿No es un error?
– trucobz
7 de enero de 2015 a las 2:36
Luz negra
Esta es la solución de “punto dulce” de las respuestas de Karakuri y Sogger. Karakuri estaba en el camino correcto, sin embargo, solo puede obtener el botón de esa manera si ya se muestra (de lo contrario, es nulo, como se indica en los comentarios). Es por eso que la respuesta de Sogger funciona, sin embargo, prefiero la configuración con el mismo método, que es onCreateDialog
y no adicionalmente en onStart
. La solución es envolver la obtención de los botones en el OnShowListener
del diálogo.
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;
}
-
Pido disculpas por el voto negativo, pero este método no activó el nuevo onClick definido en setOnShowListener para mí (probado en Lollipop). ¿Has probado esto?
– Abraham Felipe
05/08/2015 a las 22:30
-
Por supuesto, probé y usé esto varias veces, y obviamente funcionó no solo para mí. Antes de rechazar una respuesta de hace meses, tal vez debería pensar en el hecho de que esto se publicó mucho antes de que se lanzara Lollipop …
– Luz negra
6 de agosto de 2015 a las 5:22
-
Mmm. punto interesante Habiendo echado un vistazo a meta.stackoverflow.com/q/265749/3000919 y meta.stackoverflow.com/q/265749/3000919, el consenso parece ser que, idealmente, tales respuestas deberían editarse teniendo en cuenta su naturaleza obsoleta, pero dejarlas intactas. para el soporte del sistema heredado. Sin embargo, en este caso, la utilidad de esta respuesta como solución “heredada” no está clara, ya que la respuesta más votada funciona en todas las versiones (a partir de ahora). Si agregó un descargo de responsabilidad en la parte superior que dice que esto no funciona en versiones posteriores de Android, me complacería eliminar mi voto negativo, para no negarlo (continuación)
– Abraham Felipe
8 de agosto de 2015 a las 6:56
-
(continuación del comentario anterior) el reconocimiento que merecía por proporcionar una respuesta que funcionó en ese momento. Además, parece que he publicado el mismo enlace dos veces en mi comentario anterior. Esta es la pregunta a la que me refería: meta.stackexchange.com/q/11705
– Abraham Felipe
8 de agosto de 2015 a las 7:02
-
@AbrahamPhilip Para poder verificar o editar mi respuesta, configuré un proyecto de prueba únicamente para este propósito. Mi solución aún funciona y esta respuesta sigue siendo válida, incluso en el SDK más reciente (API nivel 22). Verifique su solución, porque aparentemente está haciendo algo mal.
– Luz negra
10 de agosto de 2015 a las 11:22
Gracias a Luksprog, pude encontrar una solución.
AutenticaciónDialog.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());
}
}
}
autenticación_diálogo.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>
Podrías simplemente abrir el cuadro de diálogo de nuevo. O bien, puede mantener el botón positivo deshabilitado hasta que haya una entrada en ambos campos. Esto es bastante fácil si está creando el diseño en onCreateVew()
. Si está utilizando el AlertDialog.Builder
clase en su lugar, puede obtener un identificador para el botón de la siguiente manera:
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 */
¿Cómo puedo evitar que se cierre el cuadro de diálogo? – no utilice el valor predeterminado del cuadro de diálogo
Buttons
(el que te pones consetPositiveButton
etc). Establece tu propioButtons
para descartar el diálogo e implementar la lógica deseada en suOnClickListeners
. Deberías publicar el código de tuDialogFragment
.– usuario
6 de diciembre de 2012 a las 15:29
@Luksprog Código publicado. Cuando probé lo que sugirió, obtener referencias a los elementos de mi vista personalizada desde dentro de onCreateDialog siempre devuelve nulo.
– Groppe
6 de diciembre de 2012 a las 18:25
En ese momento, el diálogo no se representa en la pantalla. En su lugar, intente inflar el diseño
R.layout.authentication_dialog
en unView
referencia y luego busque elButtons
:View v = inflater.inflate(R.layout.authentication_dialog); Button b = (Button) v.findviewById(R.id.the_btn_id);
.– usuario
6 de diciembre de 2012 a las 18:36
@Luksprog Según lo que sugirió, encontré una solución. Voy a publicar mi código en una respuesta, pero si desea publicar una respuesta y hacer referencia a la mía, le daré la respuesta correcta.
– Groppe
6 de diciembre de 2012 a las 19:30
¿El código del comentario anterior no funcionó?
– usuario
6 de diciembre de 2012 a las 19:44