2011-04-14 24 views
32

Tengo un cuadro de diálogo de alerta con una lista de una opción y dos botones: un botón OK y un botón cancel. El siguiente código muestra cómo lo implementé.¿Cómo seleccionar una entrada en AlertDialog con casilla de verificación de opción única en Android?

private final Dialog createListFile(final String[] fileList) { 
    AlertDialog.Builder builder = new AlertDialog.Builder(this); 
    builder.setTitle("Compare with:"); 

    builder.setSingleChoiceItems(fileList, -1, new DialogInterface.OnClickListener() { 
    public void onClick(DialogInterface dialog, int whichButton) { 
     Log.d(TAG,"The wrong button was tapped: " + fileList[whichButton]); 
    } 
    }); 

    builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { 
    public void onClick(DialogInterface dialog, int whichButton) {} 
    }); 

    builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { 
    public void onClick(DialogInterface dialog, int whichButton) {} 
    }); 

    return builder.create(); 
} 

Mi objetivo es obtener el nombre del botón de opción seleccionado cuando se pulsa el botón OK. Traté de guardar la cadena en una variable, pero dentro de una clase interna es posible acceder solo a las variables finales. ¿Hay alguna forma de evitar el uso de una variable final para almacenar el botón de opción seleccionado?

Respuesta

119

El uso de una variable final obviamente no funcionará (ya que solo se puede asignar una vez, en el momento de la declaración). Las denominadas variables "globales" suelen ser un olor a código (especialmente cuando se vuelven parte de una clase de actividad, que suele ser donde se crean AlertDialogs). La solución más limpia consiste en convertir el objeto DialogInterface en AlertDialog y luego llamar a getListView(). GetCheckedItemPosition(). De esta manera:

new AlertDialog.Builder(this) 
     .setSingleChoiceItems(items, 0, null) 
     .setPositiveButton(R.string.ok_button_label, new DialogInterface.OnClickListener() { 
      public void onClick(DialogInterface dialog, int whichButton) { 
       dialog.dismiss(); 
       int selectedPosition = ((AlertDialog)dialog).getListView().getCheckedItemPosition(); 
       // Do something useful withe the position of the selected radio button 
      } 
     }) 
     .show(); 
+1

Al menos la más útil y googleable;) – Snicolas

+1

¿Qué pasa si quiero recordar lo que se seleccionó y la próxima vez que se abre el cuadro de diálogo, la opción está pre seleccionada? – Si8

+0

@ SiKni8 podría almacenar la posición seleccionada (probablemente como una variable de instancia de la actividad) y luego llamar a getListView(). SetItemChecked() la próxima vez que se abra el cuadro de diálogo. –

8
final CharSequence[] choice = {"Choose from Gallery","Capture a photo"}; 

int from; //This must be declared as global ! 

AlertDialog.Builder alert = new AlertDialog.Builder(activity); 
alert.setTitle("Upload Photo"); 
alert.setSingleChoiceItems(choice, -1, new DialogInterface.OnClickListener() { 
    @Override 
    public void onClick(DialogInterface dialog, int which) { 
     if (choice[which] == "Choose from Gallery") { 
      from = 1; 
     } else if (choice[which] == "Capture a photo") { 
      from = 2; 
     } 
    } 
}); 
alert.setPositiveButton("OK", new DialogInterface.OnClickListener() { 
    @Override 
    public void onClick(DialogInterface dialog, int which) { 
     if (from == 0) { 
      Toast.makeText(activity, "Select One Choice", 
         Toast.LENGTH_SHORT).show(); 
     } else if (from == 1) { 
      // Your Code 
     } else if (from == 2) { 
      // Your Code 
     } 
    } 
}); 
alert.show(); 
+2

variable no es definitiva, no se puede utilizar en la clase interna. – LuckyStarr

+0

simplemente defina final o local (global) .. –

14

Esto ha sido contestada muy bien, pero sigo encontrando esta respuesta de Google y quería compartir una solución de clase no anónimo. Prefiero clases reutilizables y puedo ser útil para otros.

En este ejemplo, estoy usando una implementación de DialogFragment y obtengo un valor a través del método de devolución de llamada .

La devolución de llamada método para obtener valores de un diálogo se puede hacer mediante la creación de una interfaz pública

public interface OnDialogSelectorListener { 
    public void onSelectedOption(int selectedIndex); 
} 

también los implementos DialogFragmentDialogInterface.OnClickListener lo que significa que puede registrar la clase que ha implementado como OnClickListener para el DialogFragment que se está creando.

Por ejemplo

public Dialog onCreateDialog(Bundle savedInstanceState) { 
    final AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity()); 

    builder.setTitle(R.string.select); 
    builder.setSingleChoiceItems(mResourceArray, mSelectedIndex, this); 
    builder.setPositiveButton(R.string.ok, this); 
    builder.setNegativeButton(R.string.cancel, this); 
    return builder.create(); 
} 

La línea

builder.setSingleChoiceItems(mResourceArray, mSelectedIndex, this);

Crea un diálogo elección con las opciones de una matriz recurso almacenada en mResourceArray. Esto también preselecciona un índice de opción de lo que está almacenado en mSelectedIndex y finalmente establece this como el OnClickListener. (Ver código completo al final si este párrafo es un poco confuso)

