Xamarin.Forms BoxView
BoxView vykreslí jednoduchý obdélník zadané šířky, výšky a barvy. Můžete použít BoxView pro dekorace, základní grafiku a pro interakci s uživatelem přes dotykové ovládání.
Vzhledem Xamarin.Forms k tomu, že nemá integrovaný systém vektorových grafik, BoxView pomáhá kompenzovat. Některé z ukázkových programů popsaných v tomto článku se používají BoxView pro vykreslování grafiky. BoxViewVelikost může být podobná čáře konkrétní šířky a tloušťky a následně otočena jakýmkoli úhlem pomocí Rotation Vlastnosti.
I když BoxView mohou napodobovat jednoduché grafiky, můžete chtít prozkoumat Using SkiaSharp in Xamarin.Forms podrobnější požadavky na grafiku.
Nastavení BoxView barvy a velikosti
Obvykle nastavíte následující vlastnosti BoxView :
- Xamarin_Forms _BoxView_Color "data-LINKTYPE =" absolutní cestu ">
Colork nastavení jeho barvy. - Xamarin_Forms _BoxView_CornerRadius "data-LINKTYPE =" absolutní cestu ">
CornerRadiusk nastavení poloměru rohů. - Xamarin_Forms _VisualElement_WidthRequest "data-LINKTYPE =" absolutní cestu ">
WidthRequestpro nastavení šířkyBoxViewv jednotkách nezávislých na zařízení. - Xamarin_Forms _VisualElement_HeightRequest "data-LINKTYPE =" absolutní cestu ">
HeightRequestk nastavení výškyBoxView.
ColorVlastnost je typu Color ; vlastnost může být nastavena na libovolnou Color hodnotu, včetně statických polí jen pro čtení, která 141 jsou v abecedním pořadí od AliceBlue do YellowGreen .
CornerRadiusVlastnost je typu CornerRadius ; vlastnost může být nastavena na jedinou double hodnotu poloměru horního rohu nebo na CornerRadius strukturu definovanou čtyřmi double hodnotami, které jsou aplikovány na levý horní, pravý horní, dolní levý a pravý dolní okraj BoxView .
WidthRequestVlastnosti a HeightRequest hrají pouze roli, pokud BoxView je v rozložení WidthRequest . Jedná se o případ, kdy kontejner rozložení potřebuje znát velikost dítěte, například, když BoxView je objekt podřízenosti buňky s automatickou velikostí v Grid rozložení. BoxViewJe také bez omezení HorizontalOptions , pokud VerticalOptions jsou vlastnosti a vlastností nastaveny na jiné hodnoty než LayoutOptions.Fill . Pokud BoxView je neomezená, ale WidthRequest vlastnosti a nejsou HeightRequest nastaveny, Šířka nebo výška se nastaví na výchozí hodnoty 40 jednotek nebo přibližně na 1/4 palce na mobilních zařízeních.
WidthRequestVlastnosti a HeightRequest jsou ignorovány, pokud BoxView je WidthRequest v rozložení, v takovém případě kontejner rozložení ukládá svoji vlastní velikost na BoxView .
Je BoxView možné omezit v jedné dimenzi a Neomezovat v druhé. Například pokud BoxView je podřízenou položkou svislé StackLayout , svislá dimenze BoxView je neomezená a její vodorovná dimenze je obecně omezená. Existují však výjimky pro tuto vodorovnou dimenzi: Pokud BoxView má HorizontalOptions vlastnost nastavenou na jinou hodnotu než LayoutOptions.Fill , je vodorovná dimenze také neomezená. Je také možné StackLayout , že samotný má neomezenou vodorovnou dimenzi, v takovém případě BoxView bude také horizontálně neomezená.
Ukázka BasicBoxView zobrazí v středu své stránky neomezenou mocninu o velikosti jednoho palce.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:BasicBoxView"
x:Class="BasicBoxView.MainPage">
<BoxView Color="CornflowerBlue"
CornerRadius="10"
WidthRequest="160"
HeightRequest="160"
VerticalOptions="Center"
HorizontalOptions="Center" />
</ContentPage>
Výsledek:
Pokud VerticalOptionsHorizontalOptions jsou vlastnosti a odebrány ze BoxView značky nebo jsou nastaveny na Fill , pak BoxView dojde k omezení velikosti stránky a rozbalí se, aby vyplnila stránku.
BoxViewMůže být také podřízenou položkou AbsoluteLayout . V takovém případě je umístění i velikost BoxView nastaveny pomocí LayoutBounds připojené vlastnosti BIND. AbsoluteLayoutJe popsána v článku AbsoluteLayout.
Příklady všech těchto případů najdete v ukázkových programech, které následují.
Vykreslování dekorace textu
Můžete použít BoxView k přidání některých jednoduchých dekorace na stránky ve formě vodorovných a svislých čar. Tento příklad demonstruje TextDecoration Sample. Všechny vizuály programu jsou definovány v souboru MainPage. XAML , který obsahuje několik elementů a, které jsou BoxViewStackLayout zde uvedeny:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TextDecoration"
x:Class="TextDecoration.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="BoxView">
<Setter Property="Color" Value="Black" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ScrollView Margin="15">
<StackLayout>
···
</StackLayout>
</ScrollView>
</ContentPage>
Všechny následující značky jsou podřízené objekty StackLayout . Tento kód se skládá z několika typů dekorativních prvků, které BoxView jsou použity s Label prvkem:
Styl tohoto příznaku v horní části stránky se dosáhne pomocí AbsoluteLayout , jehož podřízené položky jsou čtyři BoxView prvky a a, ke Label kterým jsou přiřazena konkrétní umístění a velikosti:
<AbsoluteLayout>
<BoxView AbsoluteLayout.LayoutBounds="0, 10, 200, 5" />
<BoxView AbsoluteLayout.LayoutBounds="0, 20, 200, 5" />
<BoxView AbsoluteLayout.LayoutBounds="10, 0, 5, 65" />
<BoxView AbsoluteLayout.LayoutBounds="20, 0, 5, 65" />
<Label Text="Stylish Header"
FontSize="24"
AbsoluteLayout.LayoutBounds="30, 25, AutoSize, AutoSize"/>
</AbsoluteLayout>
V souboru XAML AbsoluteLayout je následován a Label formátovaný text, který popisuje AbsoluteLayout .
Textový řetězec lze podtrhnout uzavřením Label a BoxView v StackLayout , jehož HorizontalOptions hodnota je nastavena na jinou hodnotu než Fill . Šířka ovládacího panelu StackLayout se pak řídí šířkou Label , která poté ukládá tuto šířku na BoxView . BoxViewJe přiřazena pouze explicitní Výška:
<StackLayout HorizontalOptions="Center">
<Label Text="Underlined Text"
FontSize="24" />
<BoxView HeightRequest="2" />
</StackLayout>
Tuto techniku nelze použít pro podtržení jednotlivých slov v rámci delších textových řetězců nebo odstavců.
Je také možné použít BoxView pro podobnou hr prvku HTML (horizontální pravidlo). Stačí, když zadáte šířku BoxView určené jeho nadřazeným kontejnerem, což je v tomto případě StackLayout :
<BoxView HeightRequest="3" />
Nakonec můžete nakreslit svislou čáru na jednu stranu textu odstavce, a to uzavřením do BoxViewLabel vodorovného StackLayout . V tomto případě je výška je BoxView stejná jako výška StackLayout , která se řídí výškou Label :
<StackLayout Orientation="Horizontal">
<BoxView WidthRequest="4"
Margin="0, 0, 10, 0" />
<Label>
···
</Label>
</StackLayout>
Seznam barev pomocí BoxView
BoxViewJe vhodný pro zobrazení barev. Tento program používá ListView k vypsání všech veřejných statických polí jen pro čtení ve Xamarin.FormsColor struktuře:
Program ListViewColors obsahuje třídu s názvem . Statický konstruktor používá reflexi pro přístup ke všem polím Color struktury a k vytvoření NamedColor objektu pro každý z nich. Jsou uloženy ve statické All vlastnosti:
public class NamedColor
{
// Instance members.
private NamedColor()
{
}
public string Name { private set; get; }
public string FriendlyName { private set; get; }
public Color Color { private set; get; }
public string RgbDisplay { private set; get; }
// Static members.
static NamedColor()
{
List<NamedColor> all = new List<NamedColor>();
StringBuilder stringBuilder = new StringBuilder();
// Loop through the public static fields of the Color structure.
foreach (FieldInfo fieldInfo in typeof(Color).GetRuntimeFields ())
{
if (fieldInfo.IsPublic &&
fieldInfo.IsStatic &&
fieldInfo.FieldType == typeof (Color))
{
// Convert the name to a friendly name.
string name = fieldInfo.Name;
stringBuilder.Clear();
int index = 0;
foreach (char ch in name)
{
if (index != 0 && Char.IsUpper(ch))
{
stringBuilder.Append(' ');
}
stringBuilder.Append(ch);
index++;
}
// Instantiate a NamedColor object.
Color color = (Color)fieldInfo.GetValue(null);
NamedColor namedColor = new NamedColor
{
Name = name,
FriendlyName = stringBuilder.ToString(),
Color = color,
RgbDisplay = String.Format("{0:X2}-{1:X2}-{2:X2}",
(int)(255 * color.R),
(int)(255 * color.G),
(int)(255 * color.B))
};
// Add it to the collection.
all.Add(namedColor);
}
}
all.TrimExcess();
All = all;
}
public static IList<NamedColor> All { private set; get; }
}
Vizuály programu jsou popsány v souboru XAML. ItemsSourceVlastnost ListView je nastavena na statickou NamedColor.All vlastnost, což znamená, že ListView zobrazí všechny jednotlivé NamedColor objekty:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ListViewColors"
x:Class="ListViewColors.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="10, 20, 10, 0" />
<On Platform="Android, UWP" Value="10, 0" />
</OnPlatform>
</ContentPage.Padding>
<ListView SeparatorVisibility="None"
ItemsSource="{x:Static local:NamedColor.All}">
<ListView.RowHeight>
<OnPlatform x:TypeArguments="x:Int32">
<On Platform="iOS, Android" Value="80" />
<On Platform="UWP" Value="90" />
</OnPlatform>
</ListView.RowHeight>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ContentView Padding="5">
<Frame OutlineColor="Accent"
Padding="10">
<StackLayout Orientation="Horizontal">
<BoxView Color="{Binding Color}"
WidthRequest="50"
HeightRequest="50" />
<StackLayout>
<Label Text="{Binding FriendlyName}"
FontSize="22"
VerticalOptions="StartAndExpand" />
<Label Text="{Binding RgbDisplay, StringFormat='RGB = {0}'}"
FontSize="16"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</StackLayout>
</Frame>
</ContentView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
NamedColorObjekty jsou formátovány ViewCell objektem, který je nastaven jako šablona dat pro ListView . Tato šablona obsahuje, BoxView jejíž Color vlastnost je svázána s Color vlastností NamedColor objektu.
Hraní herního života pomocí BoxView podtříd
Hra životního cyklu je mobilní Automation vymysleli od mathematician Jan Conwayův kodex a oblíbená na stránkách vědecké Ameriky v 1970s. Dobrá příručka je k dispozici ve hře Wikipedii article Conwayův kodex pro životní cyklus.
Program Xamarin.FormsXamarin.Forms definuje třídu s názvem , která je odvozena z BoxView . Tato třída zapouzdřuje logiku jednotlivých buněk ve hře:
class LifeCell : BoxView
{
bool isAlive;
public event EventHandler Tapped;
public LifeCell()
{
BackgroundColor = Color.White;
TapGestureRecognizer tapGesture = new TapGestureRecognizer();
tapGesture.Tapped += (sender, args) =>
{
Tapped?.Invoke(this, EventArgs.Empty);
};
GestureRecognizers.Add(tapGesture);
}
public int Col { set; get; }
public int Row { set; get; }
public bool IsAlive
{
set
{
if (isAlive != value)
{
isAlive = value;
BackgroundColor = isAlive ? Color.Black : Color.White;
}
}
get
{
return isAlive;
}
}
}
LifeCell Přidá tři další vlastnosti k BoxView : Col vlastnosti a Row ukládají pozici buňky v mřížce a IsAlive vlastnost indikuje její stav. IsAliveVlastnost také nastaví Color vlastnost BoxView na černou, pokud je buňka aktivní a bílá, pokud buňka není aktivní.
LifeCell nainstaluje také TapGestureRecognizer , aby uživatel mohl přepnout stav buněk klepnutím na ně. Třída překládá Tapped událost z nástroje pro rozpoznávání gest na vlastní Tapped událost.
Program GameOfLife zahrnuje také třídu, která zapouzdřuje většinu logiky hry, a MainPage třídu, která zpracovává vizuály programu. Mezi ně patří překrytí, které popisuje pravidla hry. Tady je program v akci, na kterém je vidět několik stovek LifeCell objektů:
Vytváření digitálních hodin
Program DotMatrixClock vytvoří prvky 210 pro simulaci teček ze starého displeje s tečkou 5-po 7. Čas si můžete přečíst v režimu na výšku nebo na šířku, ale je větší na šířku:
Soubor XAML má poněkud více instancí než vytvoření instance AbsoluteLayout používané pro hodiny:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DotMatrixClock"
x:Class="DotMatrixClock.MainPage"
Padding="10"
SizeChanged="OnPageSizeChanged">
<AbsoluteLayout x:Name="absoluteLayout"
VerticalOptions="Center" />
</ContentPage>
Všechno ostatní dojde v souboru kódu na pozadí. Logika zobrazení jehličkové matice je výrazně zjednodušená definicí několika polí, která popisují tečky odpovídající každé z 10 číslic a dvojtečkou:
public partial class MainPage : ContentPage
{
// Total dots horizontally and vertically.
const int horzDots = 41;
const int vertDots = 7;
// 5 x 7 dot matrix patterns for 0 through 9.
static readonly int[, ,] numberPatterns = new int[10, 7, 5]
{
{
{ 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 1, 0, 0, 1, 1}, { 1, 0, 1, 0, 1},
{ 1, 1, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
},
{
{ 0, 0, 1, 0, 0}, { 0, 1, 1, 0, 0}, { 0, 0, 1, 0, 0}, { 0, 0, 1, 0, 0},
{ 0, 0, 1, 0, 0}, { 0, 0, 1, 0, 0}, { 0, 1, 1, 1, 0}
},
{
{ 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 0, 0, 0, 0, 1}, { 0, 0, 0, 1, 0},
{ 0, 0, 1, 0, 0}, { 0, 1, 0, 0, 0}, { 1, 1, 1, 1, 1}
},
{
{ 1, 1, 1, 1, 1}, { 0, 0, 0, 1, 0}, { 0, 0, 1, 0, 0}, { 0, 0, 0, 1, 0},
{ 0, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
},
{
{ 0, 0, 0, 1, 0}, { 0, 0, 1, 1, 0}, { 0, 1, 0, 1, 0}, { 1, 0, 0, 1, 0},
{ 1, 1, 1, 1, 1}, { 0, 0, 0, 1, 0}, { 0, 0, 0, 1, 0}
},
{
{ 1, 1, 1, 1, 1}, { 1, 0, 0, 0, 0}, { 1, 1, 1, 1, 0}, { 0, 0, 0, 0, 1},
{ 0, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
},
{
{ 0, 0, 1, 1, 0}, { 0, 1, 0, 0, 0}, { 1, 0, 0, 0, 0}, { 1, 1, 1, 1, 0},
{ 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
},
{
{ 1, 1, 1, 1, 1}, { 0, 0, 0, 0, 1}, { 0, 0, 0, 1, 0}, { 0, 0, 1, 0, 0},
{ 0, 1, 0, 0, 0}, { 0, 1, 0, 0, 0}, { 0, 1, 0, 0, 0}
},
{
{ 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0},
{ 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0}
},
{
{ 0, 1, 1, 1, 0}, { 1, 0, 0, 0, 1}, { 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 1},
{ 0, 0, 0, 0, 1}, { 0, 0, 0, 1, 0}, { 0, 1, 1, 0, 0}
},
};
// Dot matrix pattern for a colon.
static readonly int[,] colonPattern = new int[7, 2]
{
{ 0, 0 }, { 1, 1 }, { 1, 1 }, { 0, 0 }, { 1, 1 }, { 1, 1 }, { 0, 0 }
};
// BoxView colors for on and off.
static readonly Color colorOn = Color.Red;
static readonly Color colorOff = new Color(0.5, 0.5, 0.5, 0.25);
// Box views for 6 digits, 7 rows, 5 columns.
BoxView[, ,] digitBoxViews = new BoxView[6, 7, 5];
···
}
Tato pole se dokončí trojrozměrným polem BoxView prvků pro uložení vzorů teček pro šest číslic.
Konstruktor vytvoří všechny BoxView prvky pro číslice a dvojtečku a také inicializuje Color vlastnost BoxView prvků dvojtečky:
public partial class MainPage : ContentPage
{
···
public MainPage()
{
InitializeComponent();
// BoxView dot dimensions.
double height = 0.85 / vertDots;
double width = 0.85 / horzDots;
// Create and assemble the BoxViews.
double xIncrement = 1.0 / (horzDots - 1);
double yIncrement = 1.0 / (vertDots - 1);
double x = 0;
for (int digit = 0; digit < 6; digit++)
{
for (int col = 0; col < 5; col++)
{
double y = 0;
for (int row = 0; row < 7; row++)
{
// Create the digit BoxView and add to layout.
BoxView boxView = new BoxView();
digitBoxViews[digit, row, col] = boxView;
absoluteLayout.Children.Add(boxView,
new Rectangle(x, y, width, height),
AbsoluteLayoutFlags.All);
y += yIncrement;
}
x += xIncrement;
}
x += xIncrement;
// Colons between the hours, minutes, and seconds.
if (digit == 1 || digit == 3)
{
int colon = digit / 2;
for (int col = 0; col < 2; col++)
{
double y = 0;
for (int row = 0; row < 7; row++)
{
// Create the BoxView and set the color.
BoxView boxView = new BoxView
{
Color = colonPattern[row, col] == 1 ?
colorOn : colorOff
};
absoluteLayout.Children.Add(boxView,
new Rectangle(x, y, width, height),
AbsoluteLayoutFlags.All);
y += yIncrement;
}
x += xIncrement;
}
x += xIncrement;
}
}
// Set the timer and initialize with a manual call.
Device.StartTimer(TimeSpan.FromSeconds(1), OnTimer);
OnTimer();
}
···
}
Tento program používá funkci relativního umístění a velikosti AbsoluteLayout . Šířka a výška každého z nich BoxView je nastavená na desetinné hodnoty, konkrétně 85% z 1 dělené počtem vodorovných a svislých teček. Pozice jsou také nastaveny na desetinné hodnoty.
Vzhledem k tomu, že všechny pozice a velikosti jsou relativní vzhledem k celkové velikosti AbsoluteLayout , SizeChanged obslužná rutina stránky musí nastavit pouze HeightRequestAbsoluteLayout :
public partial class MainPage : ContentPage
{
···
void OnPageSizeChanged(object sender, EventArgs args)
{
// No chance a display will have an aspect ratio > 41:7
absoluteLayout.HeightRequest = vertDots * Width / horzDots;
}
···
}
Šířka AbsoluteLayout je automaticky nastavena, protože je roztažena k celé šířce stránky.
Konečný kód ve MainPage třídě zpracovává zpětné volání časovače a barevně tečky každé číslice. Definice multidimenzionálních polí na začátku souboru s kódem na pozadí usnadňuje tuto logiku nejjednodušší část programu:
public partial class MainPage : ContentPage
{
···
bool OnTimer()
{
DateTime dateTime = DateTime.Now;
// Convert 24-hour clock to 12-hour clock.
int hour = (dateTime.Hour + 11) % 12 + 1;
// Set the dot colors for each digit separately.
SetDotMatrix(0, hour / 10);
SetDotMatrix(1, hour % 10);
SetDotMatrix(2, dateTime.Minute / 10);
SetDotMatrix(3, dateTime.Minute % 10);
SetDotMatrix(4, dateTime.Second / 10);
SetDotMatrix(5, dateTime.Second % 10);
return true;
}
void SetDotMatrix(int index, int digit)
{
for (int row = 0; row < 7; row++)
for (int col = 0; col < 5; col++)
{
bool isOn = numberPatterns[digit, row, col] == 1;
Color color = isOn ? colorOn : colorOff;
digitBoxViews[index, row, col].Color = color;
}
}
}
Vytváření analogových hodin
Hodiny jehličkové tabulky můžou být zjevné aplikace BoxView , ale BoxView prvky jsou také schopné realizovat analogové hodiny:
Hodiny BoxView hodin
hodin BoxView
Všechny vizuály v programu BoxViewClock jsou podřízené . Tyto prvky mají velikost pomocí LayoutBounds připojené vlastnosti a jsou otočeny pomocí Rotation Vlastnosti.
Tři BoxView prvky pro ruce s hodinami jsou vytvořeny v souboru XAML, ale ne v umístění nebo velikosti:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:BoxViewClock"
x:Class="BoxViewClock.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 20, 0, 0" />
</OnPlatform>
</ContentPage.Padding>
<AbsoluteLayout x:Name="absoluteLayout"
SizeChanged="OnAbsoluteLayoutSizeChanged">
<BoxView x:Name="hourHand"
Color="Black" />
<BoxView x:Name="minuteHand"
Color="Black" />
<BoxView x:Name="secondHand"
Color="Black" />
</AbsoluteLayout>
</ContentPage>
Konstruktor souboru kódu na pozadí vytváří instanci BoxView elementů 60 pro značky zaškrtnutí kolem obvodu hodin:
public partial class MainPage : ContentPage
{
···
BoxView[] tickMarks = new BoxView[60];
public MainPage()
{
InitializeComponent();
// Create the tick marks (to be sized and positioned later).
for (int i = 0; i < tickMarks.Length; i++)
{
tickMarks[i] = new BoxView { Color = Color.Black };
absoluteLayout.Children.Add(tickMarks[i]);
}
Device.StartTimer(TimeSpan.FromSeconds(1.0 / 60), OnTimerTick);
}
···
}
Velikost a umístění všech BoxView prvků se vyskytnou v SizeChanged obslužné rutině pro AbsoluteLayout . Malá vnitřní struktura třídy s názvem popisuje velikost každé ze tří rukou vzhledem k celkové HandParams velikosti hodin:
public partial class MainPage : ContentPage
{
// Structure for storing information about the three hands.
struct HandParams
{
public HandParams(double width, double height, double offset) : this()
{
Width = width;
Height = height;
Offset = offset;
}
public double Width { private set; get; } // fraction of radius
public double Height { private set; get; } // ditto
public double Offset { private set; get; } // relative to center pivot
}
static readonly HandParams secondParams = new HandParams(0.02, 1.1, 0.85);
static readonly HandParams minuteParams = new HandParams(0.05, 0.8, 0.9);
static readonly HandParams hourParams = new HandParams(0.125, 0.65, 0.9);
···
}
Obslužná rutina určuje střed a poloměr a pak velikost a umístění 60 prvků použitých SizeChangedAbsoluteLayout jako BoxView značky. Smyčka for končí nastavením vlastnosti každého z těchto RotationBoxView prvků. Na konci obslužné rutiny je volána metoda pro nastavení velikosti a umístění tří rukou SizeChangedLayoutHand hodin:
public partial class MainPage : ContentPage
{
···
void OnAbsoluteLayoutSizeChanged(object sender, EventArgs args)
{
// Get the center and radius of the AbsoluteLayout.
Point center = new Point(absoluteLayout.Width / 2, absoluteLayout.Height / 2);
double radius = 0.45 * Math.Min(absoluteLayout.Width, absoluteLayout.Height);
// Position, size, and rotate the 60 tick marks.
for (int index = 0; index < tickMarks.Length; index++)
{
double size = radius / (index % 5 == 0 ? 15 : 30);
double radians = index * 2 * Math.PI / tickMarks.Length;
double x = center.X + radius * Math.Sin(radians) - size / 2;
double y = center.Y - radius * Math.Cos(radians) - size / 2;
AbsoluteLayout.SetLayoutBounds(tickMarks[index], new Rectangle(x, y, size, size));
tickMarks[index].Rotation = 180 * radians / Math.PI;
}
// Position and size the three hands.
LayoutHand(secondHand, secondParams, center, radius);
LayoutHand(minuteHand, minuteParams, center, radius);
LayoutHand(hourHand, hourParams, center, radius);
}
void LayoutHand(BoxView boxView, HandParams handParams, Point center, double radius)
{
double width = handParams.Width * radius;
double height = handParams.Height * radius;
double offset = handParams.Offset;
AbsoluteLayout.SetLayoutBounds(boxView,
new Rectangle(center.X - 0.5 * width,
center.Y - offset * height,
width, height));
// Set the AnchorY property for rotations.
boxView.AnchorY = handParams.Offset;
}
···
}
Metoda LayoutHand velikostí a umístěním každé ruky, aby odkazla přímo na pozici 12:00. Na konci metody je vlastnost nastavená na pozici odpovídající AnchorY středu hodin. Označuje střed rotace.
Ruce se otáčí ve funkci zpětného volání časovače:
public partial class MainPage : ContentPage
{
···
bool OnTimerTick()
{
// Set rotation angles for hour and minute hands.
DateTime dateTime = DateTime.Now;
hourHand.Rotation = 30 * (dateTime.Hour % 12) + 0.5 * dateTime.Minute;
minuteHand.Rotation = 6 * dateTime.Minute + 0.1 * dateTime.Second;
// Do an animation for the second hand.
double t = dateTime.Millisecond / 1000.0;
if (t < 0.5)
{
t = 0.5 * Easing.SpringIn.Ease(t / 0.5);
}
else
{
t = 0.5 * (1 + Easing.SpringOut.Ease((t - 0.5) / 0.5));
}
secondHand.Rotation = 6 * (dateTime.Second + t);
return true;
}
}
Na druhé straně se s pohybem zachází trochu jinak: Používá se funkce animace, která umožňuje, aby se pohyb zdál být hladký a nikoli hladký. Při každém odškrtu se druhá ruky trochu vrátí zpět a pak přeřesní svůj cíl. Tento malý fragment kódu přidává hodně do realismu pohybu.
Stažení ukázky

ListView
životního cyklu životnosti
matice