Xamarin.Forms BoxView
BoxView
belirtilen genişlik, yükseklik ve renkte basit bir dikdörtgen oluşturur. Dekorasyon, ilkel grafikler ve dokunarak kullanıcıyla etkileşim için kullanabilirsiniz BoxView
.
Xamarin.Forms Yerleşik vektör grafik sistemi olmadığından, BoxView
bunu telafi etmeye yardımcı olur. Bu makalede açıklanan örnek programlardan bazıları grafikleri işlemek için kullanılır BoxView
. BoxView
, belirli bir genişlik ve kalınlıkta bir çizgiye benzeyecek şekilde boyutlandırılabilir ve ardından özelliği kullanılarak herhangi bir açıyla Rotation
döndürülebilir.
Basit grafikleri taklit edebilir, ancak BoxView
daha karmaşık grafik gereksinimleri için SkiaSharp'ı Xamarin.Forms kullanma hakkında araştırma yapmak isteyebilirsiniz.
BoxView Renk ve Boyutunu Ayarlama
Genellikle aşağıdaki özelliklerini BoxView
ayarlarsınız:
Color
öğesini seçin.CornerRadius
öğesini seçin.WidthRequest
cihazın genişliğini cihazdanBoxView
bağımsız birimler halinde ayarlamak için.HeightRequest
öğesinin yüksekliğini ayarlamak içinBoxView
.
Color
özelliği türündedirColor
; özelliği, ile arasında alfabetik olarak AliceBlue
değişen adlandırılmış renklerin 141 statik salt okunur alanı da dahil olmak üzere herhangi bir Color
değere YellowGreen
ayarlanabilir.
CornerRadius
özelliği türündedirCornerRadius
; özelliği tek double
bir tekdüzen köşe yarıçapı değerine veya sol üst, sağ üst, sol alt ve sağ BoxView
alta uygulanan dört double
değerle tanımlanan bir CornerRadius
yapıya ayarlanabilir.
WidthRequest
ve HeightRequest
özellikleri yalnızca düzeninde kısıtlanmamışsa BoxView
rol oynar. Bu durum, düzen kapsayıcısının çocuğun boyutunu bilmesi gerektiğinde (örneğin, düzende Grid
otomatik boyutlandırılmış bir hücrenin alt öğesi olduğundaBoxView
) durumdur. ve özellikleri dışındaki değerlere ayarlandığında da A BoxView
kısıtlanmamıştır VerticalOptions
HorizontalOptions
.LayoutOptions.Fill
BoxView
kısıtlanmamışsa ancak WidthRequest
ve HeightRequest
özellikleri ayarlanmamışsa, genişlik veya yükseklik 40 birim veya mobil cihazlarda yaklaşık 1/4 inç varsayılan değerlere ayarlanır.
WidthRequest
düzeni kısıtlanmışsaBoxView
ve HeightRequest
özellikleri yoksayılır ve bu durumda düzen kapsayıcısı üzerinde BoxView
kendi boyutunu uygular.
Bir BoxView
, bir boyutta kısıtlanabilir ve diğerinde kısıtlanamaz. Örneğin, dikey bir öğesinin BoxView
StackLayout
alt öğesiyse, öğesinin BoxView
dikey boyutu kısıtlanmamıştır ve yatay boyutu genellikle kısıtlanır. Ancak bu yatay boyut için özel durumlar vardır: özelliği dışında LayoutOptions.Fill
bir değere ayarlanmışsa BoxView
HorizontalOptions
, yatay boyut da kısıtlanmamıştır. Ayrıca, kendisinin kısıtlanmamış bir yatay boyuta sahip olması da mümkündür StackLayout
ve bu durumda BoxView
da yatay olarak kısıtlanmamış olur.
BasicBoxView örneği, sayfasının ortasında bir inç kareyi sınırlandırılmamış BoxView
olarak görüntüler:
<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>
Sonuç şu şekildedir:
VerticalOptions
ve HorizontalOptions
özellikleri etiketinden BoxView
kaldırılırsa veya olarak ayarlanırsaFill
BoxView
, sayfa boyutuyla kısıtlanır ve sayfayı dolduracak şekilde genişletilir.
, BoxView
bir öğesinin AbsoluteLayout
de alt öğesi olabilir. Bu durumda, hem konumu hem de boyutu BoxView
ekli bağlanabilir özelliği kullanılarak LayoutBounds
ayarlanır. AbsoluteLayout
, AbsoluteLayout makalesinde ele alınmıştı.
Aşağıdaki örnek programlarda tüm bu durumların örneklerini görürsünüz.
Metin Süslemelerini İşleme
sayfalarınıza yatay ve dikey çizgiler biçiminde bazı basit süslemeler eklemek için öğesini kullanabilirsiniz BoxView
. TextDecoration örneği bunu gösterir. Programın tüm görselleri MainPage.xaml dosyasında tanımlanır ve burada gösterilen birkaç Label
öğeyi içerir StackLayout
BoxView
:
<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>
Aşağıdaki işaretlemelerin tümü öğesinin StackLayout
alt öğeleridir. Bu işaretleme, öğesiyle Label
kullanılan çeşitli dekoratif BoxView
öğe türlerinden oluşur:
Sayfanın üst kısmındaki şık üst bilgi, alt öğeleri dört BoxView
öğe ve tümüne belirli konumlar ve boyutlar atanmış olan bir Label
ile AbsoluteLayout
elde edilir:
<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>
XAML dosyasında, AbsoluteLayout
öğesinin ardından Label
öğesini açıklayan AbsoluteLayout
biçimlendirilmiş bir metin eklenir.
hem hem BoxView
de Label
değerini dışında Fill
bir değere ayarlanmış bir içine alarak bir StackLayout
HorizontalOptions
metin dizesinin altını çizebilirsiniz. StackLayout
genişliği daha sonra genişliğine göre Label
yönetilir ve ardından bu genişliği üzerinde uygularBoxView
. BoxView
yalnızca açık bir yükseklik atanır:
<StackLayout HorizontalOptions="Center">
<Label Text="Underlined Text"
FontSize="24" />
<BoxView HeightRequest="2" />
</StackLayout>
Bu tekniği, uzun metin dizeleri veya paragraf içindeki tek tek sözcüklerin altını çizmek için kullanamazsınız.
Html (yatay kural) öğesine benzemek için de hr
kullanabilirsinizBoxView
. Yalnızca öğesinin genişliğinin BoxView
üst kapsayıcısı tarafından belirlenmesine izin verin. Bu örnekte :StackLayout
<BoxView HeightRequest="3" />
Son olarak, hem hem Label
de BoxView
öğesini yatay StackLayout
bir içine alarak metin paragrafının bir tarafına dikey çizgi çizebilirsiniz. Bu durumda, yüksekliği BoxView
yüksekliği ile aynıdır StackLayout
ve yüksekliği ile aynıdır. Bu, yüksekliğine göre Label
yönetilir:
<StackLayout Orientation="Horizontal">
<BoxView WidthRequest="4"
Margin="0, 0, 10, 0" />
<Label>
···
</Label>
</StackLayout>
BoxView ile Renkleri Listeleme
, BoxView
renkleri görüntülemek için uygundur. Bu program, yapının tüm genel statik salt okunur alanlarını listelemek Xamarin.FormsColor
için bir ListView
kullanır:
ListViewColors programı adlı NamedColor
bir sınıf içerir. Statik oluşturucu, yapının tüm alanlarına Color
erişmek ve her biri için bir NamedColor
nesne oluşturmak için yansıma kullanır. Bunlar statik All
özelliğinde depolanır:
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; }
}
Program görselleri XAML dosyasında açıklanmıştır. ItemsSource
özelliğinin ListView
statik NamedColor.All
özelliğine ayarlanmış olması, tüm nesneleri tek tek NamedColor
görüntülediği ListView
anlamına gelir:
<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>
NamedColor
Nesneler, veri şablonu ListView
olarak ayarlanan nesnesi tarafından ViewCell
biçimlendirilir. Bu şablon, özelliği nesnenin Color
NamedColor
özelliğine bağlı olan Color
bir BoxView
içerir.
BoxView'ı Alt Sınıflayarak Yaşam Oyununu Oynama
The Game of Life, matematikçi John Conway tarafından icat edilen ve 1970'lerde Scientific American sayfalarında popüler hale getirilen hücresel bir otomatondur. Wikipedia makalesi Conway's Game of Life tarafından iyi bir giriş sağlanır.
Xamarin.FormsGameOfLife programı, öğesinden BoxView
türetilen adlı LifeCell
bir sınıf tanımlar. Bu sınıf, Game of Life'taki tek bir hücrenin mantığını kapsüller:
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
öğesine BoxView
üç özellik daha ekler: Col
ve Row
özellikleri hücrenin konumunu kılavuz içinde depolar ve IsAlive
özelliği durumunu gösterir. özelliğiIsAlive
, hücre yaşıyorsa özelliğini BoxView
siyah, hücre yaşamıyorsa beyaz olarak da ayarlarColor
.
LifeCell
ayrıca kullanıcının hücrelere dokunarak durumlarını değiştirmesine izin vermek için bir TapGestureRecognizer
yükler. sınıfı, olayı hareket tanıyıcısından kendi Tapped
olayına çevirirTapped
.
GameOfLife programı ayrıca oyunun mantığının büyük bölümünü kapsülleyen bir LifeGrid
sınıf ve programın görsellerini işleyen bir MainPage
sınıf içerir. Bunlar, oyunun kurallarını açıklayan bir katman içerir. Sayfada birkaç yüz LifeCell
nesne gösteren program şu şekildedir:
Dijital Saat Oluşturma
DotMatrixClock programı, eski moda 5'e 7 nokta matrisli bir ekranın noktalarının benzetimini yapmak için 210 BoxView
öğe oluşturur. Saati dikey veya yatay modda okuyabilirsiniz, ancak yatay olarak daha büyüktür:
XAML dosyası, saat için kullanılan örneğinden AbsoluteLayout
biraz daha fazlasını yapar:
<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>
Diğer her şey arka planda kod dosyasında gerçekleşir. Noktalı matris görüntüleme mantığı, 10 basamak ve iki nokta üst üste her birine karşılık gelen noktaları açıklayan çeşitli dizilerin tanımıyla büyük ölçüde basitleştirilmiştir:
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];
···
}
Bu alanlar, altı basamak için nokta desenlerini BoxView
depolamak için üç boyutlu bir öğe dizisiyle sonuçlanmıştır.
Oluşturucu, basamaklar BoxView
ve iki nokta üst üste için tüm öğeleri oluşturur ve ayrıca iki nokta üst üste için öğelerin özelliğini BoxView
başlatırColor
:
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();
}
···
}
Bu program, göreli konumlandırma ve boyutlandırma özelliğini AbsoluteLayout
kullanır. Her BoxView
birinin genişliği ve yüksekliği kesirli değerlere ayarlanır; özellikle 1'in %85'i yatay ve dikey nokta sayısına bölünür. Konumlar da kesirli değerlere ayarlanır.
Tüm konumlar ve boyutlar toplam boyutuna AbsoluteLayout
SizeChanged
göre olduğundan, sayfanın işleyicisinin yalnızca öğesini HeightRequest
ayarlaması AbsoluteLayout
gerekir:
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;
}
···
}
öğesinin AbsoluteLayout
genişliği, sayfanın tam genişliğine kadar uzandığından otomatik olarak ayarlanır.
sınıfındaki MainPage
son kod zamanlayıcı geri çağırmasını işler ve her bir basamaktaki noktaları renkler. Arka planda kod dosyasının başındaki çok boyutlu dizilerin tanımı, bu mantığın programın en basit parçası haline getirmesine yardımcı olur:
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;
}
}
}
Analog Saat Oluşturma
Noktalı matrisli saat, uygulamasının BoxView
belirgin bir uygulaması gibi görünebilir, ancak BoxView
öğeler analog bir saati de gerçekleştirebilir:
BoxViewClock programındaki tüm görseller bir AbsoluteLayout
öğesinin alt öğeleridir. Bu öğeler ekli özellik kullanılarak LayoutBounds
boyutlandırılır ve özelliği kullanılarak Rotation
döndürülür.
Saatin elleri için üç BoxView
öğe XAML dosyasında örneği oluşturulur, ancak konumlandırılmaz veya boyutlandırılmaz:
<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>
Arka planda kod dosyasının oluşturucusu, saatin çevresi etrafındaki değer çizgileri için 60 BoxView
öğeyi oluşturur:
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);
}
···
}
Tüm BoxView
öğelerin boyutlandırması ve konumlandırması işleyicisinde SizeChanged
AbsoluteLayout
gerçekleşir. adlı HandParams
sınıfın içindeki küçük bir yapı, saatin toplam boyutuna göre üç elin her birinin boyutunu açıklar:
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);
···
}
İşleyici SizeChanged
, öğesinin merkezini ve yarıçapını AbsoluteLayout
belirler ve ardından değer çizgileri olarak kullanılan 60 BoxView
öğeyi boyutlandırır ve konumlandırır. Döngü, for
bu BoxView
öğelerin her birinin özelliğini ayarlayarak Rotation
sona erer. İşleyicinin SizeChanged
sonunda, LayoutHand
saatin üç elini boyutlandırmak ve konumlandırmak için yöntemi çağrılır:
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;
}
···
}
Yöntem LayoutHand
her eli 12:00 konumuna doğru işaret etmek için boyutlandırıp konumlandırıyor. yönteminin sonunda özelliği, AnchorY
saatin merkezine karşılık gelen bir konuma ayarlanır. Bu, döndürme merkezini gösterir.
Eller zamanlayıcı geri çağırma işlevinde döndürülür:
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;
}
}
İkinci el biraz farklı şekilde ele alındı: Hareketin pürüzsüz değil mekanik görünmesi için bir animasyon kolaylaştırma işlevi uygulanır. Her bir kene üzerinde, ikinci el biraz geri çeker ve ardından hedefini aşıyor. Bu küçük kod parçası hareketin gerçekçiliği için çok şey katıyor.