Mobiele apps programmeren met Xamarin – Afbeeldingen integreren

print

Inhoud


Wat vooraf ging

Het toevoegen van afbeeldingen aan uw applicatie is niet nieuw, we hebben dit al vaker gedaan in vorige voorbeelden. De standaardcode is de volgende:

<Image Source="https://ictopleidingen.azurewebsites.net/wp-content/uploads/2016/12/LogoPCVOGroot.png" />

Inleiding

Afbeeldingen vormen een belangrijk visueel onderdeel van een applicatie en vragen daarom aparte aandacht.

Er zijn 4 soorten afbeeldingen:

  • Local images – dit zijn afbeeldingen die meegeleverd worden met de applicatie en die zich in een specifieke map bevinden binnen de applicatie.
  • Embedded images – dit zijn afbeeldingen die deel uitmaken van de broncode van de app. Ze zijn dus niet terug te vinden in een map maar maken integraal deel uit van de broncode.
  • Downloaded images – Afbeeldingen die opgenomen worden door te verwijzen naar hun specifieke URL.
  • Icons and splashscreens – platform-specifieke iconen en opstartafbeeldingen.

Eigenchappen

Afbeeldingen hebben twee belangrijke eigenschappen:

  • Source – De bron imageSource van de afbeelding (File, Uri, Resource of Stream).
  • Aspect – Hoe de afbeelding zal weergeven worden binnen de voorziene ruimte Aspect.

Source

Er zijn 4 mogelijke imageSource(s):

  • FromFile – De bron is een bestand (met een naam en eventueel een pad) waarnaar verwezen moet worden. Deze bron kan platform specifiek zijn.
  • FromUri – De bron is een afbeelding die zich op het internet bevindt. U verwijst er naar via de URI new Uri("http://server.com/image.jpg").
  • FromResource – De afbeelding is opgenomen (embedded) in de applicatie zelf (Action:EmbeddedResource).
  • FromStream – De afbeelding wordt gestreamd.

Aspect

De eigenschap Aspect heeft 3 mogelijke waarden:

  • AspectFit (default) – De afbeelding past volledige in de voorziene ruimte en eventuele wordt er witruimte (boven, onder, links, rechts) toegevoegd.

<Image Source="https://ictopleidingen.azurewebsites.net/wp-content/uploads/2016/12/LogoPCVOGroot.png" Aspect="AspectFit"/>
  • Fill – De afbeelding neemt de volledige beschikbare ruimte in en zal hiertoe gestretcht worden, wat kan leiden tot vervorming van de afbeelding.

<Image Source="https://ictopleidingen.azurewebsites.net/wp-content/uploads/2016/12/LogoPCVOGroot.png" Aspect="Fill"/>
  • AspectFill – De afbeelding neemt de volledige beschikbare ruimte in maar behoudt zijn verhoudingen, wat kan leiden tot het “afknippen” (clippen) van de afbeelding.

<Image Source="https://ictopleidingen.azurewebsites.net/wp-content/uploads/2016/12/LogoPCVOGroot.png" Aspect="AspectFill"/>

Afbeeldingen toevoegen aan het project

Afbeeldingen kunnen ter beschikking worden gesteld aan uw app op 3 manieren:

  • Via zijn URL (Uniform Resource Locator of zijn locatie op het Internet).
  • In een lokale map binnen de mappenstructuur van het project.
  • Embedded (geïntegreerd) in het project zelf.

URL (FromUri)

Indien u een afbeelding “aanspreekt” via zijn URL wordt de afbeelding zelf niet toegevoegd aan het project en ze we klaar met dit te bespreken.

XAML

<Image Source="https://ictopleidingen.azurewebsites.net/wp-content/uploads/2016/12/LogoPCVOGroot.png" Aspect="AspectFit"/>

C#

Image LogoPCVO= new Image { WidthRequest = 300, HeightRequest = 300 };
LogoPCVO.Source = ImageSource.FromUri(new Uri("https://ictopleidingen.azurewebsites.net/wp-content/uploads/2016/12/LogoPCVOGroot.png"));
LogoPCVO.Aspect = Aspect.AspectFit;

of beperkt tot zijn essentie:

Image LogoPCVO= new Image { Source = ImageSource.FromUri(new Uri("https://ictopleidingen.azurewebsites.net/wp-content/uploads/2016/12/LogoPCVOGroot.png")) };;

