2017-11-10 17:57:45 +00:00
|
|
|
|
using System;
|
|
|
|
|
using Xamarin.Forms;
|
|
|
|
|
|
|
|
|
|
namespace Samples
|
|
|
|
|
{
|
|
|
|
|
public class BoxViewClockSample : ISample
|
|
|
|
|
{
|
|
|
|
|
public string Title => "Xamarin.Forms BoxViewClock";
|
|
|
|
|
|
2017-11-10 18:14:28 +00:00
|
|
|
|
BoxViewClockPage page;
|
|
|
|
|
|
2017-11-10 17:57:45 +00:00
|
|
|
|
public Ooui.Element CreateElement ()
|
|
|
|
|
{
|
2017-11-10 18:14:28 +00:00
|
|
|
|
//
|
|
|
|
|
// Always return the same page because the code never stops the timer
|
|
|
|
|
// and we don't want to create an unlimited number of them.
|
|
|
|
|
//
|
|
|
|
|
if (page == null)
|
|
|
|
|
page = new BoxViewClockPage ();
|
|
|
|
|
return page.GetOouiElement ();
|
2017-11-10 17:57:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class BoxViewClockPage : 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);
|
|
|
|
|
|
|
|
|
|
BoxView[] tickMarks = new BoxView[60];
|
|
|
|
|
BoxView secondHand, minuteHand, hourHand;
|
|
|
|
|
|
|
|
|
|
public BoxViewClockPage ()
|
|
|
|
|
{
|
|
|
|
|
AbsoluteLayout absoluteLayout = new AbsoluteLayout ();
|
|
|
|
|
|
|
|
|
|
// Create the tick marks (to be sized and positioned later)
|
|
|
|
|
for (int i = 0; i < tickMarks.Length; i++) {
|
|
|
|
|
tickMarks[i] = new BoxView {
|
|
|
|
|
Color = Color.Accent
|
|
|
|
|
};
|
|
|
|
|
absoluteLayout.Children.Add (tickMarks[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create the three hands.
|
|
|
|
|
absoluteLayout.Children.Add (hourHand =
|
|
|
|
|
new BoxView {
|
|
|
|
|
Color = Color.Accent
|
|
|
|
|
});
|
|
|
|
|
absoluteLayout.Children.Add (minuteHand =
|
|
|
|
|
new BoxView {
|
|
|
|
|
Color = Color.Accent
|
|
|
|
|
});
|
|
|
|
|
absoluteLayout.Children.Add (secondHand =
|
|
|
|
|
new BoxView {
|
|
|
|
|
Color = Color.Accent
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Content = absoluteLayout;
|
|
|
|
|
|
|
|
|
|
// Attach a couple event handlers.
|
|
|
|
|
Device.StartTimer (TimeSpan.FromMilliseconds (16), OnTimerTick);
|
|
|
|
|
SizeChanged += OnPageSizeChanged;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnPageSizeChanged (object sender, EventArgs args)
|
|
|
|
|
{
|
|
|
|
|
// Size and position the 12 tick marks.
|
|
|
|
|
Point center = new Point (this.Width / 2, this.Height / 2);
|
|
|
|
|
double radius = 0.45 * Math.Min (this.Width, this.Height);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < tickMarks.Length; i++) {
|
|
|
|
|
double size = radius / (i % 5 == 0 ? 15 : 30);
|
|
|
|
|
double radians = i * 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[i], new Rectangle (x, y, size, size));
|
|
|
|
|
|
|
|
|
|
tickMarks[i].AnchorX = 0.51; // Anchor settings necessary for Android
|
|
|
|
|
tickMarks[i].AnchorY = 0.51;
|
|
|
|
|
tickMarks[i].Rotation = 180 * radians / Math.PI;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Function for positioning and sizing hands.
|
|
|
|
|
Action<BoxView, HandParams> Layout = (boxView, handParams) => {
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
|
|
boxView.AnchorX = 0.51;
|
|
|
|
|
boxView.AnchorY = handParams.Offset;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Layout (secondHand, secondParams);
|
|
|
|
|
Layout (minuteHand, minuteParams);
|
|
|
|
|
Layout (hourHand, hourParams);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|