Zpracování otáčení
Toto téma popisuje, jak zpracovávat změny orientace zařízení v Xamarin.Androidu. Popisuje, jak pracovat se systémem prostředků Androidu, aby automaticky načítá prostředky pro konkrétní orientaci zařízení a jak programově zpracovávat změny orientace.
Přehled
Vzhledem k tomu, že se mobilní zařízení snadno otočí, je integrovaná obměna standardní funkcí mobilních operačních systému. Android poskytuje sofistikovanou architekturu pro práci s obměnou aplikací bez ohledu na to, jestli se uživatelské rozhraní vytváří deklarativní v jazyce XML nebo programově v kódu. Při automatickém zpracování deklarativních změn rozložení na otočeném zařízení může aplikace těžit z těsné integrace se systémem prostředků Android. U programového rozložení je nutné změny zpracovat ručně. To umožňuje jemněji řídit za běhu, ale za cenu větší práce pro vývojáře. Aplikace se také může rozhodnout odhlásit se z restartování aktivity a převzít ruční kontrolu nad změnami orientace.
Tato příručka zkoumá následující témata orientace:
Deklarativní obměna rozložení – Jak používat systém prostředků Androidu k vytváření aplikací pracujících s orientací, včetně toho, jak načíst rozložení a kreslitelné pro konkrétní orientace.
Otočení rozložení programu – Jak přidat ovládací prvky prostřednictvím kódu programu a jak zpracovat změny orientace ručně.
Deklarativní zpracování obměny pomocí rozložení
Zahrnutím souborů do složek, které dodržují zásady vytváření názvů, Android automaticky načte příslušné soubory při změně orientace. Zahrnuje podporu pro tyto možnosti:
Zdroje rozložení – Určení, které soubory rozložení jsou pro každou orientaci nafoukané.
Nakreslitelné zdroje – Určení, které nakreslitelné položky jsou načteny pro každou orientaci.
Prostředky rozložení
Ve výchozím nastavení se soubory Android XML (AXML) obsažené ve složce Resources/layout používají k vykreslování zobrazení pro aktivitu. Prostředky této složky se používají pro orientaci na výšku i na šířku, pokud nejsou k dispozici žádné další prostředky rozložení speciálně pro orientaci na šířku. Představte si strukturu projektu vytvořenou výchozí šablonou projektu:
Tento projekt vytvoří jeden soubor Main.axml ve složce Resources/layout . Když je volána metoda Aktivity OnCreate
, nafoukne zobrazení definované v Main.axml, které deklaruje tlačítko, jak je znázorněno v xml níže:
<?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>
Pokud se zařízení otočí na orientaci na šířku, metoda aktivity OnCreate
se znovu zavolá a stejný soubor Main.axml se nafoukne, jak je znázorněno na následujícím snímku obrazovky:
Rozložení specifická pro orientaci
Kromě složky rozložení (která má výchozí hodnotu na výšku a dá se také explicitně pojmenovat port rozložení zahrnutím složky s názvem layout-land
), může aplikace definovat zobrazení, která potřebuje, když je na šířku bez jakýchkoli změn kódu.
Předpokládejme, že soubor Main.axml obsahoval následující kód XML:
<?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>
Pokud je do projektu přidána složka s názvem layout-land, která obsahuje další soubor Main.axml , nafouknutí rozložení v případě, že je na šířku, způsobí načtení nově přidaného souboru Main.axml pro Android. Představte si verzi souboru Main.axml na šířku, která obsahuje následující kód (pro zjednodušení se tento KÓD podobá výchozí verzi kódu na výšku, ale používá jiný řetězec v tomto TextView
kódu):
<?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>
Spuštění tohoto kódu a otočení zařízení na výšku na šířku ukazuje nové načítání XML, jak je znázorněno níže:
Nakreslitelné zdroje
Během obměny android zachází s kreslenými prostředky podobně jako s prostředky rozložení. V tomto případě systém získá nakreslené zdroje ze složek Zdroje/kreslení a Zdroje/kreslení-země , v uvedeném pořadí.
Řekněme například, že projekt obsahuje obrázek s názvem Monkey.png ve složce Resources/drawable , kde se na kreslení odkazuje z xml ImageView
takto:
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/monkey"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
Dále předpokládejme, že v části Zdroje/nakreslitelná země je zahrnuta jiná verze Monkey.png. Stejně jako u souborů rozložení se při otočení zařízení změní nakreslený pro danou orientaci, jak je znázorněno níže:
Zpracování obměně prostřednictvím kódu programu
Někdy definujeme rozložení v kódu. K tomu může dojít z různých důvodů, včetně technických omezení, preferencí vývojářů atd. Když přidáme ovládací prvky programově, musí aplikace ručně počítat s orientací zařízení, která se zpracovává automaticky při použití prostředků XML.
Přidání ovládacích prvků v kódu
Pokud chcete přidat ovládací prvky prostřednictvím kódu programu, musí aplikace provést následující kroky:
- Vytvořte rozložení.
- Nastavte parametry rozložení.
- Vytváření ovládacích prvků
- Nastavte parametry rozložení ovládacího prvku.
- Přidejte do rozložení ovládací prvky.
- Nastavte rozložení jako zobrazení obsahu.
Představte si například uživatelské rozhraní, které se skládá z jednoho TextView
ovládacího prvku přidaného do objektu RelativeLayout
, jak je znázorněno v následujícím kódu.
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);
}
Tento kód vytvoří instanci RelativeLayout
třídy a nastaví její LayoutParameters
vlastnost. Třída LayoutParams
je způsob zapouzdření způsobu umístění ovládacích prvků opakovaně použitelným způsobem. Jakmile se vytvoří instance rozložení, lze do ní vytvořit a přidat ovládací prvky. Ovládací prvky mají LayoutParameters
také například v tomto příkladu TextView
. Po vytvoření ho TextView
přidáte do RelativeLayout
a nastavíte RelativeLayout
jako výsledek zobrazení obsahu v aplikaci, která TextView
zobrazí, jak je znázorněno:
Detekce orientace v kódu
Pokud se aplikace pokusí načíst jiné uživatelské rozhraní pro každou orientaci při OnCreate
zavolání (k tomu dojde při každé obměně zařízení), musí zjistit orientaci a pak načíst požadovaný kód uživatelského rozhraní. Android má třídu nazvanou WindowManager
, která se dá použít k určení aktuální rotace zařízení prostřednictvím WindowManager.DefaultDisplay.Rotation
vlastnosti, jak je znázorněno níže:
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);
}
Tento kód nastaví TextView
umístění o 100 pixelů od levého horního okraje obrazovky a automaticky animuje nové rozložení při otočení na šířku, jak je znázorněno tady:
Zabránění restartování aktivity
Kromě zpracování všeho v OnCreate
aplikaci může také zabránit restartování aktivity, když se orientace změní nastavením ConfigurationChanges
následujícím ActivityAttribute
způsobem:
[Activity (Label = "CodeLayoutActivity", ConfigurationChanges=Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)]
Když se teď zařízení otočí, aktivita se nerestartuje. Aby bylo možné v tomto případě ručně zpracovat změnu orientace, může aktivita přepsat OnConfigurationChanged
metodu a určit orientaci z objektu Configuration
, který je předán, stejně jako v nové implementaci aktivity níže:
[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";
}
}
}
TextView's
Tady jsou parametry rozložení inicializovány pro orientaci na šířku i na výšku. Proměnné třídy obsahují parametry společně se TextView
samotným, protože aktivita se při změně orientace znovu nevytvoří. Kód stále používá surfaceOrientartion
in OnCreate
k nastavení počátečního rozložení pro TextView
. OnConfigurationChanged
Potom zpracuje všechny následné změny rozložení.
Když spustíme aplikaci, Android načte změny uživatelského rozhraní při obměně zařízení a nerestartuje aktivitu.
Zabránění restartování aktivity pro deklarativní rozložení
Restartování aktivit způsobené obměnou zařízením je také možné zabránit, pokud definujeme rozložení v jazyce XML. Tento přístup můžeme použít například v případě, že chceme zabránit restartování aktivity (z důvodů výkonu) a nemusíme načítat nové prostředky pro různé orientace.
Provedeme to stejným postupem, který používáme s programovým rozložením. Jednoduše se nastavil ConfigurationChanges
v ActivityAttribute
, jak jsme to udělali CodeLayoutActivity
dříve. V metodě je možné znovu implementovat OnConfigurationChanged
jakýkoli kód, který je potřeba spustit pro změnu orientace.
Zachování stavu během změn orientace
Ať už se jedná o rotaci deklarativním nebo programovým způsobem, měly by všechny aplikace pro Android implementovat stejné techniky pro správu stavu, když se změní orientace zařízení. Správa stavu je důležitá, protože systém restartuje spuštěnou aktivitu, když se zařízení s Androidem otočí. Android to dělá, aby bylo možné snadno načíst alternativní prostředky, jako jsou rozložení a kreslicí zařízení navržená speciálně pro konkrétní orientaci. Při restartování aktivita ztratí jakýkoli přechodný stav, který může být uložen v proměnných místní třídy. Proto pokud je aktivita závislá na stavu, musí zachovat svůj stav na úrovni aplikace. Aplikace musí zpracovávat ukládání a obnovování libovolného stavu aplikace, který chce zachovat v rámci změn orientace.
Další informace o zachování stavu v Androidu najdete v průvodci životním cyklem aktivit.
Shrnutí
Tento článek popisuje, jak používat integrované funkce Androidu pro práci s rotací. Nejprve jsme vysvětlili, jak používat systém prostředků Androidu k vytváření aplikací pracujících s orientací. Pak předá, jak přidat ovládací prvky v kódu a jak zpracovat změny orientace ručně.