Xamarin forms Dotted Cirlce using Skia Sharp - xamarin

How can we create a dotted circle in xamarin forms using Skia Sharp, i had tried many but i could not make it happen can some one help me with this.
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = Color.Red.ToSKColor(),
StrokeWidth = 10
};
canvas.DrawCircle(info.Width / 3, info.Height / 2, 100, paint);

You are pretty close. You just need to understand what you are doing. Are you setting the Constructor of your page correctly? You have to
Create an instance of SKCanvasView and add it to the Content of your page.
So assuming that the name of your class or page is SimpleCirclePage.cs, you need to add this inside it, along with other items.
Add an event handler to the PaintSurface event of your SKCanvasView instance.
The constructor
public SimpleCirclePage()
{
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
The Event Handler
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
// Creating the Outline of the circle with Black
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = Color.Black.ToSKColor(),
StrokeWidth = 22
};
canvas.DrawCircle(info.Width / 2, info.Height / 2, 100, paint);
// Filling the circle with red
paint.Style = SKPaintStyle.Fill;
paint.Color = SKColors.Red;
canvas.DrawCircle(info.Width / 2, info.Height / 2, 100, paint);
}

Related

Skia / SkiaSharp - Rotating shapes around their own vertical axis

I generate the scene above using the OnDraw method below:
protected override void OnDraw(SKCanvas canvas, int width, int height)
{
int i = 0;
int step = 0;
List<SKRect> rects = new List<SKRect>();
// get the 2D equivalent of the 3D matrix
var rotationMatrix = rotationView.Matrix;
// get the properties of the rectangle
var length = Math.Min(width / 6, height / 6);
canvas.Clear(EffectMedia.Colors.XamarinLightBlue);
foreach (var n in numbers)
{
var rect = new SKRect(0 + step, 0, 100 + step, 100);
rects.Add(rect);
step += 120;
}
//var sideHoriz = rotationMatrix.MapPoint(new SKPoint(0, 1)).Y > 0;
var sideVert = rotationMatrix.MapPoint(new SKPoint(1, 0)).X > 0;
var paint = new SKPaint
{
Color = sideVert ? EffectMedia.Colors.XamarinPurple : EffectMedia.Colors.XamarinGreen,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
// first do 2D translation to the center of the screen
canvas.Translate((width - (120 * numbers.Count)) / 2, height / 2);
// The following line is disabled because it makes the whole canvas rotate!
// canvas.Concat(ref rotationMatrix);
foreach (var n in numbers)
{
canvas.RotateDegrees((float)-3);
canvas.DrawRoundRect(rects[i], 30, 30, paint);
var shadow = SKShader.CreateLinearGradient(
new SKPoint(0, 0), new SKPoint(0, length * 2),
new[] { paint.Color.WithAlpha(127), paint.Color.WithAlpha(0) },
null,
SKShaderTileMode.Clamp);
var paintShadow = new SKPaint
{
Shader = shadow,
Style = SKPaintStyle.Fill,
IsAntialias = true,
BlendMode = SKBlendMode.SoftLight
};
foreach (var r in rects)
{
r.Offset(0, 105);
canvas.DrawRoundRect(r, 30, 30, paintShadow);
}
i++;
}
}
The idea is to make all those rounded boxes rotate (vertically) around their own axis.
I tried using SKPath + Transform, saving&restoring the rotationMatrix and/or the canvas but I can't find a way to have 6 rotating boxes ( canvas.Concat(ref rotationMatrix); makes the whole canvas rotate [*]).
Do you have any hint on how that can be achieved?
Note [*]: there's a call to rotationView.RotateYDegrees(5) every X milliseconds to update the rotationMatrix used by OnDraw.
This is what I'd like to achieve, any hints / directions would be really appreciated... :-)
The following piece of code rotates those shapes around their Z-axis:
canvas.Save();
canvas.RotateDegrees(degrees, rects[i].MidX, rects[i].MidY);
canvas.DrawRoundRect(rects[i], 30, 30, paint);
canvas.Restore();
Thanks

Skiasharp text rendering off canvas

I'm creating a custom control with skiasharp and xamarin forms. Something I've run into is when I try draw text in the top left corner of my canvas I have to offset the y co ord in order for the text to render within the canvas. I'd expect the x y co ord of the text to be in the same position as the x y co ord of the rect. What am I missing?
Using Skiasharp.View.Forms - v1.68.1 off nuget
Thanks!
protected override void OnPaintSurface(SKPaintSurfaceEventArgs args)
{
base.OnPaintSurface(args);
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
canvas.Save();
using var paint = new SKPaint {IsAntialias = true, Color = Color.Black.ToSKColor(), Style = SKPaintStyle.Stroke};
canvas.DrawRect(0, 0, info.Width, info.Height, paint);
canvas.DrawText("Off screen", 0, 0, paint);
canvas.DrawText("On screen", 0, 10, paint);
canvas.Restore();
}
You could set y coordinate as SKPaint.FontSpacing , it is the recommend line spacing.
canvas.DrawText("SKCanvasView Height and Width:", 0, paint.FontSpacing, paint);
Refer https://github.com/xamarin/xamarin-forms-samples/blob/f7cc661331b5db605e64e7efe83ef2b9fc644afb/SkiaSharpForms/Demos/Demos/SkiaSharpFormsDemos/Basics/SurfaceSizePage.cs#L38

Mask image in Xamarin Forms Android and iOS

I want to mask an image like the sample below:
I tried using the FFImageLoading Transformation, but I couldn't get the triangle shape that is in the image shown.
Also, I cannot do the trick of putting the background white, because I want to achieve this final result:
Is there any way to get the pixels of the triangle shape that are not in alpha, and convert them to the squared image pixels?
I tried this code from SkiaSharp changing the values of the SKPath, but this complicates more my problem because it is not an image, is a canvas:
public class MonkeyThroughKeyholePage : ContentPage
{
SKBitmap bitmap;
SKPath keyholePath = SKPath.ParseSvgPathData(
"M 200 130 L 250 300 L 250 300 L 300 130 A 70 70 20 1 20 300 130 Z");
public MonkeyThroughKeyholePage()
{
Title = "Monkey through Keyhole";
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
string resourceID = "SkiaSharpFormsDemos.Media.SeatedMonkey.jpg";
Assembly assembly = GetType().GetTypeInfo().Assembly;
using (Stream stream = assembly.GetManifestResourceStream(resourceID))
using (SKManagedStream skStream = new SKManagedStream(stream))
{
bitmap = SKBitmap.Decode(skStream);
}
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
// Set transform to center and enlarge clip path to window height
SKRect bounds;
keyholePath.GetTightBounds(out bounds);
canvas.Translate(info.Width / 2, info.Height / 2);
canvas.Scale(0.98f * info.Height / bounds.Height);
canvas.Translate(-bounds.MidX, -bounds.MidY);
// canvas.RotateDegrees(15f);
// Set the clip path
canvas.ClipPath(keyholePath);
// Reset transforms
canvas.ResetMatrix();
canvas.DrawBitmap(bitmap,
new SKRect((info.Width - info.Height) / 2, 0,
(info.Width + info.Height) / 2, info.Height));
}
}

ViewCell - image fill, text on bottom

The layout i want is like this: http://imgur.com/etb9ZKZ
I want the image (illustrated with the color green) to fill the entire layoutcontol. On top of image positioned at the bottom with full width i want a textbox/label to put a title. The title view should have a black semi-transparent background.
This is the best i've got (the code below), but it has a few issues:
#1 - The text doesnt wrap like it is suppose to. It just cuts the sentence, like the rest is going off screen.
#2 - The image doesnt scale to the width of the container.
Label lblTitle = new Label()
{
BackgroundColor = new Color(0, 0, 0, 0.8),
LineBreakMode = LineBreakMode.WordWrap,
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
};
lblTitle.SetBinding(Label.TextProperty, "headline");
Image imgBanner = new Image()
{
/*
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.End,
Aspect = Aspect.Fill
*/
};
imgBanner.SetBinding(Image.SourceProperty, "ImageUrlSource");
AbsoluteLayout.SetLayoutFlags(lblTitle, AbsoluteLayoutFlags.PositionProportional | AbsoluteLayoutFlags.WidthProportional);
AbsoluteLayout.SetLayoutBounds(lblTitle, new Rectangle(0, 1, 1, AbsoluteLayout.AutoSize));
AbsoluteLayout.SetLayoutFlags(imgBanner, AbsoluteLayoutFlags.SizeProportional);
AbsoluteLayout.SetLayoutBounds(imgBanner, new Rectangle(0, 0, 1, 1));
AbsoluteLayout layout = new AbsoluteLayout()
{
HorizontalOptions = LayoutOptions.Fill,
Children =
{
imgBanner,
lblTitle
}
};
View = layout;
You should use Grid instead.
Label lblTitle = new Label()
{
BackgroundColor = new Color(0, 0, 0, 0.8),
LineBreakMode = LineBreakMode.WordWrap,
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
};
lblTitle.SetBinding(Label.TextProperty, "headline");
Image imgBanner = new Image()
{
/*
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.End,
Aspect = Aspect.Fill
*/
};
imgBanner.SetBinding(Image.SourceProperty, "ImageUrlSource");
//=========== Addition Start Here ============//
Grid grid = new Grid();
grid.RowDefinitions =
{
new RowDefinition{ Height=new GridLength(200,GridUnitType.Absolute) },
new RowDefinition{ Height=new GridLength(30,GridUnitType.Absolute},
}
grid.Children.Add(imgBanner,0,1,0,2); //two rowspan
// == .Add(imgBanner,column,column+columnspan,row,row+rowspan)
grid.Children.Add(lblTitle,0,1,1,2); //one rowspan
View = grid;

How to set 3 components in one Horizontal field without adjusting editfield width

HorizontalFieldManager hfm = new HorizontalFieldManager();
this.add(hfm);
LabelField lblheight = new LabelField("Height");
EditField lField = new EditField() {
protected void layout(int width, int height) {
super.layout(width, height);
this.setExtent(200, this.getHeight());
}
public int getPreferredWidth() {
return 200;
}
};
Background editFieldBackground = BackgroundFactory
.createSolidBackground(0X00F7F7FF);
XYEdges edges = new XYEdges(5, 5, 5, 5);
Border border = BorderFactory.createRoundedBorder(edges, 0X00D6DBDE,
Border.STYLE_FILLED);
Bitmap switchOn = Bitmap.getBitmapResource("switch_left.png");
Bitmap switchOff = Bitmap.getBitmapResource("switch_right.png");
Bitmap switchOnFocus = Bitmap
.getBitmapResource("switch_left_focus.png");
Bitmap switchOffFocus = Bitmap
.getBitmapResource("switch_right_focus.png");
SwitchField sw = new SwitchField(switchOn, switchOff, switchOnFocus,
switchOffFocus, true);
lField.setBackground(editFieldBackground);
lField.setBorder(border);
hfm.add(lblheight);
hfm.add(lField);
hfm.add(sw);
I used the above code for setting 3 components in one horizontal field manager, but my issue is that here I set the width for the edittext.
So, is there any other option to display 3 components in the proper manner on all devices, without adjusting the width of the edittext?

Resources