Orientace zařízení
Je důležité zvážit, jak se bude vaše aplikace používat a jak lze začlenit orientaci na šířku, aby se zlepšilo uživatelské prostředí. Jednotlivá rozložení lze navrhnout tak, aby vyhovovala více orientací a co nejlépe využila dostupné místo. Na úrovni aplikace může být rotace zakázaná nebo povolená.
Řízení orientace
Při použití Xamarin.Formsje podporovaná metoda řízení orientace zařízení použít nastavení pro každý jednotlivý projekt.
iOS
V iOSu je orientace zařízení nakonfigurovaná pro aplikace používající soubor Info.plist . Pomocí možností integrovaného vývojového prostředí (IDE) v horní části tohoto dokumentu vyberte, které pokyny chcete zobrazit:
V sadě Visual Studio otevřete projekt iOS a otevřete Soubor Info.plist. Soubor se otevře na konfiguračním panelu počínaje kartou Informace o nasazení pro iPhone:
Android
Pokud chcete řídit orientaci v Androidu, otevřete MainActivity.cs a nastavte orientaci pomocí atributu dekorující MainActivity
třídu:
namespace MyRotatingApp.Droid
{
[Activity (Label = "MyRotatingApp.Droid", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation, ScreenOrientation = ScreenOrientation.Landscape)] //This is what controls orientation
public class MainActivity : FormsAppCompatActivity
{
protected override void OnCreate (Bundle bundle)
...
Xamarin.Android podporuje několik možností pro určení orientace:
- Na šířku – vynutí orientaci aplikace na šířku bez ohledu na data ze senzorů.
- Na výšku – vynutí orientaci aplikace na výšku bez ohledu na data snímače.
- Uživatel – způsobí, že se aplikace zobrazí s použitím preferované orientace uživatele.
- Za – způsobí, že orientace aplikace bude stejná jako orientace aktivity za ní.
- Senzor – způsobí, že senzor určí orientaci aplikace, i když uživatel zakázal automatické otáčení.
- SensorLandscape – způsobí, že aplikace použije orientaci na šířku při použití dat ze snímačů ke změně směru zobrazení obrazovky (takže se obrazovka nezobrazuje jako vzhůru nohama).
- SensorPortrait – způsobí, že aplikace použije orientaci na výšku při změně směru zobrazení obrazovky (aby se obrazovka nezobradřila vzhůru nohama).
- ReverseLandscape – způsobí, že aplikace použije orientaci na šířku, směrem k opačnému směru než obvykle, takže se zobrazí "vzhůru nohama".
- ReversePortrait – způsobí, že aplikace použije orientaci na výšku, směrem k opačnému směru než obvykle, takže se zobrazí "vzhůru nohama".
- FullSensor – způsobí, že aplikace bude spoléhat na data snímačů, aby vybrali správnou orientaci (mimo možnou 4).
- FullUser – způsobí, že aplikace použije předvolby orientace uživatele. Pokud je zapnutá automatická rotace, můžete použít všechny 4 orientace.
- UserLandscape – [Nepodporováno] způsobí, že aplikace použije orientaci na šířku, pokud uživatel nemá povolenou automatickou rotaci, v takovém případě použije senzor k určení orientace. Tato možnost přeruší kompilaci.
- UserPortrait – [Nepodporováno] způsobí, že aplikace použije orientaci na výšku, pokud uživatel nemá povolenou automatickou rotaci, v takovém případě použije senzor k určení orientace. Tato možnost přeruší kompilaci.
- Uzamčeno – [Nepodporováno] způsobí, že aplikace použije orientaci obrazovky bez ohledu na to, co je při spuštění, aniž by reagovala na změny ve fyzické orientaci zařízení. Tato možnost přeruší kompilaci.
Mějte na paměti, že nativní rozhraní API pro Android poskytují velkou kontrolu nad tím, jak se spravuje orientace, včetně možností, které explicitně odporují vyjádřeným předvolbám uživatele.
Univerzální platforma Windows
V Univerzální platforma Windows (UPW) jsou podporované orientace nastavené v souboru Package.appxmanifest. Otevření manifestu zobrazí konfigurační panel, kde je možné vybrat podporované orientace.
Reakce na změny v orientaci
Xamarin.Forms nenabízí žádné nativní události pro upozorňování aplikace na změny orientace ve sdíleném kódu. Xamarin.Essentials Obsahuje však třídu [DeviceDisplay
], která poskytuje oznámení o změnách orientace.
Chcete-li zjistit orientaci bez Xamarin.Essentials, monitorujte SizeChanged
událost Page
, která se aktivuje, když je šířka nebo výška Page
změn. Pokud je šířka Page
větší než výška, zařízení je v režimu na šířku. Další informace naleznete v tématu Zobrazení obrázku na základě orientace obrazovky.
Alternativně je možné přepsat metodu OnSizeAllocated
na , vložit do ní libovolnou logiku Page
změny rozložení. Tato OnSizeAllocated
metoda se volá vždy, když Page
je přidělena nová velikost, ke které dochází při každé obměně zařízení. Všimněte si, že základní implementace OnSizeAllocated
provádí důležité funkce rozložení, takže je důležité volat základní implementaci v přepsání:
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height); //must be called
}
Pokud tento krok neučiníte, dojde k nefunkční stránce.
Všimněte si, že OnSizeAllocated
metoda se může volat mnohokrát, když se zařízení otočí. Pokaždé, když změníte rozložení, je plýtvání prostředky a může to vést k blikání. Zvažte použití proměnné instance na stránce ke sledování, jestli je orientace na šířku nebo na výšku, a překreslit pouze v případě, že dojde ke změně:
private double width = 0;
private double height = 0;
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height); //must be called
if (this.width != width || this.height != height)
{
this.width = width;
this.height = height;
//reconfigure layout
}
}
Po zjištění změny orientace zařízení můžete chtít přidat nebo odebrat další zobrazení do a z uživatelského rozhraní, abyste mohli reagovat na změnu v dostupném prostoru. Představte si například integrovanou kalkulačku na jednotlivých platformách na výšku:
a na šířku:
Všimněte si, že aplikace využívají dostupné místo přidáním dalších funkcí na šířku.
Responzivní rozložení
Rozhraní je možné navrhnout pomocí předdefinovaných rozložení tak, aby při otáčení zařízení plynule přecházení. Při navrhování rozhraní, která budou při reagování na změny v orientaci nadále atraktivní, zvažte následující obecná pravidla:
- Věnujte pozornost poměrům – změny v orientaci můžou způsobit problémy v případě, že jsou provedeny určité předpoklady s ohledem na poměry. Například pohled, který by měl dostatek místa ve 1/3 svislém prostoru obrazovky na výšku, se nemusí vejít do 1/3 svislého prostoru na šířku.
- Buďte opatrní s absolutními hodnotami – absolutními (pixelovými) hodnotami, které dávají smysl na výšku, nemusí dávat smysl v krajině. Pokud jsou nezbytné absolutní hodnoty, izolujte jejich dopad pomocí vnořených rozložení. Bylo by například vhodné použít absolutní hodnoty v
TableView
ItemTemplate
případě, že šablona položky má zaručenou jednotnou výšku.
Výše uvedená pravidla platí také při implementaci rozhraní pro více velikostí obrazovky a obecně se považují za osvědčený postup. Zbytek tohoto průvodce vysvětluje konkrétní příklady responzivních rozložení pomocí každého z primárních rozložení v Xamarin.Forms.
Poznámka:
Následující části ukazují, jak implementovat responzivní rozložení pomocí jednoho typu Layout
najednou. V praxi je často jednodušší kombinovat Layout
s dosažením požadovaného rozložení pomocí jednodušší nebo nejintuitivnější Layout
pro každou komponentu.
StackLayout
Představte si následující aplikaci zobrazenou na výšku:
a na šířku:
To se provádí pomocí následujícího XAML:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResponsiveLayout.StackLayoutPageXaml"
Title="Stack Photo Editor - XAML">
<ContentPage.Content>
<StackLayout Spacing="10" Padding="5" Orientation="Vertical"
x:Name="outerStack"> <!-- can change orientation to make responsive -->
<ScrollView>
<StackLayout Spacing="5" HorizontalOptions="FillAndExpand"
WidthRequest="1000">
<StackLayout Orientation="Horizontal">
<Label Text="Name: " WidthRequest="75"
HorizontalOptions="Start" />
<Entry Text="deer.jpg"
HorizontalOptions="FillAndExpand" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Date: " WidthRequest="75"
HorizontalOptions="Start" />
<Entry Text="07/05/2015"
HorizontalOptions="FillAndExpand" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Tags:" WidthRequest="75"
HorizontalOptions="Start" />
<Entry Text="deer, tiger"
HorizontalOptions="FillAndExpand" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Button Text="Save" HorizontalOptions="FillAndExpand" />
</StackLayout>
</StackLayout>
</ScrollView>
<Image Source="deer.jpg" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
Některá jazyka C# slouží ke změně orientace outerStack
na základě orientace zařízení:
protected override void OnSizeAllocated (double width, double height){
base.OnSizeAllocated (width, height);
if (width != this.width || height != this.height) {
this.width = width;
this.height = height;
if (width > height) {
outerStack.Orientation = StackOrientation.Horizontal;
} else {
outerStack.Orientation = StackOrientation.Vertical;
}
}
}
Je potřeba upozornit na následující:
outerStack
se upraví tak, aby obrázek a ovládací prvky byly prezentovány jako vodorovný nebo svislý zásobník v závislosti na orientaci, aby bylo možné co nejlépe využít dostupné místo.
AbsoluteLayout
Představte si následující aplikaci zobrazenou na výšku:
a na šířku:
To se provádí pomocí následujícího XAML:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResponsiveLayout.AbsoluteLayoutPageXaml"
Title="AbsoluteLayout - XAML" BackgroundImageSource="deer.jpg">
<ContentPage.Content>
<AbsoluteLayout>
<ScrollView AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="PositionProportional,SizeProportional">
<AbsoluteLayout>
<Image Source="deer.jpg"
AbsoluteLayout.LayoutBounds=".5,0,300,300"
AbsoluteLayout.LayoutFlags="PositionProportional" />
<BoxView Color="#CC1A7019" AbsoluteLayout.LayoutBounds=".5
300,.7,50" AbsoluteLayout.LayoutFlags="XProportional
WidthProportional" />
<Label Text="deer.jpg" AbsoluteLayout.LayoutBounds = ".5
310,1, 50" AbsoluteLayout.LayoutFlags="XProportional
WidthProportional" HorizontalTextAlignment="Center" TextColor="White" />
</AbsoluteLayout>
</ScrollView>
<Button Text="Previous" AbsoluteLayout.LayoutBounds="0,1,.5,60"
AbsoluteLayout.LayoutFlags="PositionProportional
WidthProportional"
BackgroundColor="White" TextColor="Green" BorderRadius="0" />
<Button Text="Next" AbsoluteLayout.LayoutBounds="1,1,.5,60"
AbsoluteLayout.LayoutFlags="PositionProportional
WidthProportional" BackgroundColor="White"
TextColor="Green" BorderRadius="0" />
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>
Je potřeba upozornit na následující:
- Vzhledem ke způsobu, jakým byla stránka rozložena, není nutné, aby procedurální kód zavedl rychlost odezvy.
- Slouží
ScrollView
k tomu, aby byl popisek viditelný i v případě, že výška obrazovky je menší než součet pevných výšek tlačítek a obrázku.
RelativeLayout
Představte si následující aplikaci zobrazenou na výšku:
a na šířku:
To se provádí pomocí následujícího XAML:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResponsiveLayout.RelativeLayoutPageXaml"
Title="RelativeLayout - XAML"
BackgroundImageSource="deer.jpg">
<ContentPage.Content>
<RelativeLayout x:Name="outerLayout">
<BoxView BackgroundColor="#AA1A7019"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=1}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=1}"
RelativeLayout.XConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=0,Constant=0}"
RelativeLayout.YConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=0,Constant=0}" />
<ScrollView
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=1}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=1,Constant=-60}"
RelativeLayout.XConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=0,Constant=0}"
RelativeLayout.YConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=0,Constant=0}">
<RelativeLayout>
<Image Source="deer.jpg" x:Name="imageDeer"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=.8}"
RelativeLayout.XConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=.1}"
RelativeLayout.YConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=0,Constant=10}" />
<Label Text="deer.jpg" HorizontalTextAlignment="Center"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=1}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=0,Constant=75}"
RelativeLayout.XConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=0,Constant=0}"
RelativeLayout.YConstraint="{ConstraintExpression
Type=RelativeToView,ElementName=imageDeer,Property=Height,Factor=1,Constant=20}" />
</RelativeLayout>
</ScrollView>
<Button Text="Previous" BackgroundColor="White" TextColor="Green" BorderRadius="0"
RelativeLayout.YConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=1,Constant=-60}"
RelativeLayout.XConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=0,Constant=0}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=0,Constant=60}"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=.5}"
/>
<Button Text="Next" BackgroundColor="White" TextColor="Green" BorderRadius="0"
RelativeLayout.XConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=.5}"
RelativeLayout.YConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Height,Factor=1,Constant=-60}"
RelativeLayout.HeightConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=0,Constant=60}"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,Property=Width,Factor=.5}"
/>
</RelativeLayout>
</ContentPage.Content>
</ContentPage>
Je potřeba upozornit na následující:
- Vzhledem ke způsobu, jakým byla stránka rozložena, není nutné, aby procedurální kód zavedl rychlost odezvy.
- Slouží
ScrollView
k tomu, aby byl popisek viditelný i v případě, že výška obrazovky je menší než součet pevných výšek tlačítek a obrázku.
Mřížka
Představte si následující aplikaci zobrazenou na výšku:
a na šířku:
To se provádí pomocí následujícího XAML:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResponsiveLayout.GridPageXaml"
Title="Grid - XAML">
<ContentPage.Content>
<Grid x:Name="outerGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<Grid x:Name="innerGrid" Grid.Row="0" Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="deer.jpg" Grid.Row="0" Grid.Column="0" HeightRequest="300" WidthRequest="300" />
<Grid x:Name="controlsGrid" Grid.Row="0" Grid.Column="1" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="Name:" Grid.Row="0" Grid.Column="0" />
<Label Text="Date:" Grid.Row="1" Grid.Column="0" />
<Label Text="Tags:" Grid.Row="2" Grid.Column="0" />
<Entry Grid.Row="0" Grid.Column="1" />
<Entry Grid.Row="1" Grid.Column="1" />
<Entry Grid.Row="2" Grid.Column="1" />
</Grid>
</Grid>
<Grid x:Name="buttonsGrid" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Text="Previous" Grid.Column="0" />
<Button Text="Save" Grid.Column="1" />
<Button Text="Next" Grid.Column="2" />
</Grid>
</Grid>
</ContentPage.Content>
</ContentPage>
Spolu s následujícím procedurálním kódem pro zpracování změn obměně:
private double width;
private double height;
protected override void OnSizeAllocated (double width, double height){
base.OnSizeAllocated (width, height);
if (width != this.width || height != this.height) {
this.width = width;
this.height = height;
if (width > height) {
innerGrid.RowDefinitions.Clear();
innerGrid.ColumnDefinitions.Clear ();
innerGrid.RowDefinitions.Add (new RowDefinition{ Height = new GridLength (1, GridUnitType.Star) });
innerGrid.ColumnDefinitions.Add (new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star) });
innerGrid.ColumnDefinitions.Add (new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star) });
innerGrid.Children.Remove (controlsGrid);
innerGrid.Children.Add (controlsGrid, 1, 0);
} else {
innerGrid.RowDefinitions.Clear();
innerGrid.ColumnDefinitions.Clear ();
innerGrid.ColumnDefinitions.Add (new ColumnDefinition{ Width = new GridLength (1, GridUnitType.Star) });
innerGrid.RowDefinitions.Add (new RowDefinition { Height = new GridLength (1, GridUnitType.Auto) });
innerGrid.RowDefinitions.Add (new RowDefinition { Height = new GridLength (1, GridUnitType.Star) });
innerGrid.Children.Remove (controlsGrid);
innerGrid.Children.Add (controlsGrid, 0, 1);
}
}
}
Je potřeba upozornit na následující:
- Vzhledem ke způsobu rozložení stránky existuje metoda, jak změnit umístění mřížky ovládacích prvků.