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

Press F5 or Build and Run the application.

Output



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