Introduction to SkiaSharp
- SkiaSharp is a cross-platform 2D graphics API for .NET platforms.
- SkiaSharp Views & Layers is a set of platform-specific Views and Containers that can be used to draw on the screen and it's used in Google Chrome, Mozilla Firefox, and Android devices.
- Binding for Windows.Forms, WPF, iOS, tvOS, Mac, Android, Xamarin.Android and Xamarin.Forms and it can be used across mobile, server, and desktop models to render the images.
- Skia Graphics Engine was acquired by Google in 2005 and it's an open source package.
More details:
github.com/mono/skiasharpNuGet Package : Xamarin.Android -->search "SkiaSharp"
Xamarin.Forms -->search"SkiaSharp.Views.Forms"
Properties of SkiaSharp
- SKcanvas.
- SKGLView.
- SKPaint.
- SKPath.
- SKShader.
- SKPathEffect .
Now, let us discuss the attributes of SkiaSharp properties.
Drawing on SKcanvas
The SKcanvas is used for drawing models, lines, arcs, text, and images.
Drawing Methods of SKcanvas
- DrawCircle.
- DrawRect.
- DrawLine.
- DrawText.
- DrawBitmap.
- DrawPath.
Transforms for SKcanvas
- Translate.
- Scale.
- RotateDegrees.
- RotateRadians.
Drawing attributes for SKPaint
- Style: Storke, Fill, or both.
- Color: SKColor value.
- StrokeWidth.
- StrokeCap: Butt, Square, or Round.
- Strokejoin: Miter, Bevel, or Round.
- Shader: gradients or bitmap tilling.
SKPath --> Connected lines and curves
- MoveTo and LineTo.
- ArcTo: Three kinds of arc definitions.
- CubicTo and QuadTo: Bezier.
- SVG path date in and out.
SKShader --> Fancy filles
- CreateLinearGradient.
- CreateRadialGradient.
- CreateSweepGradient.
- CreateTwoPointConicalGradient.
- CreatePerlinNoise.
- CreateBitmap: Tile with SKBitmap.
SKPathEffects -->fancy strokes
- CreateDash.
- Create1DPathof: Dashed with another path.
- Create2DPath: Storked with an array of another path.
- CreateDiscrete: Jitter effect.
The below article contains just a few but many different things can be done by catclock with SkiaSharp.
Let's start.
Step 1
You can get started with a new Xamarin.Forms app by going to File >>New >>Visual C#>>Cross-platform >>select Cross-platform App(Xamarin.Native or Xamarin.Forms) and give the application a suitable name, such as CatClock. Choose your project location, then click OK.
Step 2
In this step, add the following NuGet Packages for your project.
- SkiaSharp
- SkiaSharp.Views
- SkiaSharp.Views.Forms
For that, go to Solution Explorer and select your solution, right click and select "Manage NuGet Packages for the solution".
Now, select the following NuGet package and install it.
- SkiaSharp.Views.Forms
Step 3
In this step, add a SkiaSharp control to your projects. For that, go to Solution Explorer >>catclock(PCL)>> double click on MainPage.xaml.
After opening this, you can add SkiaSharp assembly and XAML code to your project. Write the code given below.
Assembly
- xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
XAML Code
- <?xml version="1.0" encoding="utf-8" ?>
- <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
- xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
- xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
- xmlns:local="clr-namespace:CatClock"
- x:Class="CatClock.MainPage">
- <ContentPage.Padding>
- <OnPlatform x:TypeArguments="Thickness"
- iOS="0, 20, 0, 0" />
- </ContentPage.Padding>
-
- <skia:SKCanvasView x:Name="canvasView"
- PaintSurface="canvasView_PaintSurface" />
- </ContentPage>
Step 4
Now, we need to add a picture for background display. For that, go to Solution Explorer >> Add >> Existing item >> select one picture and click OK.
After this, let's change the picture properties to embedded resource. For that, go to Properties window >> Advanced >> Build Action>>select Embedded Resource.
Step 5
In this step, open Solution Explorer>>catclock(PCL)>>Mainpage.xaml.cs page and double-click to open the design view. Here is the code for this page.
CS code
- using System;
- using System.IO;
- using System.Reflection;
- using Xamarin.Forms;
- using SkiaSharp;
- using SkiaSharp.Views.Forms;
-
- namespace CatClock
- {
- public partial class MainPage : ContentPage
- {
- SKPaint blackFillPaint = new SKPaint
- {
- Style = SKPaintStyle.Fill,
- Color = SKColors.Black
- };
-
- SKPaint whiteStrokePaint = new SKPaint
- {
- Style = SKPaintStyle.Stroke,
- Color = SKColors.White,
- StrokeWidth = 2,
- StrokeCap = SKStrokeCap.Round,
- IsAntialias = true
- };
-
- SKPaint whiteFillPaint = new SKPaint
- {
- Style = SKPaintStyle.Fill,
- Color = SKColors.White
- };
-
- SKPaint greenFillPaint = new SKPaint
- {
- Style = SKPaintStyle.Fill,
- Color = SKColors.PaleGreen
- };
-
- SKPaint blackStrokePaint = new SKPaint
- {
- Style = SKPaintStyle.Stroke,
- Color = SKColors.Black,
- StrokeWidth = 20,
- StrokeCap = SKStrokeCap.Round
- };
-
- SKPaint grayFillPaint = new SKPaint
- {
- Style = SKPaintStyle.Fill,
- Color = SKColors.Gray
- };
-
- SKPaint backgroundFillPaint = new SKPaint
- {
- Style = SKPaintStyle.Fill
- };
-
- SKPath catEarPath = new SKPath();
- SKPath catEyePath = new SKPath();
- SKPath catPupilPath = new SKPath();
- SKPath catTailPath = new SKPath();
-
- SKPath hourHandPath = SKPath.ParseSvgPathData(
- "M 0 -60 C 0 -30 20 -30 5 -20 L 5 0 C 5 7.5 -5 7.5 -5 0 L -5 -20 C -20 -30 0 -30 0 -60");
- SKPath minuteHandPath = SKPath.ParseSvgPathData(
- "M 0 -80 C 0 -75 0 -70 2.5 -60 L 2.5 0 C 2.5 5 -2.5 5 -2.5 0 L -2.5 -60 C 0 -70 0 -75 0 -80");
-
- public MainPage()
- {
- InitializeComponent();
-
-
- catEarPath.MoveTo(0, 0);
- catEarPath.LineTo(0, 75);
- catEarPath.LineTo(100, 75);
- catEarPath.Close();
-
-
- catEyePath.MoveTo(0, 0);
- catEyePath.ArcTo(50, 50, 0, SKPathArcSize.Small, SKPathDirection.Clockwise, 50, 0);
- catEyePath.ArcTo(50, 50, 0, SKPathArcSize.Small, SKPathDirection.Clockwise, 0, 0);
- catEyePath.Close();
-
-
- catPupilPath.MoveTo(25, -5);
- catPupilPath.ArcTo(6, 6, 0, SKPathArcSize.Small, SKPathDirection.Clockwise, 25, 5);
- catPupilPath.ArcTo(6, 6, 0, SKPathArcSize.Small, SKPathDirection.Clockwise, 25, -5);
- catPupilPath.Close();
-
-
- catTailPath.MoveTo(0, 100);
- catTailPath.CubicTo(50, 200, 0, 250, -50, 200);
-
-
- Assembly assembly = GetType().GetTypeInfo().Assembly;
- using (Stream stream = assembly.GetManifestResourceStream("CatClock.WoodGrain.png"))
- using (SKManagedStream skStream = new SKManagedStream(stream))
- using (SKBitmap bitmap = SKBitmap.Decode(skStream))
- using (SKShader shader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Mirror, SKShaderTileMode.Mirror))
- {
- backgroundFillPaint.Shader = shader;
- }
-
- Device.StartTimer(TimeSpan.FromSeconds(1f / 60), () =>
- {
- canvasView.InvalidateSurface();
- return true;
- });
- }
-
- private void canvasView_PaintSurface(object sender, SKPaintSurfaceEventArgs e)
- {
- SKSurface surface = e.Surface;
- SKCanvas canvas = surface.Canvas;
-
- canvas.DrawPaint(backgroundFillPaint);
-
- int width = e.Info.Width;
- int height = e.Info.Height;
-
-
- canvas.Translate(width / 2, height / 2);
- canvas.Scale(Math.Min(width / 210f, height / 520f));
-
-
- DateTime dateTime = DateTime.Now;
-
-
- canvas.DrawCircle(0, -160, 75, blackFillPaint);
-
-
- for (int i = 0; i < 2; i++)
- {
- canvas.Save();
- canvas.Scale(2 * i - 1, 1);
-
- canvas.Save();
- canvas.Translate(-65, -255);
- canvas.DrawPath(catEarPath, blackFillPaint);
- canvas.Restore();
-
- canvas.Save();
- canvas.Translate(10, -170);
- canvas.DrawPath(catEyePath, greenFillPaint);
- canvas.DrawPath(catPupilPath, blackFillPaint);
- canvas.Restore();
-
-
- canvas.DrawLine(10, -120, 100, -100, whiteStrokePaint);
- canvas.DrawLine(10, -125, 100, -120, whiteStrokePaint);
- canvas.DrawLine(10, -130, 100, -140, whiteStrokePaint);
- canvas.DrawLine(10, -135, 100, -160, whiteStrokePaint);
-
- canvas.Restore();
- }
-
-
- float t = (float)Math.Sin((dateTime.Second % 2 + dateTime.Millisecond / 1000.0) * Math.PI);
- catTailPath.Reset();
- catTailPath.MoveTo(0, 100);
- SKPoint point1 = new SKPoint(-50 * t, 200);
- SKPoint point2 = new SKPoint(0, 250 - Math.Abs(50 * t));
- SKPoint point3 = new SKPoint(50 * t, 250 - Math.Abs(75 * t));
- catTailPath.CubicTo(point1, point2, point3);
-
- canvas.DrawPath(catTailPath, blackStrokePaint);
-
-
- canvas.DrawCircle(0, 0, 100, blackFillPaint);
-
-
- for (int angle = 0; angle < 360; angle += 6)
- {
- canvas.DrawCircle(0, -90, angle % 30 == 0 ? 4 : 2, whiteFillPaint);
- canvas.RotateDegrees(6);
- }
-
-
- canvas.Save();
- canvas.RotateDegrees(30 * dateTime.Hour + dateTime.Minute / 2f);
- canvas.DrawPath(hourHandPath, grayFillPaint);
- canvas.DrawPath(hourHandPath, whiteStrokePaint);
- canvas.Restore();
-
-
- canvas.Save();
- canvas.RotateDegrees(6 * dateTime.Minute + dateTime.Second / 10f);
- canvas.DrawPath(minuteHandPath, grayFillPaint);
- canvas.DrawPath(minuteHandPath, whiteStrokePaint);
- canvas.Restore();
-
-
- canvas.Save();
- float seconds = dateTime.Second + dateTime.Millisecond / 1000f;
- canvas.RotateDegrees(6 * seconds);
- whiteStrokePaint.StrokeWidth = 2;
- canvas.DrawLine(0, 10, 0, -80, whiteStrokePaint);
- canvas.Restore();
- }
- }
- }
Step 6
Now, go to "Build" menu and click "Configure Manager". Here, you can configure your startup projects. Click F5 or Start to build and run your application.
After a few seconds, the app will start running on your Android simulators and you will see your app working successfully.
Finally, we have successfully created a Xamarin.Forms catclock with SkiaSharp application.
Conclusion
I hope you have learned how to design cat clock application using Visual Studio.