Xamarin.Forms BoxView

Download Sample Örneği indirme

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 BoxViewayarlarsınız:

  • Color öğesini seçin.
  • CornerRadius öğesini seçin.
  • WidthRequest cihazın genişliğini cihazdan BoxView bağımsız birimler halinde ayarlamak için.
  • HeightRequest öğesinin yüksekliğini ayarlamak için BoxView.

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 YellowGreenayarlanabilir.

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 BoxViewayarlanabilir.

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.Filldeğ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 BoxViewkendi boyutunu uygular.

Bir BoxView , bir boyutta kısıtlanabilir ve diğerinde kısıtlanamaz. Örneğin, dikey bir öğesinin BoxViewStackLayoutalt öğ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.Fillbir değere ayarlanmışsa BoxViewHorizontalOptions, 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:

Basic BoxView

VerticalOptions ve HorizontalOptions özellikleri etiketinden BoxView kaldırılırsa veya olarak ayarlanırsaFillBoxView, sayfa boyutuyla kısıtlanır ve sayfayı dolduracak şekilde genişletilir.

ayrıca BoxView bir öğesinin AbsoluteLayoutalt öğ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 StackLayoutalt öğeleridir. Bu işaretleme, öğesiyle Label kullanılan çeşitli dekoratif BoxView öğe türlerinden oluşur:

Text Decoration

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 Labelile 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 Fillbir değere ayarlanmış bir içine alarak bir StackLayoutHorizontalOptions metin dizesinin altını çizebilirsiniz. 'nin StackLayout genişliği daha sonra genişliğine göre Labelyönetilir ve ardından bu genişlik öğesine BoxViewuygulanı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 BoxViewhr 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 StackLayoutiçine alarak metin paragrafının bir tarafına dikey bir çizgi çizebilirsiniz. Bu durumda, öğesinin BoxView yüksekliği, yüksekliği StackLayoutile aynıdır ve bu yükseklik değerinin Labelyü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:

ListView Colors

ListViewColors programı adlı NamedColorbir 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 ListViewolarak 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 BoxViewtü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:

Game of Life

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:

Dot-Matrix Clock

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 AbsoluteLayoutkullanı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 AbsoluteLayoutSizeChanged göre olduğundan, sayfanın işleyicisinin yalnızca öğesini HeightRequest ayarlaması AbsoluteLayoutgerekir:

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 BoxViewbelirgin bir uygulaması gibi görünebilir, ancak BoxView öğeler de analog bir saat gerçekleştirebilir:

BoxView Clock

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 SizeChangedAbsoluteLayoutgerç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ı AbsoluteLayoutbelirler 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.