Girar tu dispositivo ya no será un problema
En Android, los dispositivos móviles permiten rotar la pantalla y ofrecer un layout distinto según la orientación. La rotación de la pantalla conlleva tener que restaurar las vistas y campos de nuestras activities. Si queremos implementar la rotación utilizando layouts distintos para cada orientación, debemos seguir los siguientes pasos:- Indicar el comportamiento de una activity ante la rotación de pantalla en el AndroidManifest.xml
- Crear carpetas y layouts para cada orientación.
- Sobrescribir el método onSaveInstanceState() para guardar el valor de los campos de la clase antes de rotar.
- Crear un método para restaurar el valor de los campos tras el giro de la pantalla.
1. Indicar el comportamiento ante la rotación de la pantalla
La orientación de cada pantalla de nuestra aplicación viene definida en el archivo AndroidManifest.xml. En el atributoscreenOrientation podemos definir el modo en que se mostrará la pantalla:
- sin especificar o
unspecified: si no especificamos el atributo o ponemosunspecified, la pantalla girará al girar el dispositivo, pero no se podrá poner en vertical invertida. portrait: solo vertical.landscape: solo horizontal.reversePortrait: solo vertical invertido.reverseLandscape: solo horizontal invertido.fullSensor: la pantalla girará con el dispositivo incluyendo la posición vertical invertida.sensorLandscape: la pantalla girará con el dispositivo pero solo a orientaciones horizontales.sensorPortrait: la pantalla girará con el dispositivo pero solo a orientaciones verticales.locked: la pantalla se mostrará en la orientación en que se encuentre en ese momento el dispositivo y no cambiará al girar.
fullSensor. Existen otros modos además de estos que también permiten girar la pantalla. Puedes verlos aquí: https://developer.android.com/guide/topics/manifest/activity-element.html.
2. Crear carpetas y layouts para cada orientación
Carpetas
Para que Android sepa qué layout debe aplicar para cada orientación, tenemos que crear carpetas con calificadores de orientación. En la carpeta res de nuestra aplicación crearemos una carpeta que se llame layout-land (de landscape) y en ella irán los layouts para la orientación horizontal. Cuando el dispositivo esté en horizontal, Android tomará los layouts de esta carpeta, y si no hay un layout para la pantalla actual, lo tomará de la carpeta layout. Podemos igualmente renombrar la carpeta layout por layout-port para ser más descriptivos, pero no es necesario, ya que solo hay dos orientaciones y, si no es una, es la otra.Layouts
Por cada pantalla en la que queramos implementar la rotación debemos crear un layout horizontal que se llame igual que el de la orientación vertical y asegurarnos de que las vistas comunes a ambos tienen los mismos id para que se restauren automáticamente tras rotar.3. Sobrescribir el método onSaveInstanceState(Bundle outState)
Por defecto, cuando se produce la rotación, la activity se encarga de conservar automáticamente el estado de aquellas vistas en su layout que tengan id (de un CheckBox guarda si está marcado o no, de un EditText guarda su texto…). Para ello guardará pares clave-valor en el bundleoutState del método onSaveInstanceState(Bundle outState) utilizando como clave el id. Y después, restaurará automáticamente el estado de estas vistas en el método onRestoreInstanceState(Bundle savedInstanceState).
Es decir, las vistas se restauran solas. Lo que no se restaura es el valor de los campos de la clase, como por ejemplo el valor de private boolean activado o de private Integer resultado. Estos son los campos que debemos encargarnos de almacenar si nos interesa.
Para ello sobrescribiremos el método onSaveIntanceState(Bundle outState) (no confundir con el onSavedInstanceState()) para añadir al bundle outState donde Android guarda el estado de las vistas todo aquello que deseemos conservar tras la rotación. Este bundle será recibido tanto en el método onCreate(Bundle savedInstanceState) al recrear la activity, como en el método onRestoreInstanceState(Bundle savedInstanceState).
4. ¿Dónde restaurar?
Cuando se produce la rotación de la pantalla, la activity es destruida y creada de nuevo, por lo que tendremos dos ocasiones para restaurar los campos: en elonCreate() y en el onRestoreInstanceState(). Suele convenir hacerlo en el onCreate(), ya que es en este método donde definimos la lógica de las vistas, y tal vez nos interese modificarla según el valor de los campos almacenados.
El método onCreate(Bundle savedInstanceState) recibe un bundle llamado savedInstanceState, que es el mismo que en el que hemos almacenado aquellos valores que queríamos restaurar en el onSavedInstanceState(Bundle outState). Con él ya podemos restaurar los campos de la clase.
Por otro lado, el método onRestoreInstanceState(Bundle saveInstanceState) es el método que automáticamente restaurará el estado de las vistas de nuestro layout que tengan el mismo id que en el layout de la orientación anterior. Este método se ejecuta en algún momento entre el onStart() y onPostCreate(). Es decir, que si decidimos sobrescribirlo y restaurar los campos aquí, debemos tener en cuenta que ya se habrá ejecutado todo el código del onCreate().
5. Ejemplo
En este ejemplo, restauraremos los campos en elonCreate(). En esta clase hemos creado el método restaurarCampos(), al cual hemos de pasarle el savedInstanceState y dentro escribimos la lógica de restauración. Estos son nuestro layout y nuestra MainActivity.
![]() |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent" android:gravity="center"> <EditText android:id="@+id/et_texto" android:layout_width="match_parent" android:layout_height="wrap_content"/> <Button android:id="@+id/btn_boton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Botón"/> <TextView android:id="@+id/tv_texto" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
public class MainActivity extends AppCompatActivity { private static final String PULSADO = "pulsado"; private static final String TEXTO_INTRODUCIDO = "texto"; private EditText etTexto; private Button btnBoton; private TextView tvTexto; private boolean pulsado; private String textoIntroducido; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); etTexto = (EditText) findViewById(R.id.et_texto); btnBoton = (Button) findViewById(R.id.btn_boton); tvTexto = (TextView) findViewById(R.id.tv_texto); restaurarCampos(savedInstanceState); btnBoton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String texto = etTexto.getText().toString(); if (!texto.isEmpty()) { textoIntroducido = etTexto.getText().toString(); pulsado = true; mostrarTextView(); } } }); if (pulsado) { mostrarTextView(); } } public void mostrarTextView(){ tvTexto.setText(textoIntroducido); tvTexto.setVisibility(View.VISIBLE); } private void restaurarCampos(Bundle savedInstanceState){ // Si hay algo en el bundle, es que se ha guardado algo y lo recuperaremos if (savedInstanceState != null) { if (savedInstanceState.getBoolean(PULSADO, false)){ this.pulsado = savedInstanceState.getBoolean(PULSADO); this.textoIntroducido = savedInstanceState.getString(TEXTO_INTRODUCIDO, ""); } } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // Metemos en el bundle lo que queremos conservar if (pulsado){ outState.putBoolean(PULSADO, pulsado); outState.putString(TEXTO_INTRODUCIDO, textoIntroducido); } } } |
pulsado y textoIntroducido (los estáticos no es necesario almacenarlos), por lo que, al girar la pantalla, en el onSavedInstanceState() guardaremos sus valores en el bundle. El segundo parámetro que reciben los métodos get~() de la clase Bundle es el valor que se devolverá en caso de no encontrar el par clave-valor para la clave solicitada.
Luego, la activity será destruida y reconstruida y esto es lo que pasará:
- Se llamará al
onCreate()y dentro de este, al métodosetContentView(), el cual volverá a asignar nuestro layout en su estado primitivo a la activity. Como el TextViewtvTexttiene visibilidadgonepor defecto, este se ocultará sin importar que antes de rotar estuviera visible. - Después se llamará a
restaurarCampos()y, si hemos pulsado el botón, se recuperará el booleanopulsadoy el StringtextoIntroducido. - Por último se ejecutará el resto del método
onCreate(): se comprobará si el valor de pulsado estrue, en cuyo caso, se mostrará el TextView y se le asignará eltextoIntroducido. - Después se llamará automáticamente al
onRestoreSavedInstance()el cual restaurará el contenido anterior del EditTextetTexto.
onCreate(), o de lo contrario, el TextView no se habría vuelto a mostrar con su texto tras la rotación.
| 1. | 2. |
android:freezesText="true" en el layout. Se conservará al rotar incluso por encima del valor primitivo asignado en el layout.









