How To Display Analog Clock Using BoxView In Xamarin.Forms

Introduction

This article demonstrates how the BoxView can be used to build a clock application using C# and XAML in Xamarin.Forms. A classic analog clock can be realized entirely with BoxView.
 
Although Xamarin.Forms doesn't provide a vector graphics programming interface, it does have a BoxView which is normally used for displaying the rectangular blocks of color. However, BoxView can be sized, positioned, and rotated. This is enough to render a classic analog clock.

Let’s start.

Step 1

Open Visual Studio and go to New Project >> installed >> Visual C# >> Cross-Platform. Select Cross-Platform App, then give your project a name and location.



Step 2

Open Solution Explorer >> Project Name >> Mainpage.xaml. Open the Design View of this page.

 

The code is given below.

 

XAML Code
  1. <ContentPage.Padding>  
  2.                <OnPlatform x:TypeArguments="Thickness">  
  3.                    <On Platform="IOS" Value="0, 20, 0, 0" />  
  4.                </OnPlatform>  
  5.            </ContentPage.Padding>  
  6.   
  7.            <AbsoluteLayout x:Name="absoluteLayout"  
  8.                    SizeChanged="OnAbsoluteLayoutSizeChanged">  
  9.   
  10.                <BoxView x:Name="hourHand"  
  11.                 Color="Black" />  
  12.   
  13.                <BoxView x:Name="minuteHand"  
  14.                 Color="Black" />  
  15.   
  16.                <BoxView x:Name="secondHand"  
  17.                 Color="Black" />  
  18.            </AbsoluteLayout>  
  19.      
Step 3

Open Solution Explorer >> Project Name >> Mainpage.xaml.cs. Open the Design View of this page.

 

The code is given below.

 

CS Code
  1. namespace BoxViewClock  
  2. {  
  3.     public partial class MainPage : ContentPage  
  4.     {  
  5.         struct HandParams  
  6.         {  
  7.             public HandParams(double width, double height, double offset) : this()  
  8.             {  
  9.                 Width = width;  
  10.                 Height = height;  
  11.                 Offset = offset;  
  12.             }  
  13.   
  14.             public double Width { private setget; }   // fraction of radius  
  15.             public double Height { private setget; }  // ditto  
  16.             public double Offset { private setget; }  // relative to center pivot  
  17.         }  
  18.   
  19.         static readonly HandParams secondParams = new HandParams(0.02, 1.1, 0.85);  
  20.         static readonly HandParams minuteParams = new HandParams(0.05, 0.8, 0.9);  
  21.         static readonly HandParams hourParams = new HandParams(0.125, 0.65, 0.9);  
  22.   
  23.         BoxView[] tickMarks = new BoxView[60];  
  24.   
  25.         public MainPage()  
  26.         {  
  27.             InitializeComponent();  
  28.             // Create the tick marks (to be sized and positioned later).  
  29.             for (int i = 0; i < tickMarks.Length; i++)  
  30.             {  
  31.                 tickMarks[i] = new BoxView { Color = Color.Black };  
  32.                 absoluteLayout.Children.Add(tickMarks[i]);  
  33.             }  
  34.   
  35.             Device.StartTimer(TimeSpan.FromSeconds(1.0 / 60), OnTimerTick);  
  36.         }  
  37.         void OnAbsoluteLayoutSizeChanged(object sender, EventArgs args)  
  38.         {  
  39.             // Get the center and radius of the AbsoluteLayout.  
  40.             Point center = new Point(absoluteLayout.Width / 2, absoluteLayout.Height / 2);  
  41.             double radius = 0.45 * Math.Min(absoluteLayout.Width, absoluteLayout.Height);  
  42.   
  43.             // Position, size, and rotate the 60 tick marks.  
  44.             for (int index = 0; index < tickMarks.Length; index++)  
  45.             {  
  46.                 double size = radius / (index % 5 == 0 ? 15 : 30);  
  47.                 double radians = index * 2 * Math.PI / tickMarks.Length;  
  48.                 double x = center.X + radius * Math.Sin(radians) - size / 2;  
  49.                 double y = center.Y - radius * Math.Cos(radians) - size / 2;  
  50.                 AbsoluteLayout.SetLayoutBounds(tickMarks[index], new Rectangle(x, y, size, size));  
  51.                 tickMarks[index].Rotation = 180 * radians / Math.PI;  
  52.             }  
  53.   
  54.             // Position and size the three hands.  
  55.             LayoutHand(secondHand, secondParams, center, radius);  
  56.             LayoutHand(minuteHand, minuteParams, center, radius);  
  57.             LayoutHand(hourHand, hourParams, center, radius);  
  58.         }  
  59.   
  60.         void LayoutHand(BoxView boxView, HandParams handParams, Point center, double radius)  
  61.         {  
  62.             double width = handParams.Width * radius;  
  63.             double height = handParams.Height * radius;  
  64.             double offset = handParams.Offset;  
  65.   
  66.             AbsoluteLayout.SetLayoutBounds(boxView,  
  67.                 new Rectangle(center.X - 0.5 * width,  
  68.                               center.Y - offset * height,  
  69.                               width, height));  
  70.   
  71.             // Set the AnchorY property for rotations.  
  72.             boxView.AnchorY = handParams.Offset;  
  73.         }  
  74.   
  75.         bool OnTimerTick()  
  76.         {  
  77.             // Set rotation angles for hour and minute hands.  
  78.             DateTime dateTime = DateTime.Now;  
  79.             hourHand.Rotation = 30 * (dateTime.Hour % 12) + 0.5 * dateTime.Minute;  
  80.             minuteHand.Rotation = 6 * dateTime.Minute + 0.1 * dateTime.Second;  
  81.   
  82.             // Do an animation for the second hand.  
  83.             double t = dateTime.Millisecond / 1000.0;  
  84.   
  85.             if (t < 0.5)  
  86.             {  
  87.                 t = 0.5 * Easing.SpringIn.Ease(t / 0.5);  
  88.             }  
  89.             else  
  90.             {  
  91.                 t = 0.5 * (1 + Easing.SpringOut.Ease((t - 0.5) / 0.5));  
  92.             }  
  93.   
  94.             secondHand.Rotation = 6 * (dateTime.Second + t);  
  95.             return true;  
  96.         }  
  97.   
  98.     }  
  99.   
  100. }  
Step 4

Press F5 or Build and Run the application.

Output



Finally, we have successfully created a Xamarin.Forms BoxView Clock app.