Image Caching

De UriImageSource ondersteunt ook caching van de gedownloade afbeelding. Standaard wordt iedere gedownloade afbeelding gedurende 1 dag “gecachet” in de application’s private storage area. Xamarin gebruikt hiertoe twee eigenschappen:

  • CachingEnabled – Is caching aan (standaard staat dit aan (true))?
  • CacheValidity – Een TimeSpan dat bepaalt hoelang de afbeelding “gecachet” wordt.

Onderstaande code zal de afbeelding 5 dagen cachen.

XAML

<Image >
    <Image.Source>
        <UriImageSource Uri="http://xamarin.com/content/images/pages/forms/example-app.png" CacheValidity="10:00:00.0" />
    </Image.Source>
</Image>

C#

LogoPCVO.Source = new UriImageSource
{
    Uri = new Uri("https://ictopleidingen.azurewebsites.net/wp-content/uploads/2016/12/LogoPCVOGroot.png"),
    CachingEnabled = true,
    CacheValidity = new TimeSpan(5, 0, 0, 0)
};

Lokale map (FromFile)

Bekijk afbeeldingen hier vooral als icoontjes of logo’s en niet zozeer als “echte” foto’s. Foto’s kunnen het best ergens op het internet staan en via de URL aangesproken worden (of een beperkt, vast, aantal kunnen “embedded” zijn.

UWP

U kunt afbeeldingen gewoon direct onder het UWP-project plaatsen, of indien u dit verkiest, in een mapje.

  • Klik rechts op het UWP-project en kies Add – New Folder.
  • Geef vervolgens een naam aan de folder (bv. Images).

  • Klik rechts op de net aangemaakte map en kies Add – Existing item….

  • Selecteer de gewenste afbeelding(en).
  • De afbeelding(en) is toegevoegd aan het project. Kijk ook even naar de properties/eigenschappen. Vooral naar de Build Action die “gewoon” op Content staat.

Android

Het Android-project heeft reeds de nodige mappen aangemaakt. U vindt deze onder de map Resources. U voegt de afbeelding, zoals hierboven beschreven, toe aan de gewenste map.
Standaard bevat iedere map al een afbeelding icon.png.

  • Selecteer een afbeelding icon.png en kijk ook even naar de properties/eigenschappen. De Build Action heeft nu de waarde AndroidResource.

Waarom die verschillende mappen?

Android heeft deze verschillende mappen aangemaakt om tegemoet te komen aan de verschillende eisen en mogelijkheden van de devices (smartphone, tablet,…). Elke map is bedoeld voor een specifiek “formaat” (High- en low-DPI versies). U zult dus uw afbeelding ook meerdere keren, in meerdere formaten, moeten toevoegen. De juiste afbeelding wordt “at runtime” (tijdens het werken met de app) gekozen. Het volstaat dus de verschillende formaten in de juiste mappen aan te bieden en Xamarin zorgt ervoor dat de juiste afbeelding voor het juiste toestel (dpi) gekozen wordt.

Onderstaande tabel toont de betekenis van de verschillende formaten, meer gedetailleerde informatie vindt u bij Android Material Design. Of wie alles nog meer in detail wilt kan hier terecht.

Screen resolutiondpiPixel ratioPixels
xxxhdpi6404.0400 x 400
xxhdpi4803.0300 x 300
xhdpi3202.0200 x 200
hdpi2401.5150 x 150
mdpi1601.0100 x 100

iOS

Alle afbeelding binnen het iOS-project komen eveneens in de map Resources terecht maar nu heeft de propertie Build Action de waarde BundleResource.

Kent iOS dan geen verschillende formaten zoals Android?

Tuurlijk wel, oorspronkelijk had de originele iPhone een resolutie van 320 x 480. Met de huidige “grote” iPad spreken we over heel andere waarden. Dus iOS kent hetzelfde probleem (verschillende formaten en dpi’s) als Android en past eenzelfde oplossing toe (namelijk het automatisch selecteren van de geschikte afbeelding in het geschikte formaat) alleen doet iOS het niet met verschillende mappen maar met aangepaste naamgeving. De basisnaam wordt uitgebreid met een vaste “code”. Onderstaande tabel duidt de mogelijke “codes”, maar wilt u nog meer weten kijk dan eens hier.

"Code"Definite
@2xDe 2 x, Retina resolutie formaat van de afbeelding. Bv. als Image.png een resolutie van 320 x 480 pixels heeft, dan zal Image@2x.png de 640 x 960 pixels-versie van dezelfde afbeelding zijn. @2x wordt gebruikt op de Retina displays.
@3xDe 3 x, HD resolutie formaat van de afbeelding. Bv. als Image.png een resolutie van 414 x 736 pixels heeft, dan zal Image@3x.png de 1242 x 2208 pixels-versie van dezelfde afbeelding zijn. @3x is toegevoegd om iPhone 6s (en volgende) met een HD resolution display te ondersteunen.
~iphoneiOS gebruikt deze versie van de afbeelding op een iPhone of IPod. Combinaties als Image@2x~iphone.png zijn eveneens mogelijk.
~ipadiOS gebruikt deze versie van de afbeelding op een iPad.

Let op, u moet zelf de verschillende formaten toevoegen aan de map onder hun juiste naam. Xamarin (iOS) zal op basis van de naam de geschikte keuze maken maar zal zelf niet de resolutie de afbeelding aanpassen.

De code

XAML

<Image Source="PCVODenderenSchelde.png" Aspect="AspectFit"/>

C#

Image LogoPCVO= new Image { WidthRequest = 300, HeightRequest = 300 };
LogoPCVO.Source = ImageSource.FromFile ("PCVODenderenSchelde.png");
LogoPCVO.Aspect = Aspect.AspectFit;

Platform specifiek

Onderstaande code toont hoe u een loge platform specifiek kunt instellen.

<Image>
    <Image.Source>
        <OnPlatform x:TypeArguments="ImageSource">
            <OnPlatform.iOS>
                <FileImageSource File="Icon.png"/>
            </OnPlatform.iOS>
            <OnPlatform.Android>
                <FileImageSource File="Icon.png"/>
            </OnPlatform.Android>
            <OnPlatform.WinPhone>
                <FileImageSource File="Icon.png"/>
            </OnPlatform.WinPhone>
        </OnPlatform>
    </Image.Source>
</Image>

Embedded afbeeldingen (FromResource)

“Embedded” afbeeldingen worden net als lokale afbeeldingen toegevoegd aan het project maar worden niet in een map gestoken maar rechtstreekst opgenomen in de “assemblie” van het project zelf (zeg mar in het .exe-bestand zelf).

Zoals eerder gesteld kunt u afbeeldingen het best op internet hosten maar… dan moet u wel steeds connectie hebben met internet. Nu, vele apps werken met een databank in de cloud waarvoor ook internet nodig is, dus het hebben van internet is een “must” voor vele apps. Maar stel dat u toch een aantal afbeeldingen steeds wilt kunnen weergeven, ook zonder internet?

Een oplossing is ze in lokale mappen te plaatsen. Dit kan, al geldt hier de opmerking dat u in deze lokale mappen vooral icoontjes en logo’s plaatst (in hun verschillende formaten).

Voor een beperkt aantal, essentiële afbeeldingen kan de “embedded” optie misschien de beste zijn. “Embedded” afbeeldingen maken als het ware deel uit van het programma zelf.

“Embedded” afbeeldingen worden toegevoegd aan het basisproject App1 (Portable) via rechts klikken en vervolgens opnieuw Add – Existing item…. De propertie Build Action moet uzelf de waarde Embedded Resource geven.

C#

In onderstaand voorbeeld is IntegratingImages de naam van het project.

var embeddedImage = new Image { Source = ImageSource.FromResource("IntegratingImages.PCVODenderenSchelde.jpg") };

XAML
Omdat er geen ingebouwde converter is van string naar ResourceImageSource ondersteunt XAML geen embedded images maar het kan wel via een kleine omweg. U moet zelf deze functionaliteit toevoegen door een eigen XAML markup extension te schrijven.

  • Voeg een eigen klasse toe (bv. met de naam ImageResourceExtension) toe aan het project.
  • Voeg onderstaande code toe.
using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace IntegratingImages
{
    [ContentProperty("Source")]
    class ImageResourceExtension : IMarkupExtension
    {
        public string Source { get; set; }

        public object ProvideValue(IServiceProvider serviceProvider)
        {
            if (Source == null)
                return null;

            var imageSource = ImageSource.FromResource(Source);

            return imageSource;
        }
    }
}

U bepaalt eerst welke property er uitgebreid wordt [ContentProperty("Source")]

De klasse erft van IMarkupExtension.

Voeg een methode public object ProvideValue(IServiceProvider serviceProvider).

Bepaal de conversie:

var imageSource = ImageSource.FromResource(Source);

Nu kunt u via deze converter “embedded images” opnemen via XAML.

<?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:local="clr-namespace:IntegratingImages;assembly=IntegratingImages" x:Class="IntegratingImages.EmbeddedImage">
  <StackLayout >

    <Image Source="{local:ImageResource IntegratingImages.PCVODenderenSchelde.jpg}" />

  </StackLayout>
</ContentPage>

Vergeet niet eerst de toegevoegde klasse toe te voegen via xmlns:local="clr-namespace:IntegratingImages;assembly=IntegratingImages".

De onderstaande code laadt de afbeelding.

<Image Source="{local:ImageResource IntegratingImages.PCVODenderenSchelde.jpg}" />

Applicatie-icoontje en splashscreens

Een applicatie kan een eigen specifiek icoontje hebben (het icoontje dat u moet aanklikken om de app te starten) en iOS en UWP kunnen ook een eigen specifiek beginscherm (splashscreen) hebben.

  • Voeg het gewenste icoon en splashscreen toe aan ieder project op de juiste locatie en in het gewenste/juiste formaat. U kunt ook de reeds aanwezige icoontjes en splashscreens overschrijven en vervangen.

  • Het applicatie-icoontje en de splashscreen stelt u in in de Properties van ieder project.

Android

Onder Android Manifest. Android gebruikt enkel een applicaatie-icoontje en geen splashscreen.

iOS

iOS kent het begrip Launch screen. U vindt deze onder iOS Application.

De Application icon vindt u onder Application.

UWP

Voor UWP moet u naar Application – Package Manifest.

Vervolgens gaat u naar Visual Assets en kan u daar kiezen voor App Icon voor het instellen van het gewenste applicatie-icoontje.

En voor Splash Screen voor het instellen van het opstartscherm.


Een afbeelding toevoegen aan een Button

Tenslotte nog even stilstaan bij het opnemen van een afbeelding in een Button.

De afbeelding moet beschikbaar zijn als een bestand en zich op de hiertoe voorziene plaats bevinden.

De Button beschikt over een Image-property om een afbeelding toe te voegen.

De code is dan simpelweg:

XAML

<Button Text="OK" Image="someImage.png" />

of platform specifiek.

<Button Text="OK">
    <Button.Image>
        <OnPlatform x:TypeArguments="FileImageSource" iOS="ic_action_good.png" Android="ic_action_good.png" WinPhone="Images/ic_action_good.png" />
    </Button.Image>
</Button>

C#

BtnOK.Image = ImageSource.FromFile("imageName.png");

Of simpelweg:

BtnOK.Image = "imageName.png";

Teken uw eigen vectoriele afbeeldingen met SkiaSharp

SkiaSharp is een 2D grafisch systeem voor .NET en C # op basis van de open-source grafische Skia-engine die veel wordt gebruikt in Google-producten. U kunt SkiaSharp in uw Xamarin.Forms-toepassingen gebruiken om 2D vectorafbeeldingen, bitmaps en tekst te tekenen.

Hieronder geef ik een klein voorbeeldje van de implementatie van SkiaSharp (geïnspireerd door deze blog-post).

Wilt u nog meer weten lees dan de officiële handleiding en bekijk zeker eens onderstaande video.

  • Start een nieuw Xamarin-project en geef het een passende naam (bv. Skia). Kies geen te lange naam want dit zou problemen kunnen geven.

SkiaSharp is een externe functionaliteit die we moeten integreren in ons project. We moeten dus het geschikte NuGet package installeren.

  • Klik rechts op de Solution en kies voor Manage NuGet Packages for Solution

  • Klik rechts op de Solution en kies voor Manage NuGet Packages for Solution
  • Zoek en installeer SkiaSharp.Views.Forms NuGet (SkiaSharp NuGet wordt automatisch mee geïnstalleerd).

Op het moment van dit schrijven gaf de meest recente versie 1.60.0 problemen, het installeren van de versie 1.57.1 (zoals in onderstaande video) gaf geen probleem.

Voeg vervolgens de assembly toe aan MainPage.xaml

xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"

Vervolgens wordt de canvas skia:SKCanvasView met de event PaintSurface toegevoegd. Kies een naam voor de event of gebruik de standaard naam die u kunt genereren.

<skia:SKCanvasView PaintSurface="SKCanvasView_PaintSurface" />

De volledige XAML is:

<?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:local="clr-namespace:Skia" xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms" x:Class="Skia.MainPage">

    <skia:SKCanvasView PaintSurface="SKCanvasView_PaintSurface" />

</ContentPage>

In de code-behind voegen we eerst de bibliotheek toe using SkiaSharp;.

Vervolgens initialiseert u het canvas binnen de event.

using SkiaSharp;
using Xamarin.Forms;

namespace Skia
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void SKCanvasView_PaintSurface(object sender, SkiaSharp.Views.Forms.SKPaintSurfaceEventArgs e)
        {
            // we get the current surface from the event args
            var surface = e.Surface;
            // then we get the canvas that we can draw on
            var canvas = surface.Canvas;
            // clear the canvas / view
            canvas.Clear(SKColors.White);
        }
    }
}

