Xamarin.Forms BoxView
BoxView
belirtilen genişlik, yükseklik ve renkte basit bir dikdörtgen oluşturur. Dekorasyon, temel grafikler ve kullanıcıyla dokunma yoluyla etkileşim için kullanabilirsiniz BoxView
.
Xamarin.Forms Yerleşik bir vektör grafik sistemi olmadığından, BoxView
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 gelişmiş grafik gereksinimleri için SkiaSharp'ı Xamarin.Formskullanma hakkında araştırma yapmak isteyebilirsiniz.
BoxView Rengi ve Boyutu 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
; özellik tek double
bir tekdüzen köşe yarıçapı değerine veya sol üst, sağ üst, sol alt ve sağ alta uygulanan dört double
değerle tanımlanan bir CornerRadius
yapıya BoxView
ayarlanabilir.
WidthRequest
ve HeightRequest
özellikleri yalnızca düzeninde kısıtlanmamışsaBoxView
rol oynar. Bu durum, düzen kapsayıcısının alt öğe boyutunu bilmesi gerektiğinde (örneğin, düzeninde otomatik olarak boyutlandırılmış bir hücrenin Grid
alt öğesi olduğundaBoxView
) durumdur. ve VerticalOptions
özellikleri dışındaki LayoutOptions.Fill
değerlere ayarlandığında da A BoxView
kısıtlanmamıştırHorizontalOptions
. BoxView
kısıtlanmamışsa, ancak WidthRequest
ve HeightRequest
özellikleri ayarlanmamışsa, genişlik veya yükseklik varsayılan değer olan 40 birim veya mobil cihazlarda yaklaşık 1/4 inç olarak 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ıtlanmaz. 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 kısıtlanmamış BoxView
bir inç kare 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.
ayrıca BoxView
bir öğesinin AbsoluteLayout
alt öğesi de 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 örnekleri görürsünüz.
Metin Süslemelerini İşleme
yatay ve dikey çizgiler şeklinde sayfalarınıza bazı basit süslemeler eklemek için 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 çeşitli Label
ve BoxView
öğeleri StackLayout
içerir:
<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 öğesini açıklayan biçimlendirilmiş metin içeren bir Label
yer alır AbsoluteLayout
.
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. 'nin StackLayout
genişliği daha sonra genişliğine göre Label
yönetilir ve ardından bu genişlik öğesine BoxView
uygulanır. BoxView
yalnızca açık bir yükseklik atanır:
<StackLayout HorizontalOptions="Center">
<Label Text="Underlined Text"
FontSize="24" />
<BoxView HeightRequest="2" />
</StackLayout>
Uzun metin dizeleri veya paragraf içindeki tek tek sözcüklerin altını çizmek için bu tekniği kullanamazsınız.
Html (yatay kural) öğesine benzemek için de BoxView
hr
kullanabilirsiniz. Yalnızca 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
içine alarak metin paragrafının bir tarafına dikey bir çizgi çizebilirsiniz. Bu durumda, öğesinin BoxView
yüksekliği, yüksekliği StackLayout
ile aynıdır ve bu yükseklik değerinin Label
yüksekliğine göre yönetilir:
<StackLayout Orientation="Horizontal">
<BoxView WidthRequest="4"
Margin="0, 0, 10, 0" />
<Label>
···
</Label>
</StackLayout>
BoxView ile Renkleri Listeleme
renkleri BoxView
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ği ListView
statik NamedColor.All
özelliğe ayarlanır, yani ListView
tüm nesneleri tek tek NamedColor
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: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
özelliğine NamedColor
bağlı olan Color
bir BoxView
içerir.
BoxView'ı Alt Sınıflayarak Yaşam Oyununu Oynama
Game of Life, matematikçi John Conway tarafından icat edilen ve 1970'lerde Scientific American sayfalarında popüler hale getirilmiş bir hücresel otomatondur. Conway'in Game of Life adlı Wikipedia makalesi iyi bir giriş niteliğindedir.
Xamarin.FormsGameOfLife programı, öğesinden BoxView
türetilen adlı LifeCell
bir sınıf tanımlar. Bu sınıf, Game of Life içindeki 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 kılavuz içindeki konumunu depolar ve IsAlive
özelliği durumunu gösterir. özelliğiIsAlive
, hücre yaşıyorsa özelliğini BoxView
siyah, hücre canlı değilse beyaz olarak da ayarlarColor
.
LifeCell
ayrıca, kullanıcının hücrelere dokunarak hücrelerin durumunu 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 çoğunu 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 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 genişlediğinden otomatik olarak ayarlanır.
sınıfındaki MainPage
son kod, zamanlayıcı geri çağırmasını işler ve her bir basama ait 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 de analog bir saat 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ırılması ve konumlandırılması, işleyicisinde SizeChanged
AbsoluteLayout
gerçekleşir. adlı HandParams
sınıfın içinde küçük bir yapı, üç elin her birinin boyutunu saatin toplam boyutuna göre 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
, merkezini ve yarıçapını AbsoluteLayout
belirler ve ardından değer çizgisi 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 yöntemi, LayoutHand
saatin üç elini boyutlandırmak ve konumlandırmak için ç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;
}
···
}
LayoutHand
Yöntem, 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ürmenin 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ünmesini sağlamak için animasyon kolaylaştırma işlevi uygulanır. Her kenede, ikinci el biraz geri çeker ve ardından hedefini aşırı çeker. Bu küçük kod parçası hareketin gerçekçiliğine çok şey katıyor.