2011-04-08 12 views
10

Tengo una aplicación de Android que ya está manejando los cambios de orientación, es decir, hay un android:configChanges="orientation" en el manifiesto y un controlador onConfigurationChange() en la actividad que cambia al diseño apropiado y lo prepara. Tengo una versión de paisaje/retrato del diseño.¿Cómo manejo la orientación de la pantalla cuando se abre un cuadro de diálogo?

El problema que tengo es que la actividad tiene un cuadro de diálogo que podría abrirse cuando el usuario gira la orientación del dispositivo. También tengo una versión de paisaje/retrato del diálogo.

¿Debo cambiar el diseño del diálogo sobre la marcha o bloquear la rotación de la actividad hasta que el usuario cierre el diálogo?

La última opción de bloquear la aplicación me atrae ya que ahorra tener que hacer algo especial en el cuadro de diálogo. Estoy suponiendo que podría desactivar la orientación cuando se abre un cuadro de diálogo, como

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); 

y luego, cuando se despide

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); 

Sería eso una cosa sensible a hacer? Si la orientación de la pantalla cambió mientras estaba bloqueada, ¿notaría inmediatamente el cambio de orientación cuando se desbloqueara?

¿Hay alternativas?

+1

Creo que sería una experiencia de usuario extraña si el usuario no puede girar la pantalla cuando se muestra un cuadro de diálogo. – Flo

+0

Posiblemente, pero pronto aprenderían a no hacerlo. Girar mientras tienen el diálogo abierto significa guardar el estado del diálogo, descartar el diálogo, abrirlo nuevamente y poner toda la lógica que estaba en onCreateDialog en onPrepareDialog, y finalmente restaurar el estado. Algo desordenado – locka

+0

Por supuesto que pueden aprenderlo, pero cuando uso una aplicación, quiero que encaje en la experiencia general de Android. Y la experiencia general de las aplicaciones estándar de Android no me impide rotar mi dispositivo cuando quiero. Por supuesto, es más fácil bloquear la rotación, pero a sus usuarios no les importa si es más fácil de implementar, solo les interesa el comportamiento de la aplicación. Solo mis 2 centavos. – Flo

Respuesta

0

Sugiero que su cuadro de diálogo debe anular onSaveInstanceState() y onRestoreInstanceState(Bundle) para guardar su estado en un paquete.

A continuación, anula los métodos en su Actividad, verificando si se muestra el cuadro de diálogo y, de ser así, llamando a los métodos del cuadro de diálogo para guardar y restaurar su estado.

Si está visualizando este diálogo desde un fragmento, querrá anular OnActivityCreated(Bundle) en lugar de OnRestoreInstanceState.

Para ver un ejemplo de fuente, consulte la aplicación de reloj incorporada provista con Android, donde SetAlarm Activity maneja el TimePickerDialog de esta manera.

0

Si está manejando cambios de orientación usted mismo, entonces este es un enfoque.

Yo no pretendo que esta es una solución elegante, pero funciona:

Puede hacer un seguimiento de si el diálogo tiene una instancia activa dentro de la misma clase de diálogo, mediante el uso de un activeInstance variable estática, y anulando onStart() para establecer activeInstance = this y onCancel() para establecer activeInstance = null.

Proporcionar un método estático updateConfigurationForAnyCurrentInstance() que pone a prueba esa variable activeInstance y, si no nulo, invoca un método activeInstance.reInitializeDialog(), que es un método que se va a escribir para contener la llamada setContentView() más el código de que conecta los controladores para los controles de diálogo (botón en los manejadores Click, etc.), este es el código que normalmente aparecería en onCreate()). Después de eso, restauraría cualquier información mostrada a esos controles (de variables miembro en su objeto de diálogo). Entonces, por ejemplo, si tenía una lista de elementos para ser vistos, y el usuario estaba viendo el elemento tres de esa lista antes de que cambie la orientación, volvería a mostrar el mismo elemento tres al final de updateConfigurationForAnyCurrentInstance(), justo después volver a cargar los controles desde el recurso de diálogo y volver a cablear los controladores de control.

A continuación, llamar a ese mismo método reInitializeDialog() desde onCreate(), justo después de super.onCreate(), y colocar su onCreate() - código de inicialización específica (por ejemplo, la creación de la lista de elementos a partir del cual el usuario podría elegir, como se describe arriba) después de esa llamada.

Esto hará que se cargue el recurso apropiado (vertical u horizontal) para la nueva orientación del diálogo (siempre que tenga dos recursos definidos con el mismo nombre, uno en la carpeta de diseño y el otro en la carpeta layout-land , como siempre).

Aquí hay un código que estaría en una clase llamada YourDialog:

ArrayList<String> listOfPossibleChoices = null; 
int currentUserChoice = 0; 

static private YourDialog activeInstance = null; 

@Override 
protected void onStart() { 
    super.onStart(); 
    activeInstance = this; 
} 

