Mobiele apps programmeren met Xamarin – Animaties

print

Inhoud


Wat vooraf ging


Inleiding

De ViewExtensions class voorziet in een aantal methoden die kunnen gebruikt worden voor eenvoudige animaties.

  • TranslateTo animeert de TranslationX en TranslationY eigenschap.
  • ScaleTo animeert de Scale eigenschap van de beginwaarde (1) naar de gewenste waarde.
  • RelScaleTo animeert de Scale eigenschap relatieve ten opzicht van de huidige waarde.
  • RotateTo animeert de Rotation eigenschap eigenschap.
  • RelRotateTo animeert de Rotation eigenschap relatieve ten opzicht van de huidige waarde.
  • RotateXTo animeert de RotationX eigenschap.
  • RotateYTo animeert de RotationY eigenschap.
  • FadeTo animeert de Opacity eigenschap.

Standaard duurt iedere animatie 250 millieseconden maar dit kan gewijzigd worden.

De ViewExtensions class voorziet ook een CancelAnimations methode die gebruikt kan worden om de animatie te beëindingen.

De animation extension methods in de ViewExtensions class zijn allen asynchroon.

De kwaliteit van onderstaande video is niet optimaal maar ik wel hem toch opnemen in deze post.


Eenvoudige animaties

  • Maak een nieuw Xamarin-project aan en geef het een passende naam (bv. Animaties). Voor mijn voorbeelden heb ik hetzelfde project gebruikt als in het hoofdstuk van de afbeeldingen, ik werk dan ook hierop verder.
  • Voeg een afbeelding toe aan het project (in onderstaand voorbeeld wordt de afbeelding monkey.png gebruikt.
  • Voeg onderstaande XAML toe aan MainPage.xaml.

Onderstaande voorbeelden sluiten nauw aan bij de officiële handleiding.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="IntegratingImages.ScaleAndRotateImage">
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="0.8*" />
      <RowDefinition Height="0.2*" />
    </Grid.RowDefinitions>
    <AbsoluteLayout x:Name="absoluteLayout">
      <Image x:Name="image" Source="monkey.png" SizeChanged="OnImageSizeChanged" />
    </AbsoluteLayout>
    <StackLayout Grid.Row="1">
      <Button x:Name="startButton" Text="Start Animation" Clicked="OnStartAnimationButtonClicked" VerticalOptions="EndAndExpand" />
      <Button x:Name="cancelButton" Text="Cancel Animation" Clicked="OnCancelAnimationButtonClicked" IsEnabled="false" />
    </StackLayout>
  </Grid>
</ContentPage>

Merk het gebruik van de AbsoluteLayout op.

Merk de naam op die gegeven is aan de afbeelding x:Name="image".

  • Voeg onderstaande code-behind toe aan MainPage.xaml.cs.
using System;
using Xamarin.Forms;

namespace IntegratingImages
{
    public partial class AnimatingImage : ContentPage
    {
        public AnimatingImage()
        {
            InitializeComponent();
        }

        void OnImageSizeChanged(object sender, EventArgs e)
        {
            var center = new Point(absoluteLayout.Width / 2, absoluteLayout.Height / 2);
            AbsoluteLayout.SetLayoutBounds( image, new Rectangle(center.X - image.Width / 2, center.Y - image.Height / 2, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
        }


        async void OnStartAnimationButtonClicked(object sender, EventArgs e)
        {
            //Hier komt de animatie
        }

        void OnCancelAnimationButtonClicked(object sender, EventArgs e)
        {
            ViewExtensions.CancelAnimations(image);
        }
    }
}

Merk op dat de event, die de animatie bevat, reeds async is.

Bij het opstarten, of void OnImageSizeChanged(object sender, EventArgs e) wordt de afbeelding gecentreerd.

void OnImageSizeChanged(object sender, EventArgs e)
{
    var center = new Point(absoluteLayout.Width / 2, absoluteLayout.Height / 2);
    AbsoluteLayout.SetLayoutBounds( image, new Rectangle(center.X - image.Width / 2, center.Y - image.Height / 2, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
}

Het annuleren van de animatie is reeds toegevoegd ViewExtensions.CancelAnimations(image) via de klasse ViewExtensions class.

Rotatie

Een eenvoudige animatie toevoegen, bv. een RotateTo gebeurt nu als volgt:

await image.RotateTo (360, 2000);
image.Rotation = 0;

Deze RotateTo roteert de afbeelding over 360° en dit over een periode van 2 seconden (2000 milliseconden). Nadien wordt de RotateTo opnieuw op 0° gezet (opdat hij niet op 360° zou blijven staan). Let op de await om de animatie asynchroon te maken.

De volledige code wordt nu:

using System;
using Xamarin.Forms;

namespace IntegratingImages
{
    public partial class AnimatingImage : ContentPage
    {
        public AnimatingImage()
        {
            InitializeComponent();
        }

        async void OnStartAnimationButtonClicked(object sender, EventArgs e)
        {
            await image.RotateTo (360, 2000);
            image.Rotation = 0;        
        }

        void OnCancelAnimationButtonClicked(object sender, EventArgs e)
        {
            ViewExtensions.CancelAnimations(image);
        }
    }
}

Relatief

De onderstaande code voert de rotatie relatief ten opzichte van zichzelf uit.

await image.RelRotateTo(360, 2000);

Schalen

Onderstaande code schaalt de afbeelding naar zijn dubbele grootte over een periode van 2 seconden. Het eindresultaat is altijd 2 keer de begingrootte, ongeachte de grootte van de afbeelding op het moment dat de schaling begon.

await image.ScaleTo(2, 2000);

Relatief

De onderstaande code schaalt relatief ten opzichte van de huidige schaling (dus niet noodzakelijk de beginschaling van 1).

await image.RelScaleTo(2, 2000);

Verankeren

Voor het roteren en het schalen kunt u ook een ankerpunt vaststellen waarrond geroteerd of geschaald wordt. De verankering, het centrum van de rotatie of de schaling, kan gezet worden op de x-as via AnchorX of op de y-as via AnchorY.

Als u de afbeelding rond het midden van de lay-out wilt roteren, moeten de eigenschappen AnchorX en AnchorY worden ingesteld op waarden die relatief zijn ten opzichte van de breedte en hoogte van de afbeelding. In dit voorbeeld wordt het midden van de afbeelding gedefinieerd als het midden van de lay-out en daarom hoeft de standaard AnchorX-waarde van 0,5 niet te worden gewijzigd. De eigenschap AnchorYwordt echter opnieuw gedefinieerd als een waarde van de bovenkant van de afbeelding tot het middelpunt van de lay-out.

Dit zorgt ervoor dat de afbeelding een volledige rotatie van 360 graden maakt rond het middelpunt van de lay-out, zoals in onderstaand voorbeeld is uitgewerkt.

image.AnchorY = (Math.Min (absoluteLayout.Width, absoluteLayout.Height) / 2) / image.Height;
await image.RotateTo (360, 2000);

Verplaatsen

Onderstaand voorbeeld toont hoe u een afbeelding kunt verplaatsen (via TranslateTo).

await image.TranslateTo (-100, -100, 1000);

De afbeelding verplaatst zich 100 pixels naar links en naar boven (door de negatieve waarden) over een duur van 1 seconde.

Samengestelde verplaatsing

U kunt meerdere verplaatsingen na mekaar uitvoeren.

await image.TranslateTo (-100, 0, 1000);    // verplaatst de afbeelding naar links
await image.TranslateTo (-100, -100, 1000); // Verplaatst de afbeelding vervolgens naar boven
await image.TranslateTo (100, 100, 2000);   // verplaatst de afbeelding diagonaal naar rechtsonder
await image.TranslateTo (0, 100, 1000);     // verplaatst de afbeelding naar links
await image.TranslateTo (0, 0, 1000);       // verplaatst de afbeelding naar boven

Vervagen

Onderstaande code vervaagt de afbeelding (via FadeTo)

image.Opacity = 0;
await image.FadeTo (1, 4000);

Deze code animeert de afbeelding door deze binnen 4 seconden (4000 milliseconden) te vervagen. De FadeTo-methode verkrijgt de huidige opaciteit-eigenschapswaarde voor het begin van de animatie en vervaagt vervolgens van die waarde naar het eerste argument (hier 1).


Samengetelde animaties

Een samengestelde animatie is een combinatie van animaties waarbij twee of meer animaties tegelijkertijd worden uitgevoerd. Samengestelde animaties kunnen worden gemaakt door het combineren van await-animaties en animaties zonder await. Onderstaand voorbeeld demonstreert dit.

image.RotateTo (360, 4000);
await image.ScaleTo (2, 2000);
await image.ScaleTo (1, 2000);

In dit voorbeeld wordt de afbeelding geschaald en tegelijkertijd gedurende 4 seconden (4000 milliseconden) geroteerd. Het schalen van de afbeelding maakt gebruik van twee opeenvolgende animaties die tegelijkertijd met de rotatie plaatsvinden. De RotateTo-methode wordt uitgevoerd zonder een operator await en zal bijgevolg meteen doorgaan naar het volgende statement.

De await image.ScaleTo (2, 2000) zorgt ervoor dat de huidige rotatie blijft doorgaan en dat dus terzelfdertijd de schaling gebeurt. Er wordt echter niet meteen doorgegaan naar het volgende statement, er wordt gewacht tot deze taak (schalen naar 2 maal de grootte gedurende 2 seconden) is beëindigt voor er wordt verdergegaan met het volgende statement.
Als de eerste await image.ScaleTo (2, 2000) beëindigd is, is de RotateTo-animatie halverwege en is de afbeelding 180 graden gedraaid. Tijdens de laatste 2 seconden (2000 milliseconden) worden de tweede ScaleTo-animatie en de RotateTo-animatie beiden voltooid.

Samengestelde animaties groeperen

U kunt animaties, of bij uitbreiding taken, groeperen via de Task.WhenAny-methode of de Task.WhenAll-methode.

De Task.WhenAny-methode gaat verder met het volgende statement van zodra één van de gegroepeerde taken voltooid is, eventuele andere gegroepeerde taken die niet voltooid zijn blijven verder hun ding doen (roteren, schalen,…).

await Task.WhenAny<bool>
(
  image.RotateTo (360, 4000),
  image.ScaleTo (2, 2000)
);
await image.ScaleTo (1, 2000);

Eigenlijk doet dit hetzelfde als de voorgaande code. De rotatie start en tegelijk start de eerste schaling image.ScaleTo (2, 2000). De schaling eindigt het eerst, en na het einde van deze eerst schaling wordt verdergegaan met de tweede schaling, de rotatie blijft ondertussen doorlopen. De animatie eindigt na 4 seconden.

De Task.WhenAll-methode gaat pas verder met het volgende statement wanneer alle taken binnen de gegroepeerde taken voltooid zijn.

await Task.WhenAll (
  image.RotateTo (360, 4000),
  image.ScaleTo (2, 2000)
);
await image.ScaleTo (1, 2000);

De rotatie en de eerste schaling starten tegelijk maar de tweede schaling zal pas starten wanneer alle gegroepeerde taken voltooid zijn, dus na het voltooien van de rotatie. De animatie eindigt dus pas na 6 seconden.


Easing functies

Xamarin.Forms bevat een Easing-klasse waarmee u een functie kunt toevoegen die bepaalt hoe animaties versnellen of vertragen terwijl ze worden uitgevoerd.

De Easing-klasse kent onderstaande functies.

Linear
Linear – de standaard versnelling.

BounceIn
BounceIn – stuitert 3 maal tot het tot stilstand komt bij de finale waarde.

BounceOut
BounceOut – springt naar de finale waarde en stuitert vervolgens nog 3 maal.

CubicIn
CubicIn – start langzaam en versnelt.

CubicInOut
CubicInOut – versnelt in het begin en vertraagt op het einde.

CubicOut
CubicOut – start snel en vertraagt.

SinIn
SinIn – versnelt langzaam.

SinInOut
SinInOut – versnelt langzaam en vertraagt langzaam.

SinOut
SinOut – vertraagt langzaam.

SpringIn
SpringIn – keert terug en springt dan naar voor naar de finale waarde.

SpringOut
SpringOut – gaat te ver (overshoot) en keert dan terug.

De gewenste Easing-functie wordt toegevoegd aan de animatie.

await image.TranslateTo(0, 200, 2000, Easing.BounceIn);
await image.ScaleTo(2, 2000, Easing.CubicIn);
await image.RotateTo(360, 2000, Easing.SinInOut);
await image.ScaleTo(1, 2000, Easing.CubicOut);
await image.TranslateTo(0, -200, 2000, Easing.BounceOut);

Hebt u met deze animaties nog niet het gewenste resultaat dan kunt u overwegen eigen animaties aan te maken. Op de officiële website leest u hier meer over.


Behandelde Basiscompetenties uit de module ICT Programmeren – Integratie externe functionaliteiten

  • IC BC232 – kan digitale tools gebruiken om modellen, simulaties en visualisaties van de realiteit te maken
  • IC BC255 – kan de geïntegreerde content in functie van het beoogde eindresultaat aanpassen

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.