Skip to content

Instantly share code, notes, and snippets.

@benoitjadinon
Last active October 7, 2020 04:48
Show Gist options
  • Select an option

  • Save benoitjadinon/c0055013da4f256917ad7f538c1fcbff to your computer and use it in GitHub Desktop.

Select an option

Save benoitjadinon/c0055013da4f256917ad7f538c1fcbff to your computer and use it in GitHub Desktop.
SkiaSharp Xamarin Coach Marks Overlay
using System.Collections.Generic;
using System.Drawing;
using SkiaSharp;
#if __IOS__
using SkiaSharp.Views.iOS;
using UIKit;
#elif __ANDROID__
using SkiaSharp.Views.Android;
#endif
namespace some
{
public class CoachMarks : ICoachMarks
{
private List<CoachMark> Marks { get; } = new List<CoachMark>();
SKPaint paint = new SKPaint {
IsAntialias = true,
Color = 0xFF0000FF,
Style = SKPaintStyle.Fill,
};
SKPaint bgPaint = new SKPaint {
IsAntialias = false,
Color = 0xAA000000,
Style = SKPaintStyle.Fill,
};
private SKPaint textPaint = new SKPaint
{
IsAntialias = true,
Color = 0xFF00FF00,
TextSize = 40,
FakeBoldText = true
//Typeface =
};
private SKCanvasView skiaCanvasView = null;
public ICoachMarks Add(RectangleF rect, string text, CoachMarkPosition textPosition = null)
{
this.Marks.Add(new CoachMark(rect, text, textPosition));
ReDraw();
return this;
}
public ICoachMarks Create()
{
Marks.Clear();
#if __IOS__
if (skiaCanvasView == null)
{
skiaCanvasView = new SKCanvasView(UIApplication.SharedApplication.KeyWindow.Bounds);
skiaCanvasView.BackgroundColor = UIColor.Clear;
skiaCanvasView.Opaque = false;
UIApplication.SharedApplication.KeyWindow.AddSubview(skiaCanvasView);
skiaCanvasView.FillParent();
skiaCanvasView.UserInteractionEnabled = true;
skiaCanvasView.AddGestureRecognizer (new UITapGestureRecognizer(skiaCanvasView.RemoveFromSuperview));
skiaCanvasView.PaintSurface += (sender, e) =>
{
var canvas = e.Surface.Canvas;
var size = e.Info.Size;
Draw(canvas, size, (float)skiaCanvasView.ContentScaleFactor);
};
}
#elif __ANDROID__
//TODO
#endif
ReDraw();
return this;
}
private void ReDraw()
{
#if __IOS__
skiaCanvasView.SetNeedsDisplay();
#elif __ANDROID__
skiaCanvasView.Invalidate();
#endif
}
private void Draw(SKCanvas canvas, SKSize size, float scale = 1)
{
canvas.Clear();
// clipping
foreach (var mark in Marks)
{
var pos = mark.Pos.Scale(scale);
canvas.ClipRect(new SKRect(pos.Left, pos.Top, pos.Right, pos.Bottom), SKClipOperation.Difference);
}
// clipping reset
canvas.ResetMatrix();
// background
canvas.DrawRect(0, 0, size.Width, size.Height, bgPaint);
// mark texts
foreach (var mark in this.Marks)
{
var pos = mark.Pos.Scale(scale);
if (mark.TextPosition.V == -1)
canvas.DrawText(mark.Text, pos.X, pos.Y, textPaint);
else if (mark.TextPosition.V == 0)
canvas.DrawText(mark.Text, pos.X, pos.Y + pos.Height, textPaint);
else if (mark.TextPosition.V == +1)
{
SKFontMetrics metrics;
textPaint.GetFontMetrics(out metrics, scale);
canvas.DrawText(mark.Text, pos.X, pos.Y + pos.Height + metrics.XHeight, textPaint);
}
}
}
private class CoachMark
{
public RectangleF Pos { get; }
public string Text { get; }
public CoachMarkPosition TextPosition { get; }
public CoachMark(RectangleF pos, string text, CoachMarkPosition textPosition = null)
{
Pos = pos;
Text = text;
TextPosition = textPosition ?? CoachMarkPosition.Below;
}
}
}
}
@benoitjadinon
Copy link
Copy Markdown
Author

benoitjadinon commented Aug 10, 2018

_coachMarks
            .Create()
            .Add(passButton, "press meeeee!", CoachMarkPosition.Above)
            .Add(forgotPasswordButton, "u forgot bro?")
            ;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment