Lekce 5 - Pozicování v Xamarin.Forms
V předchozím kvízu, Kvíz - Životní cyklus aplikace, XAML v C# .NET Xamarin, jsme si ověřili nabyté zkušenosti z předchozích lekcí.
V dnešním C# .NET tutoriálu se naučíme pozicovat elementy, což je poslední věc, kterou musíme znát před tím, abychom tvořili záživnější aplikace.
Absolutní a relativní pozice
Absolutní pozice
Někdy potřebujeme element umístit na konkrétní pozici na stránce
(třeba [89;23]
).
V Xamarin.Forms lze vkládat prvky na absolutní pozici v kontejneru zvaném
AbsoluteLayout
. Jelikož se tento kontejner moc nevyužívá, tak
si ho dnes blíže popisovat nebudeme.
V ostatních kontejnerech (Grid
, StackLayout
, ...)
si můžeme pomoci okrajem, čímž obsah elementu posuneme:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyFirstApp.MainPage"> <Grid> <Label Text="Pozdrav z Xamarin.Forms!" VerticalOptions="Start" HorizontalOptions="Start" Margin="89,23,0,0" /> </Grid> </ContentPage>
Prvek <Label>
nejprve zarovnáme vlevo nahoru pomocí
atributů VerticalOptions
a HorizontalOptions
. Dále
mu nastavíme vnější okraje na 89
zleva a 23
shora
atributem Margin
. Takto vypadá, že je ovládací prvek na pozici
[89;23]
, ale ve skutečnosti je kolem něj jen okraj:
Asi největší nevýhoda používání absolutních pozic je, že aplikace nereaguje na změnu poměru stran jednotlivých zařízení, jelikož každé zařízení má jinak velký displej (mobil, tablet, PC). Další nevýhodou je, že pokud nějaký ovládací prvek zvětší svou velikost, musíme ručně ty okolní posunout, aby se nám všechno nerozsypalo. To může být u větších aplikací opravdu velmi nepřehledné. Proto se tak aplikace již nedělají.
Relativní pozice
Relativní pozice na rozdíl od absolutní respektuje okolní prvky v
kontejneru. Upravme XAML kód elementu <Label>
tak, aby se
centroval do elementu, ve kterém je vložený. V našem případě bude ve
středu kontejneru <Grid>
:
<Label HorizontalOptions="Center" VerticalOptions="Center" Text="Pozdrav z Xamarin.Forms!" />
Když aplikaci nyní spustíme na různých zařízeních, Label
je stále uprostřed. Asi nemusím říkat, že HorizontalOptions
nastavuje vodorovné zarovnání a VerticalOptions
svislé:
Okraje
Již jsme zjistili, že každý element má nějaké okraje. Těm vnitřním
se říká Padding
a těm vnějším Margin
. Znalci HTML zde budou jako doma:
Každý okraj můžeme nastavit jiný pro různé strany nebo ho na všech stranách elementu nastavit na jednu velikost.
Vymažeme z aplikace <Label>
a místo něj vložíme
tlačítko pomocí následujícího XAML kódu:
<Button Text="Tlačítko" HorizontalOptions="Center" VerticalOptions="Center" WidthRequest="100" Margin="100,0,0,0" Padding="0,50,0,0"/>
Výsledek vypadá takto:
Je vidět, že ačkoli je tlačítko zarovnané doprostřed, jeho vnější
okraj je na levé straně 100
. Tuto hodnotu jsme nastavili pomocí
Margin
. U vnitřního okraje tlačítka naopak vidíme, že ten
horní je výrazně větší než ostatní. To je hodnota 50
v
Padding
.
Hodnoty zadáváme v pořadí: levý okraj, horní, pravý, dolní a oddělujeme je čárkami. Je možné zadat jen jednu hodnotu, která nastaví všechny okraje na stejnou velikost. Stejně tak můžeme zadat i 2 hodnoty, jednu pro vodorovné okraje a jednu pro svislé.
Všimněte si, že jsme tlačítku v příkladu výše zadali šířku
pomocí atributu WidthRequest
. To se u tlačítek obvykle dělá,
jelikož nevypadá hezky, když je každé jinak široké podle délky textu v
něm. Výška elementů se poté nastavuje pomocí vlastnosti
HeightRequest
.
Jednotky velikostí
Xamarin.Forms pracuje s jednotkami, které nejsou závislé na určitém
zařízení (platformě) a každá platforma tak využívá své vlastní
jednotky. Jestliže nastavíme tlačítku vlastnost WidthRequest
na
100
, tak Xamarin.Forms vezme toto číslo a akorát ho převede na
jednotky používané každou konkrétní platformou. Jednotky pro jednotlivé
platformy jsou:
- iOS:
points
(pts) - Android:
density-independent pixels
(dps)
Přibližně platí, že
163 points = 160 density-independent pixels = 1 palec
. Z tohoto
vztahu vyplývá, že musíme počítat s tím, že nikdy nebudou velikosti na
každé platformě úplně stejné. Tlačítko se šířkou 100
bude mít na Androidu šířku 100 dps
a na iOS
100 pts
, tudíž bude na Androidu o kousíček větší.
Pozicování
Zmiňme si ještě něco málo o pozicování ovládacích prvků. Upravme XAML kód tlačítka tak, aby vypadal následovně:
<Button Text="Tlačítko" />
Tlačítko se roztáhne po celém kontejneru Grid
:
Toto je výchozí chování prvků. Pokud totiž neurčíme zarovnání,
předpokládají se v nich hodnoty Fill
:
<Button Text="Tlačítko" HorizontalOptions="Fill" VerticalOptions="Fill" />
Do atributů HorizontalOptions
můžeme nastavit následující
hodnoty:
Start
- Zarovnání na začátek, tedy vlevoCenter
- Zarovnání na středEnd
- Zarovnání na konec, tedy vpravoFill
- Roztažení přes celou šířkuStartAndExpand
CenterAndExpand
EndAndExpand
FillAndExpand
Hodnoty, které obsahují Expand
, jsou určené pro kontejner
StackLayout
. Když takovou hodnotu použijeme na element ve
StackLayout
, tak daný prvek se bude zarovnávat v co největším
možném prostoru, který mu StackLayout
poskytuje:
<StackLayout> <Button Text="Tlačítko1" VerticalOptions="Start" HorizontalOptions="Center" WidthRequest="100"/> <Button Text="Tlačítko2" VerticalOptions="FillAndExpand" HorizontalOptions="Center" WidthRequest="100"/> </StackLayout>
Kdybychom u druhého tlačítka použili namísto hodnoty
FillAndExpand
jen Fill
, tak se tlačítko
neroztáhne:
U VerticalOptions
jsou hodnoty stejné, akorát hodnota
Start
zarovná element nahoru a hodnota End
dolů.
Pro jistotu ještě jednou zmiňme, že ovládací prvky se zarovnávají do elementu, ve kterém jsou vložené. Tomuto elementu se říká rodičovský (anglicky parent).
Výška a šířka elementů
Pro výšku a šířku elementů používáme atributy
WidthRequest
a HeightRequest
. Při používání
těchto atributů však musíme danému elementu zároveň nastavit
VerticalOptions
a HorizontalOptions
na nějakou jinou
hodnotu než Fill
nebo FillAndExpand
, protože tyto
hodnoty mají přednost před WidthRequest
a
HeightRequest
. Můžeme také nastavit minimální nebo maximální
rozměr pomocí atributů MinimumWidthRequest
,
MinimumHeightRequest
, MaximumWidthRequest
a
MaximumHeightRequest
.
Grid
a StackLayout
Na konec dnešní lekce si ještě řekněme něco málo o dvou základních kontejnerech na ovládací prvky.
Grid
Doposud jsme Grid
brali jako jednoduchý panel, do kterého lze
vkládat nějaké další prvky. Grid
je však již podle názvu
mřížka a jedná se tak o nejuniverzálnější kontejner v Xamarin.Forms. Ve
výchozím nastavení má jen jednu buňku (jeden řádek a jeden sloupec).
Jednotlivé řádky definujeme pomocí elementů RowDefinitions
a ColumnDefinitions
:
<Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="60"/> </Grid.RowDefinitions> <Button Grid.Row="1" Grid.Column="1" Text="Tlačítko"/> </Grid>
V definici sloupců máme 2 sloupce, u kterých definujeme jejich šířku.
První sloupec má pevně nastavenou velikost na 100
. Druhý
sloupec má nastavenou hodnotu na *
, díky které rovnoměrně
vyplní zbylé místo.
Někdy se nám hodí upřesnit i tuto výplň, např. aby byl některý
vyplňující sloupec 2x tak široký než ostatní nebo poloviční. Zapsali
bychom to jako 2*
nebo 0.5*
.
Jestliže chceme, aby byl sloupec široký, jako jsou prvky v
něm obsažené, tak použijeme hodnotu auto
.
U definic řádku je to obdobné, druhý řádek je vysoký přesně
60
, první řádek vyplní zbytek obrazovky.
Všem řádkům a sloupcům můžeme nastavit rozestupy pomocí
vlastností RowSpacing
a ColumnSpacing
.
Od verze Xamarin.Forms 4.7 můžeme definici jednotlivých
řádků a sloupců značně zjednodušit. <Grid>
, který
jsme definovali výše, by se dal ještě definovat takto:
<Grid ColumnDefinitions="100, *" RowDefinitions="*, 60"> <Button Grid.Row="1" Grid.Column="1" Text="Tlačítko"/> </Grid>
Jednotlivé prvky poté umisťujeme do mřížky pomocí atributů
Grid.Row
a Grid.Column
, jejichž výchozí hodnota je
0
. Asi vás nepřekvapí, že indexy jsou od nuly. Naše tlačítko
by se tedy umístilo do druhého sloupce a druhého řádku:
V případě, že chceme, aby prvky zabíraly více řádků
nebo sloupců, tak použijeme atributy Grid.RowSpan
nebo
Grid.ColumnSpan
, kterým zadáme počty řádků nebo sloupců.
StackLayout
StackLayout
je kontejner, který jednoduše skládá ovládací
prvky za sebe. Směr, ve kterém tyto prvky bude skládat, můžeme určit
pomocí atributu Orientation
. Orientation
je ve
výchozím stavu nastavená na hodnotu Vertical
, ale lze ji
nastavit i na Horizontal
. Pomocí atributu Spacing
poté nastavujeme rozestup mezi ovládacími prvky.
V příští lekci, Debug Xamarin aplikace na Android zařízení a stylovaní, se zaměříme na stylování a další komponenty .NETu.