Vervolgens kunt u aan het tekenen slaan.

using SkiaSharp;
using Xamarin.Forms;

namespace Skia
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void SKCanvasView_PaintSurface(object sender, SkiaSharp.Views.Forms.SKPaintSurfaceEventArgs e)
        {
            // we get the current surface from the event args
            var surface = e.Surface;
            // then we get the canvas that we can draw on
            var canvas = surface.Canvas;
            // clear the canvas / view
            canvas.Clear(SKColors.White);


            // create the paint for the filled circle
            var circleFill = new SKPaint
            {
                IsAntialias = true,
                Style = SKPaintStyle.Fill,
                Color = SKColors.Blue
            };

            // draw the circle fill
            canvas.DrawCircle(100, 100, 40, circleFill);

            // create the paint for the circle border
            var circleBorder = new SKPaint
            {
                IsAntialias = true,
                Style = SKPaintStyle.Stroke,
                Color = SKColors.Red,
                StrokeWidth = 5
            };

            // draw the circle border
            canvas.DrawCircle(100, 100, 40, circleBorder);

            // create the paint for the path
            var pathStroke = new SKPaint
            {
                IsAntialias = true,
                Style = SKPaintStyle.Stroke,
                Color = SKColors.Green,
                StrokeWidth = 5
            };

            // create a path
            var path = new SKPath();
            path.MoveTo(160, 60);
            path.LineTo(240, 140);
            path.MoveTo(240, 60);
            path.LineTo(160, 140);

            // draw the path
            canvas.DrawPath(path, pathStroke);

            // create the paint for the text
            var textPaint = new SKPaint
            {
                IsAntialias = true,
                Style = SKPaintStyle.Fill,
                Color = SKColors.Orange,
                TextSize = 80
            };

            // draw the text (from the baseline)
            canvas.DrawText("SkiaSharp", 60, 160 + 80, textPaint);

        }
    }
}

Wilt u nog verder leren tekenen, lees dan de officiële handleiding en bekijk zeker eens onderstaande video.


Behandelde Basiscompetenties uit de module ICT Programmeren – Integratie externe functionaliteiten

  • IC BC024 – * kan zijn eigen deskundigheid inzake ICT opbouwen
  • IC BC232 – kan digitale tools gebruiken om modellen, simulaties en visualisaties van de realiteit te maken
  • IC BC254 – kan externe content integreren en structureren
  • IC BC255 – kan de geïntegreerde content in functie van het beoogde eindresultaat aanpassen
  • IC BC256 – kan diverse elementen tot een nieuw betekenisvol geheel samenstellen
  • IC BC258 – houdt rekening met regelgeving m.b.t. licenties voor het gebruik en de publicatie van broncode
  • IC BC288 – kan ICT-problemen oplossen

Geef een reactie

  • Abonneer je op deze website d.m.v. e-mail

    Voer je e-mailadres in om je in te schrijven op deze website en e-mailmeldingen te ontvangen van nieuwe berichten.