Gestione della rotazione
Questo argomento descrive come gestire le modifiche dell'orientamento del dispositivo in Xamarin.Android. Illustra come usare il sistema di risorse Android per caricare automaticamente le risorse per un particolare orientamento del dispositivo e come gestire a livello di codice le modifiche dell'orientamento.
Panoramica
Poiché i dispositivi mobili sono facilmente ruotati, la rotazione predefinita è una funzionalità standard nei sistemi operativi mobili. Android offre un framework sofisticato per gestire la rotazione all'interno delle applicazioni, indipendentemente dal fatto che l'interfaccia utente venga creata in modo dichiarativo in XML o a livello di codice. Quando si gestiscono automaticamente le modifiche di layout dichiarativo in un dispositivo ruotato, un'applicazione può trarre vantaggio dalla stretta integrazione con il sistema di risorse Android. Per il layout a livello di codice, le modifiche devono essere gestite manualmente. Ciò consente un controllo più dettagliato in fase di esecuzione, ma a scapito di un maggiore lavoro per lo sviluppatore. Un'applicazione può anche scegliere di rifiutare esplicitamente il riavvio dell'attività e di assumere il controllo manuale delle modifiche di orientamento.
In questa guida vengono esaminati gli argomenti di orientamento seguenti:
Rotazione del layout dichiarativo: come usare il sistema di risorse Android per creare applicazioni con riconoscimento dell'orientamento, tra cui come caricare sia layout che disegnare per determinati orientamenti.
Rotazione layout a livello di codice: come aggiungere controlli a livello di codice e come gestire manualmente le modifiche di orientamento.
Gestione della rotazione in modo dichiarativo con layout
Includendo i file nelle cartelle che seguono le convenzioni di denominazione, Android carica automaticamente i file appropriati quando cambia l'orientamento. È incluso il supporto per:
Risorse layout: specificare i file di layout gonfiati per ogni orientamento.
Risorse disegnabili: specificando quali elementi di disegno vengono caricati per ogni orientamento.
Risorse layout
Per impostazione predefinita, i file XML Android (AXML) inclusi nella cartella Resources/layout vengono usati per il rendering delle visualizzazioni per un'attività. Le risorse di questa cartella vengono usate sia per l'orientamento verticale che orizzontale se non vengono fornite risorse di layout aggiuntive specificamente per il panorama orizzontale. Si consideri la struttura del progetto creata dal modello di progetto predefinito:
Questo progetto crea un singolo file Main.axml nella cartella Resources/layout . Quando viene chiamato il metodo dell'attività OnCreate
, viene gonfiata la visualizzazione definita in Main.axml, che dichiara un pulsante come illustrato nel codice XML seguente:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:id="@+id/myButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"/>
</LinearLayout>
Se il dispositivo viene ruotato sull'orientamento orizzontale, viene chiamato di nuovo il metodo dell'attività OnCreate
e lo stesso file Main.axml viene gonfiato, come illustrato nello screenshot seguente:
Layout specifici dell'orientamento
Oltre alla cartella di layout (che per impostazione predefinita è verticale e può anche essere denominata in modo esplicito layout-port includendo una cartella denominata layout-land
), un'applicazione può definire le visualizzazioni necessarie quando in orizzontale senza modifiche al codice.
Si supponga che il file Main.axml contenga il codice XML seguente:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:text="This is portrait"
android:layout_height="wrap_content"
android:layout_width="fill_parent" />
</RelativeLayout>
Se al progetto viene aggiunta una cartella denominata layout-land che contiene un file Main.axml aggiuntivo, l'aumento del layout quando in orizzontale comporta ora il caricamento di Android del file Main.axml appena aggiunto. Si consideri la versione orizzontale del file Main.axml che contiene il codice seguente (per semplicità, questo codice XML è simile alla versione verticale predefinita del codice, ma usa una stringa diversa in TextView
):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:text="This is landscape"
android:layout_height="wrap_content"
android:layout_width="fill_parent" />
</RelativeLayout>
L'esecuzione di questo codice e la rotazione del dispositivo da verticale a orizzontale illustra il nuovo caricamento XML, come illustrato di seguito:
Risorse disegnabili
Durante la rotazione, Android gestisce risorse disegnabili in modo analogo alle risorse di layout. In questo caso, il sistema ottiene i drawable rispettivamente dalle cartelle Risorse/disegnabili e Risorse/terreni disegnabili.
Si supponga, ad esempio, che il progetto includa un'immagine denominata Monkey.png nella cartella Resources/drawable , in cui viene fatto riferimento all'oggetto drawable da un oggetto ImageView
in FORMATO XML simile al seguente:
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/monkey"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
Si supponga inoltre che una versione diversa di Monkey.png sia inclusa in Risorse/terreno di disegno. Proprio come con i file di layout, quando il dispositivo viene ruotato, le modifiche disegnabili per l'orientamento specificato, come illustrato di seguito:
Gestione della rotazione a livello di codice
A volte definiamo i layout nel codice. Ciò può verificarsi per diversi motivi, tra cui limitazioni tecniche, preferenze per gli sviluppatori e così via. Quando si aggiungono controlli a livello di codice, un'applicazione deve tenere conto manualmente dell'orientamento del dispositivo, che viene gestito automaticamente quando si usano risorse XML.
Aggiunta di controlli nel codice
Per aggiungere controlli a livello di codice, un'applicazione deve eseguire la procedura seguente:
- Creare un layout.
- Impostare i parametri di layout.
- Creare controlli.
- Impostare i parametri del layout del controllo.
- Aggiungere controlli al layout.
- Impostare il layout come visualizzazione contenuto.
Si consideri, ad esempio, un'interfaccia utente costituita da un singolo TextView
controllo aggiunto a un RelativeLayout
oggetto , come illustrato nel codice seguente.
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// create a layout
var rl = new RelativeLayout (this);
// set layout parameters
var layoutParams = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.FillParent);
rl.LayoutParameters = layoutParams;
// create TextView control
var tv = new TextView (this);
// set TextView's LayoutParameters
tv.LayoutParameters = layoutParams;
tv.Text = "Programmatic layout";
// add TextView to the layout
rl.AddView (tv);
// set the layout as the content view
SetContentView (rl);
}
Questo codice crea un'istanza di una RelativeLayout
classe e ne imposta la LayoutParameters
proprietà. La LayoutParams
classe è il modo di incapsulare il modo in cui i controlli vengono posizionati in modo riutilizzabile. Dopo aver creato un'istanza di un layout, i controlli possono essere creati e aggiunti. I controlli hanno LayoutParameters
anche , ad esempio TextView
in questo esempio. Dopo aver creato l'oggetto TextView
, aggiungerlo a RelativeLayout
e impostando RelativeLayout
come risultato della visualizzazione contenuto nell'applicazione viene visualizzato TextView
come illustrato:
Rilevamento dell'orientamento nel codice
Se un'applicazione tenta di caricare un'interfaccia utente diversa per ogni orientamento quando OnCreate
viene chiamato (questo avviene ogni volta che un dispositivo viene ruotato), deve rilevare l'orientamento e quindi caricare il codice dell'interfaccia utente desiderato. Android ha una classe denominata WindowManager
, che può essere usata per determinare la rotazione del dispositivo corrente tramite la WindowManager.DefaultDisplay.Rotation
proprietà , come illustrato di seguito:
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// create a layout
var rl = new RelativeLayout (this);
// set layout parameters
var layoutParams = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.FillParent);
rl.LayoutParameters = layoutParams;
// get the initial orientation
var surfaceOrientation = WindowManager.DefaultDisplay.Rotation;
// create layout based upon orientation
RelativeLayout.LayoutParams tvLayoutParams;
if (surfaceOrientation == SurfaceOrientation.Rotation0 || surfaceOrientation == SurfaceOrientation.Rotation180) {
tvLayoutParams = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
} else {
tvLayoutParams = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
tvLayoutParams.LeftMargin = 100;
tvLayoutParams.TopMargin = 100;
}
// create TextView control
var tv = new TextView (this);
tv.LayoutParameters = tvLayoutParams;
tv.Text = "Programmatic layout";
// add TextView to the layout
rl.AddView (tv);
// set the layout as the content view
SetContentView (rl);
}
Questo codice imposta l'oggetto TextView
da posizionare 100 pixel dall'alto a sinistra dello schermo, animando automaticamente il nuovo layout, quando ruotato in orizzontale, come illustrato di seguito:
Prevenzione del riavvio delle attività
Oltre a gestire tutti gli elementi in OnCreate
, un'applicazione può anche impedire il riavvio di un'attività quando l'orientamento cambia impostando ConfigurationChanges
in ActivityAttribute
come indicato di seguito:
[Activity (Label = "CodeLayoutActivity", ConfigurationChanges=Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)]
Ora, quando il dispositivo viene ruotato, l'attività non viene riavviata. Per gestire manualmente la modifica dell'orientamento in questo caso, un'attività può eseguire l'override del OnConfigurationChanged
metodo e determinare l'orientamento dell'oggetto Configuration
passato, come nella nuova implementazione dell'attività seguente:
[Activity (Label = "CodeLayoutActivity", ConfigurationChanges=Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)]
public class CodeLayoutActivity : Activity
{
TextView _tv;
RelativeLayout.LayoutParams _layoutParamsPortrait;
RelativeLayout.LayoutParams _layoutParamsLandscape;
protected override void OnCreate (Bundle bundle)
{
// create a layout
// set layout parameters
// get the initial orientation
// create portrait and landscape layout for the TextView
_layoutParamsPortrait = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
_layoutParamsLandscape = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
_layoutParamsLandscape.LeftMargin = 100;
_layoutParamsLandscape.TopMargin = 100;
_tv = new TextView (this);
if (surfaceOrientation == SurfaceOrientation.Rotation0 || surfaceOrientation == SurfaceOrientation.Rotation180) {
_tv.LayoutParameters = _layoutParamsPortrait;
} else {
_tv.LayoutParameters = _layoutParamsLandscape;
}
_tv.Text = "Programmatic layout";
rl.AddView (_tv);
SetContentView (rl);
}
public override void OnConfigurationChanged (Android.Content.Res.Configuration newConfig)
{
base.OnConfigurationChanged (newConfig);
if (newConfig.Orientation == Android.Content.Res.Orientation.Portrait) {
_tv.LayoutParameters = _layoutParamsPortrait;
_tv.Text = "Changed to portrait";
} else if (newConfig.Orientation == Android.Content.Res.Orientation.Landscape) {
_tv.LayoutParameters = _layoutParamsLandscape;
_tv.Text = "Changed to landscape";
}
}
}
Qui i parametri di layout vengono inizializzati sia per orizzontale TextView's
che per verticale. Le variabili di classe contengono i parametri, insieme a TextView
se stessa, perché l'attività non verrà ricreata quando cambia l'orientamento. Il codice usa ancora in surfaceOrientartion
OnCreate
per impostare il layout iniziale per .TextView
Successivamente, OnConfigurationChanged
gestisce tutte le modifiche di layout successive.
Quando si esegue l'applicazione, Android carica le modifiche dell'interfaccia utente man mano che si verifica la rotazione del dispositivo e non riavvia l'attività.
Prevenzione del riavvio delle attività per layout dichiarativi
I riavvii dell'attività causati dalla rotazione del dispositivo possono essere impediti anche se definiamo il layout in XML. Ad esempio, è possibile usare questo approccio se si vuole impedire un riavvio dell'attività (per motivi di prestazioni, ad esempio) e non è necessario caricare nuove risorse per orientamenti diversi.
A tale scopo, si segue la stessa procedura usata con un layout a livello di codice. È sufficiente impostare ConfigurationChanges
in ActivityAttribute
, come abbiamo fatto in CodeLayoutActivity
precedenza. Qualsiasi codice che deve essere eseguito per la modifica dell'orientamento può essere nuovamente implementato nel OnConfigurationChanged
metodo .
Mantenimento dello stato durante le modifiche all'orientamento
Indipendentemente dalla gestione della rotazione in modo dichiarativo o programmatico, tutte le applicazioni Android devono implementare le stesse tecniche per la gestione dello stato quando cambia l'orientamento del dispositivo. La gestione dello stato è importante perché il sistema riavvia un'attività in esecuzione quando un dispositivo Android viene ruotato. Android esegue questa operazione per semplificare il caricamento di risorse alternative, ad esempio layout e drawable progettati appositamente per un particolare orientamento. Al riavvio, l'attività perde qualsiasi stato temporaneo archiviato nelle variabili di classe locale. Pertanto, se un'attività è conforme allo stato, deve mantenere lo stato a livello di applicazione. Un'applicazione deve gestire il salvataggio e il ripristino di qualsiasi stato dell'applicazione che vuole mantenere tra le modifiche di orientamento.
Per altre informazioni sulla persistenza dello stato in Android, vedere la Guida al ciclo di vita dell'attività.
Riepilogo
Questo articolo ha illustrato come usare le funzionalità predefinite di Android per lavorare con la rotazione. In primo luogo, è stato spiegato come usare il sistema di risorse Android per creare applicazioni con riconoscimento dell'orientamento. Quindi ha illustrato come aggiungere controlli nel codice e come gestire manualmente le modifiche di orientamento.