SVG in Xamarin Forms

Drawing using Xamarin Forms cross platform wasn’t an easy task till date until the SkiaSharp library was released,thanks to mattleibow who is the contributor of Skiasharp public repo . I thought of writing an early blog about “How to use SkiaSharp in Cross Platform” but i could see a lot of  basic things has been covered in the Charles petzold blog and Xamarin Forms e-book. So in this blog i will be covering the usage of SkiaSharp library to render SVG in Xamarin Forms cross platform solution using PCL.

Agenda

We will be creating a simple xamarin forms project targeting  Android , iOS which will intent to show ListView with svg images loaded inside a custom SVGCanvas control in each record.

Pre-requisites

  • Knowledge about Xamarin Forms  & PCL
  • Basic understanding of what is SVG
  • How to use SkiaSharp nuget to the solution.

Create a Xamarin.Forms project

Create a Xamarin.Forms project with a name of your choice and add the below mentioned nuget packages:

  1. SkiaSharp – PCL & Platforms project
  2. SkiaSharp.Svg – PCL & Platforms project
  3. SkiaSharp.Views.Forms – PCL & Platforms project.

Now we will add a Grid and ListView to the MainPage.Xaml and start doing the screen design so that the screen will be partitioned as per the need.

MainPage.Xaml

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height=”*”/>
</Grid.RowDefinitions>
<ListView RowHeight=”80″ x:Name=”listView”  ItemsSource=”{Binding ListItems,                                                                 Mode=TwoWay}”>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame BackgroundColor=”Transparent” x:Name=”frame”>
< Grid>
<Grid.RowDefinitions>
<RowDefinition Height=”2″/>
<RowDefinition Height=”*”/>
<RowDefinition Height=”2″/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”5″/>
<ColumnDefinition Width=”Auto”/>
<ColumnDefinition Width=”2″/>
<ColumnDefinition Width=”*”/>
<ColumnDefinition Width=”5″/>
</Grid.ColumnDefinitions>

                     <Label Grid.Row=”1″ Grid.Column=”3″ Text=”{Binding Imagename}”/>                                    <controls:CustomSkCanvasView
behavior:SkCanvasBehavoir.ImageSource=”{Binding                                                                    BindingContext.Imagename,
Source={x:Reference frame} }”
IndexSource=”{Binding Index}”
Grid.Row=”1″
Grid.Column=”1″>
<controls:CustomSkCanvasView.Behaviors>
<behavior:SkCanvasBehavoir/>
</controls:CustomSkCanvasView.Behaviors>
</controls:CustomSkCanvasView>

             </Grid>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>

Now we need to add a behavior for CustomSKCanvasView, which is nothing but a  exteneded SkCanvas with additional Bindable property for future use. The behavior will be responsible for rendering the image in the available pixels.

SkCanvasBehavior:

public class SkCanvasBehavoir : Behavior<CustomSkCanvasView>
{
private CustomSkCanvasView view;

public static readonly BindableProperty ImageSourceProperty =
BindableProperty.Create(“ImageSource”, typeof(string), typeof(CustomSkCanvasView), string.Empty,
BindingMode.OneWay, null, OnImageSourcePropertyChanged, null, null, null);

private static void OnImageSourcePropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var customskCanview = bindable as CustomSkCanvasView;
if (!string.IsNullOrEmpty(newValue.ToString()))
{
customskCanview.ImageSource = newValue.ToString();
customskCanview.LoadSvg(newValue.ToString());
}
}

public string ImageSource
{
get { return (string) GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}

protected override void OnAttachedTo(CustomSkCanvasView bindable)
{
base.OnAttachedTo(bindable);
view = bindable;
view.PaintSurface += View_PaintSurface;
}

private void View_PaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
var surface = e.Surface;
var canvas = surface.Canvas;

var width = e.Info.Width;
var height = e.Info.Height;

var cacheValue = TryGetCache(view.ImageSource);
if (cacheValue != null)
{
canvas.Clear(SKColors.Transparent);
canvas.DrawPicture(cacheValue.Picture, ref cacheValue.Matrix);
return;
}

// clear the surface
canvas.Clear(SKColors.Transparent);

// the page is not visible yet
if (view.SvgView == null)
return;

// calculate the scaling need to fit to screen
float canvasMin = Math.Min(width, height);
float svgMax = Math.Max(view.SvgView.Picture.CullRect.Width, view.SvgView.Picture.CullRect.Height);
float scale = canvasMin / svgMax;
var matrix = SKMatrix.MakeScale(scale, scale);

// draw the svg
canvas.DrawPicture(view.SvgView.Picture, ref matrix);
AddCache(view.ImageSource, new SVGCache() {Matrix = matrix, Picture = view.SvgView.Picture});
}

In the above code snippet we have handled the PaintSurface event of SkCanvas where we wiil calculate the size of the SVG image to be drawn from the SkCanvas Height & Width. In this sample i have used 4 SVG downloaded form the Google Material design site which you can make use of it. Now the page should be loaded with some sample data :

MainPage.Xaml.cs:

private IList<ModelWrapper> listItems;

public IList<ModelWrapper> ListItems
{
get { return listItems; }
set
{
listItems = value;
OnPropertyChanged();
}
}

public MainPage()
{
InitializeComponent();
ListItems = new List<ModelWrapper>();
int j = 1;
for (int i = 0; i < 400; i++)
{
if (j > 4)
j = 1;
if (j == 1)
ListItems.Add(new ModelWrapper() {Imagename = “account.svg”, Index = i});
else if (j == 2)
ListItems.Add(new ModelWrapper() {Imagename = “android.svg”, Index = i});
else if (j == 3)
ListItems.Add(new ModelWrapper() {Imagename = “ann.svg”, Index = i});
else if (j == 4)
ListItems.Add(new ModelWrapper() {Imagename = “perm.svg”, Index = i});
j++;
}
BindingContext = this;
}

Now run the app to see the SVG being loaded in the listview, see the below image for the sample output.

nexus5x-portrait
SVG Images

Summary

In this blog i have shared my idea about integrating/loading SVG in Xamarin Forms using the SkiaSharp library Cross-Platform solution. This is just a part of SkiaSharp usage as the application of drawing library is huge, i will try to come up with someother useful scenario which developers could make use of it in their apps. The sample along with the above discussed piece of codes in Github.  If you have any suggestions or improvements to this please add it in the comments section.

 

 

Advertisements

2 thoughts on “SVG in Xamarin Forms

  1. The GitHub link at the end of the post is to a different example. The SkiaSharp SVG sample on you GitHub repo is also empthy.

    Thanks for sharing. I’m really curious to see how your CustumSkCancasView looks 😉

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s