Ahora, el método OnClick es donde se agarra el valor que viene desde el diálogo

@Override 
public void onClick(DialogInterface dialog, int which) { 

    switch (which) { 
     case Dialog.BUTTON_NEGATIVE: // Cancel button selected, do nothing 
      dialog.cancel(); 
      break; 

     case Dialog.BUTTON_POSITIVE: // OK button selected, send the data back 
      dialog.dismiss(); 
      // message selected value to registered callbacks with the 
        // selected value. 
      mDialogSelectorCallback.onSelectedOption(mSelectedIndex); 
      break; 

     default: // choice item selected 
        // store the new selected value in the static variable 
      mSelectedIndex = which; 
      break; 
    } 
} 

Lo que sucede aquí es cuando una el elemento se selecciona, se almacena en una variable. Si el usuario hace clic en el botón Cancelar Cancelar, no se envía ninguna actualización y no cambia nada.Si el usuario hace clic en el botón Aceptar, devuelve el valor Activity que lo creó a través de la devolución de llamada creada.

Como ejemplo, aquí se muestra cómo crearía el cuadro de diálogo desde FragmentActivity.

final SelectorDialog sd = SelectorDialog.newInstance(R.array.selector_array, preSelectedValue); 
sd.show(getSupportFragmentManager(), TAG); 

En este caso, la matriz de recursos _R.array.selector_array_ es una matriz de cadenas para mostrar en el cuadro de diálogo y preSelectedValue es el índice para seleccionar en abierto.

Finalmente, su FragmentActivity implementará OnDialogSelectorListener y recibirá el mensaje de devolución de llamada.

public class MyActivity extends FragmentActivity implements OnDialogSelectorListener { 
// .... 

    public void onSelectedOption(int selectedIndex) { 
     // do something with the newly selected index 
    } 
} 

Espero que esto sea útil para alguien, ya que me llevó MUCHOS intentos de comprenderlo. Una implementación completa de este tipo de DialogFragment con una devolución de llamada está aquí.

public class SelectorDialog extends DialogFragment implements OnClickListener { 
    static final String TAG = "SelectorDialog"; 

    static int mResourceArray; 
    static int mSelectedIndex; 
    static OnDialogSelectorListener mDialogSelectorCallback; 

    public interface OnDialogSelectorListener { 
     public void onSelectedOption(int dialogId); 
    } 

    public static DialogSelectorDialog newInstance(int res, int selected) { 
     final DialogSelectorDialog dialog = new DialogSelectorDialog(); 
     mResourceArray = res; 
     mSelectedIndex = selected; 

     return dialog; 
    } 

    @Override 
    public void onAttach(Activity activity) { 
     super.onAttach(activity); 

     try { 
      mDialogSelectorCallback = (OnDialogSelectorListener)activity; 
     } catch (final ClassCastException e) { 
      throw new ClassCastException(activity.toString() + " must implement OnDialogSelectorListener"); 
     } 
    } 

    public Dialog onCreateDialog(Bundle savedInstanceState) { 
     final AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity()); 

     builder.setTitle(R.string.select); 
     builder.setSingleChoiceItems(mResourceArray, mSelectedIndex, this); 
     builder.setPositiveButton(R.string.ok, this); 
     builder.setNegativeButton(R.string.cancel, this); 
     return builder.create(); 
    } 

    @Override 
    public void onClick(DialogInterface dialog, int which) { 

     switch (which) { 
      case Dialog.BUTTON_NEGATIVE: 
       dialog.cancel(); 
       break; 

      case Dialog.BUTTON_POSITIVE: 
       dialog.dismiss(); 
       // message selected value to registered calbacks 
       mDialogSelectorCallback.onSelectedOption(mSelectedIndex); 
       break; 

      default: // choice selected click 
       mSelectedIndex = which; 
       break; 
     } 

    } 
} 

Pregunta de un comentario Cómo llamar a esto de un Fragment en lugar de un Activity.

Primero realice algunos cambios en el DialogFragment.

Elimine el evento onAttach ya que esa no es la forma más fácil en este escenario.

Añadir un nuevo método para agregar una referencia a la devolución de llamada

public void setDialogSelectorListener (OnDialogSelectorListener listener) { 
    this.mListener = listener; 
} 

implementar el oyente en su Fragment

public class MyFragment extends Fragment implements SelectorDialog.OnDialogSelectorListener { 
// .... 

    public void onSelectedOption(int selectedIndex) { 
     // do something with the newly selected index 
    } 
} 

Ahora crea una nueva instancia y pasa una referencia a la Fragment utilizar eso.

final SelectorDialog sd = SelectorDialog.newInstance(R.array.selector_array, preSelectedValue); 
// this is a reference to MyFragment 
sd.setDialogSelectorListener(this); 
// mActivity is just a reference to the activity attached to MyFragment 
sd.show(this.mActivity.getSupportFragmentManager(), TAG); 
+0

Gracias por sus explicaciones. ¿Cómo implementaría la devolución de llamada para que se informe un 'Fragmento' en lugar de una 'Actividad' cuando el oyente dispara? – JJD

+2

He agregado una explicación de cómo uso esto en un 'Fragmento' – Kirk

Cuestiones relacionadas