Sdílet prostřednictvím


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:

Výchozí struktura šablony 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:

Stejná obrazovka, ale v orientaci na šířku

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 TextViewkó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:

Snímky obrazovky s orientací na výšku a na šířku při tisku režimu na výšku

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:

Různé verze Monkey.png zobrazené v režimech na výšku a na šířku

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í LayoutParameterstaké 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:

Tlačítko čítače přírůstku zobrazené v režimu na výšku i na šířku

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:

Stav zobrazení se zachová v režimu na výšku a na šířku.

Zabránění restartování aktivity

Kromě zpracování všeho v OnCreateaplikaci 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ě.