SkiaSharp SKCanvasView loading inconsistancies in Android emulators

LindsayMilesLindsayMiles CAMember ✭✭✭
edited April 2018 in Xamarin.Forms

Hello,

Strange error happening with SkiaSharp SKCanvasView on Android device emulators.

SKCanvasView implemeted in a contentView like this:

<StackLayout Orientation="Vertical" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" BackgroundColor="#414141" >
                            <skia:SKCanvasView x:Name="canvasView" Grid.Column="0" Grid.Row="0" PaintSurface="OnCanvasViewPaintSurface" Touch="OnCanvasTouch" EnableTouchEvents="True" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" BackgroundColor="#414141" />
</StackLayout>

When the contentView loads, I use a pre-defined _resourceId which is simply a string pointing at an embeddedResource image in the shared project.
The base image is 600px x 300px

            Assembly assembly = GetType().GetTypeInfo().Assembly;

            using (Stream stream = assembly.GetManifestResourceStream(_resourceID))
            using (SKManagedStream skStream = new SKManagedStream(stream))
            {
                _resourceBitmap = SKBitmap.Decode(skStream);
            }

After the constructor completes, the OnCanvasViewPaintSurface() method fires to draw the image onto the canvas.
Note the _resourceBitmap now used to fill the SKCanvasView control...

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        try
        {
            //base control size
            var baseFrame = SKRect.Create(0, 0, info.Width, info.Height);
            var imageSize = new SKSize(_resourceBitmap.Width, _resourceBitmap.Height);
            var aspect = baseFrame.AspectFit(imageSize);

            var pictureFrame = SKRect.Create(0, 0, aspect.Width, aspect.Height);

            //expand control to the available area
            canvasView.WidthRequest = pictureFrame.Width;
            canvasView.HeightRequest = pictureFrame.Height;

            var paint = new SKPaint { FilterQuality = SKFilterQuality.High };
            paint.IsAntialias = true;
            paint.IsStroke = true;

            //load the base image
            canvas.DrawBitmap(_resourceBitmap, pictureFrame, paint);

        }
        catch (Exception ex)
        {
            string s = ex.Message;
        }

    }

As already stated, _resourceBitmap is 600px x 300px.
The SKImageInfo info object shows an initial size of 40x40.

The SKRect pictureFrame used to transform the image when loaded in the DrawBitmap() method, is scaled using the aspect object. This enlarges as does the info object as the method is called each time, thus the image is animated as it opens and is displayed. Finally, the image is actually enlarged and displayed filling the space available to it. In the Nexus5x case, final dimensions are 1200x600.

Here's the issue - if I run this in a Nexus5x emulator using API 26 Android 8.0, the OnCanvasViewPaintSurface() is called 5 times as the SKCanvasView animates up to full view. No problems, works as expected.

If I run this in a 7" Tablet or 10" Tablet emulator also running API 26 Android 8.0, the OnCanvasViewPaintSurface() is only called twice and the base image is never displayed at it's full size and certainly never fills the space available.

No idea why this is happening. Same code, same OS version, different emulators, different display results.

Any ideas?

Questions:
How can I turn OFF animation on the SKCanvasView? it ALWAYS animates on opening.
I want it to load to max available size/space and only call the OnCanvasViewPaintSurface() once and not twice or five times... OR call/invoke the OnCanvasViewPaintSurface() method as many time as needed as long as it displays the image in full.

How can I determine the max size the SKCanvasView can expand to PRIOR to loading any image? This will vary from device to device obviously.

Any advice or insights would be welcome!

Thank you.

Answers

  • LindsayMilesLindsayMiles CAMember ✭✭✭
    edited April 2018

    UPDATE:

    As I said, this works as-is on an Android Nexus5x emulator. It also works in iOS on all device emulators.

    To try fix the issue with Android tablets of any size, I messed with HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" on both the SKCanvasView and the containing StackPanel.

    If I set those to HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" on the SKCanvasView only, it still will not display the base image as it does in the working device emulators already stated.

    If I set HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" in BOTH the SKCanvasView AND the containing StackPanel, it all works. On all emulators.

    BUT... (always a but...)

    The OnCanvasViewPaintSurface is still called 5 times as that containing contentView loads up on the Nexus5x emulator and only once on the tablet emulators. Opening on the Nexus5x opening the image is animated, on all other emulators it is not and it displays in full immediately.

    Same code on all.

    It is now working well enough for now. Strange behaviour though...

Sign In or Register to comment.