@Override 
public void cancel() { 
    super.cancel(); 
    activeInstance = null; 
} 


static public void updateConfigurationForAnyCurrentInstance() { 
    if(activeInstance != null) { 
     activeInstance.reInitializeDialog(); 
     displayCurrentUserChoice(); 
    } 
} 

private void reInitializeDialog() { 
    setContentView(R.layout.your_dialog); 
    btnClose = (Button) findViewById(R.id.btnClose); 
    btnClose.setOnClickListener(this); 
    btnNextChoice = (Button) findViewById(R.id.btnNextChoice); 
    btnNextChoice.setOnClickListener(this); 
    btnPriorChoice = (Button) findViewById(R.id.btnPriorChoice); 
    btnPriorChoice.setOnClickListener(this); 
    tvCurrentChoice = (TextView) findViewById(R.id.tvCurrentChoice); 
} 

private void displayCurrentUserChoice() { 
    tvCurrentChoice.setText(listOfPossibleChoices.get(currentUserChoice)); 
} 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    reInitializeDialog(); 
    listOfPossibleChoices = new ArrayList<String>(); 
    listOfPossibleChoices.add("One"); 
    listOfPossibleChoices.add("Two"); 
    listOfPossibleChoices.add("Three"); 
    currentUserChoice = 0; 
    displayCurrentUserChoice(); 
} 

@Override 
public void onClick(View v) { 
    int viewID = v.getId(); 

    if(viewID == R.id.btnNextChoice) { 
     if(currentUserChoice < (listOfPossibleChoices.size() - 1)) 
     currentUserChoice++; 
     displayCurrentUserChoice(); 
     } 
    } 
    else if(viewID == R.id.btnPriorChoice) { 
     if(currentUserChoice > 0) { 
     currentUserChoice--; 
     displayCurrentUserChoice(); 
     } 
    } 
    Etc. 

Luego, en el método de su actividad onConfigurationChanged(), que acaba de invocar YourDialog.updateConfigurationForAnyCurrentInstance() siempre onConfigurationChanged() es llamado por el sistema operativo.

2

Recomendaría no desactivar la rotación de la pantalla, en lugar de manejar los cambios de configuración para el Diálogo. Se podría utilizar uno de estos dos enfoque para esto:

La primera de ellas es el uso de una variable de la bandera en el método onSaveInstanceState (Outstate), y restaurar el diálogo onCreate (bundle) Método:

en este ejemplo mi variable de indicador se llama 'isShowing Dialog', cuando el sistema android llama al método onCreate por primera vez, el argumento del paquete será nulo y no ocurre nada. Sin embargo, cuando la actividad es recreada por un cambio de configuración (rotación de pantalla), el paquete tendrá el valor booleano mostrando el diálogo, previamente guardado por el método inSaveInstanceState (...), de modo que si la variable se vuelve verdadera, el diálogo se crea nuevamente, El truco aquí es establecer la bandera en verdadero cuando se muestra el diálogo, y falso cuando no lo está, es un truco pequeño pero simple.

Class MyClass extends Activity { 
    Boolean isShowingDialog = false; 
    AlertDialog myDialog; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     if(savedInstanceState!=null){ 
      isShowingDialog = savedInstanceState.getBoolean("IS_SHOWING_DIALOG", false); 
      if(isShowingDialog){ 
       createDialog(); 
      } 
     } 

    } 

    @Override 
    protected void onSaveInstanceState(Bundle outState) { 
     outState.putBoolean("IS_SHOWING_DIALOG", isShowingDialog); 
     super.onSaveInstanceState(outState); 
    } 

    @Override 
    protected void onPause() { 
     if(myDialog!=null && myDialog.isShowing()) { 
      myDialog.dismiss(); 
     } 
    } 

    private void createDialog() { 
     AlertDialog.Builder dialog_builder = new AlertDialog.Builder(this); 
     dialog_builder.setTitle("Some Title"): 
     ... more dialog settings ... 

     myDialog = dialog_builder.create(); 
     myDialog.show(); 
     isShowingDialog = true; 
    } 

    private void hideDialog(){ 
     myDialog.dismiss(); 
     isShowingDialog = false; 
    } 
} 

El segundo enfoque es utilizar la capacidad de los componentes de fragmentos para retener sus estados, la idea principal es crear el diálogo dentro de un fragmento, existe el problema de desconexión y vuelva a colocar el fragmento durante los cambios de configuración (porque necesita descartar y mostrar el diálogo correctamente), pero la solución es muy similar al primer enfoque. La ventaja de este enfoque es que si tiene un AlertDialog con un par de configuraciones, cuando se recrea el fragmento no es necesario crear y configurar el diálogo de nuevo, solo hacer que se muestre() y el estado AlertDialog se mantiene por el fragmento.

Espero que esto ayude.

Cuestiones relacionadas