Fermer

mars 8, 2019

Créez des animations dans votre application Xamarin avec SkiaSharp


SkiaSharp est une bibliothèque d’enveloppes .NET à code source libre reposant sur le logiciel Skia de Google, développée et maintenue par les ingénieurs de Xamarin. Poursuivez votre lecture pour apprendre à créer de superbes animations dans votre application mobile avec Xamarin.Forms et SkiaSharp.

Il me fait grand plaisir de partager avec vous certains de mes sujets de prédilection dans le développement de logiciels: infographie et applications mobiles. J'adore le graphisme depuis que je suis tout petit – j'aimais dessiner sur papier et, lorsque mes parents m'ont offert mon premier ordinateur personnel, un étonnant ZX Spectrum, je suis devenu complètement fasciné par l'infographie.

SkiaSharp est. une bibliothèque de wrapper open-source .NET du moteur graphique Skia et en combinaison avec Xamarin.Forms, qui est un excellent framework de développement d'applications mobiles open-source multiplate-forme, vous pouvez donner une nouvelle vie à vos applications mobiles.

Skia , The Star Performer

Skia est un moteur graphique 2D de haute performance et à source ouverte, écrit en C ++. C’est la propriété de Google et son soutien. Preuve de ses performances solides, il a été utilisé dans plusieurs produits grand public, tels que Google Chrome, Chrome OS, Android ou Mozilla FireFox, pour n'en nommer que quelques-uns. Le référentiel Skia est disponible ici: https://github.com/google/skia

Skia propose des versions de bibliothèque natives pour Android, iOS, Mac, Windows et ChromeOS.

Comme on pouvait s'y attendre d'un moteur graphique 2D, Skia dispose d'une API permettant de dessiner des primitives graphiques telles que du texte, des géométries et des images. Il possède une API en mode de rendu immédiat, de sorte que chaque appel effectué avec l'API Skia sera rapidement tracé à l'écran.

A Sharp Skia

SkiaSharp est un La bibliothèque d'enveloppes .NET sur Skia de Google, développée et maintenue par les ingénieurs de Xamarin et, bien sûr, est entièrement open source sous licence MIT. Vous pouvez consulter son référentiel de code source sur Github: https://github.com/mono/SkiaSharp

Sur les plates-formes autres que Windows, SkiaSharp s'exécute sur Xamarin et, comme pour toutes les autres. La bibliothèque NET, le moyen le plus simple d’ajouter SkiaSharp à vos projets est de NuGet: https://www.nuget.org/packages/SkiaSharp

SkiaSharp Canvas View

Pour voir réellement ce qui est à l’écran vous dessinez avec l’API SkiaSharp, SkiaSharp fournit un contrôle de zone de travail sur chaque plate-forme prise en charge. Ceci est fait par SkiaSharp.Views, une bibliothèque d'extension reposant sur SkiaSharp: https://www.nuget.org/packages/SkiaSharp.Views.Forms .

Voici quelques exemples du contrôle natif sur toile, fourni par SkiaSharp sur certaines plates-formes:

 // Xamarin.iOS 
 public   classe   SKCanvasView  :  UIView .
 {
 public   événement  EventHandler  < SKPaintSurfaceEventArgs >  PaintSurface ; 
]. 
 // Xamarin.Andruck ] public   class   SKSurfaceView  :  SurfaceView  ISurfaceHolderCallback
 {
 public   événement  EventHandler  < SKPaintSurfaceEventArgs >  PaintSurface ; 
]. 
 // Mac 
.   classe   SKCanvasView  :  NSView
 {
 public   évènement  EventHandler  < SKPaintSurfaceEventArgs >  PaintSurface ; 
]. 
 // UWP 
.   partiel   classe   SKXamlCanvas  :  Toile
 {
 public   événement  EventHandler  < SKPaintSurfaceEventArgs >  PaintSurface ; 
]. 
 // WPF 
 public   classe   SKElement  :  FrameworkElement
 {
 public   événement  EventHandler  < SKPaintSurfaceEventArgs >  PaintSurface ; 
] 

Comme vous le savez, Xamarin.Forms possède sa propre API multiplate-forme et ses contrôles qui encapsulent les API et les contrôles natifs. Par conséquent, pour les applications Xamarin.Forms, SkiaSharp dispose d'une bibliothèque dédiée appelée SkiaSharp.Views.Forms: https://www.nuget.org/packages/SkiaSharp.Views.Forms

SkiaSharp.Views. Forms fournit un contrôle Xamarin.Forms pour la toile, la classe SkCanvasView :

 // Xamarin.Forms 
 public     SKCanvasView  :  Voir . ] ISKCanvasViewController
 {
 public   événement  EventHandler  < SKPaintSurfaceEventArgs >  PaintSurface ; 
] 

Sous le capot, le Xamarin. Les rendus de formulaires pour SKCanvasView utilisent les mêmes vues natives qui partagent la même implémentation que dans SkiaSharp.Views

S'appuyant sur la vue SkiaSharp Canvas

Comme vous pouvez le voir ci-dessus, sur toutes les plates-formes, SkiCanvasView a un événement PaintSurface . Il déclenche l'événement lorsque le canevas doit être peint, soit parce que la vue a été redimensionnée, soit parce que vous avez appelé la méthode InvalidateSurface () :

 _skCanvasView.InvalidateSurface (); 

Sur le gestionnaire d'événements , vous obtenez une instance de SkiCanvas que vous pouvez utiliser pour dessiner avec l’API SkiaSharp:

. . . 
_skCanvasView .  PaintSurface  +  =  SkCanvasViewRequiredPainting ; 
. . . . 19659080] objet  expéditeur  SKPaintSurfaceEventArgs e ) 
 {
SKSurface skSurface  =  et .  Surface ; 
SKCanvas skCanvas  =  skSurface .  Toile ; 
skCanvas .  Clear  () ; 
 var  paint  =   nouveau   SKPaint  (). 19659021] {
Style  =  SKPaintStyle .  AVC 
Couleur  =  Couleur .  Bleu .  Couleur du dessus  () 
StrokeWidth  =   10 
} ; 

 // Dessinez sur l'instance skCanvas à l'aide de l'API SkiaSharp 
skCanvas .  DrawRect  [ x  y  largeur  hauteur  peinture ) ; 
} 

Je trouve impressionnant de voir comment la combinaison de Xamarin, Xamarin.Forms et SkiaSharp permet de réunir .NET et Skia sur autant de plates-formes différentes et de fournir une plate-forme .NET croisée. API pour le développement d'applications mobiles et Skia!

Cet article traite de l'utilisation de Xamarin.Forms et de SkiaSharp. Par conséquent, ce que vous lirez au sujet de la prochaine utilisation utilise le SkCanvasView de la bibliothèque SkiaSharp.Views.Forms.

Implémentation d'une surbrillance animée dans une application mobile avec Xamarin.Forms et SkiaSharp

À titre d'exemple, je vais montrer comment créer une surbrillance qui se déplace entre les entrées et un bouton d'un formulaire d'inscription, en créant une animation captivante effet. L'application est construite avec Xamarin.Forms, Skia.Sharp et C #, qui s'exécute de manière transparente sur Android et iOS. Voici une capture d'écran de l'application finale exécutée dans le simulateur iOS: https://www.youtube.com/watch?v=BBZWcWjJO_g

Vous pouvez consulter le code source complet de l'application dans mon référentiel sur GitHub: https://github.com/andreinitescu/AnimatedHighlightApp

L'implémentation est en C # et est partagée à 100% sur toutes les plates-formes: aucun code personnalisé, aucune plate-forme n'est impliqué, aucun Xamarin n'est impliqué. Les formes de rendu et aucun effet n'a été utilisé. Je ne l'ai pas testé sur d'autres plates-formes prises en charge par Xamarin.Forms et SkiaSharp, mais je suis sûr que le code fonctionne très bien sur celles-ci également.

Nous remercions les sources suivantes et leurs auteurs pour l'idée de conception d'animation: [19659111] Implémentation de la surbrillance

L'effet de surbrillance est créé en combinant le tracé d'un chemin géométrique avec l'API SkiaSharp et l'animation de la partie visible du chemin à l'aide de l'API d'animation Xamarin.Forms. Voici les principales étapes de ma mise en œuvre:

  1. Créer la présentation du formulaire d'inscription

  2. Construire et dessiner SkPath sur sur SkCanvasView en fonction de la position des éléments de formulaire dans la disposition du conteneur

  3. Rendre une certaine partie de SkPath visible à l'aide d'un effet de tiret

  4. Animation du point culminant entre les éléments

Création de la disposition du formulaire d'inscription

Le formulaire d'inscription comporte trois Entrée éléments pour entrer le nom d'utilisateur, le mot de passe et le mot de passe de confirmation, et un bouton pour le soumettre. J'utilise un StackLayout comme conteneur pour les éléments de formulaire, mais tout autre conteneur fonctionnerait:

 < StackLayout   x:  Nom  =  ] " _formLayout "   ... > 
 < Label   Texte  =  " Nom d'utilisateur " [19659129] Style  = " { de StaticResource FormLabelStyle }  "    /> 
 < Entrée   de [1965915]]. = " { StaticResource FormEntryStyle }  " 
 Focused  =  " EntryFocused "  " /> 
 < Label   Texte  =  " Mot de passe " 
 Marge  =  " 0, 15, 0, 0  "
 Style  ="  { StaticResource FormLabelStyle }   "  /> 
 < Entrée   IsPassword  =  " Vrai " 
 Style  = "19659121] { StaticResource FormEntryStyle   "
 Focused  =  =  EntryFocused "   / 
 < Label   Texte  =  " Confirmer le mot de passe " 
 Marge  =  " 0, 15, 0, 0 " 
 Style  = "[19659121] { StaticResource FormLabelStyle }   "  /> 19659125] < Entrée   IsPassword  < True  "
 Style  ="  { StaticResource FormEntryStyle }   "
 Focused  = " .  "  /> 
 < Button   Text  = "  Inscrivez-vous  "
" Margin 
 19659121] =  " 0, 40, 0, 0 " 
 Style  = " { de référence statique FormSubmitBtnStyle } . 
 Clicked  =  " ButtonClicked "   /> 
 </  StackLayout > 

Créez et dessinez SkPath sur SkCanView Basée sur la position des éléments de formulaire dans la disposition du conteneur

La ligne de surbrillance réelle est un chemin géométrique tracé à l'aide de l'API SkiaSharp. En utilisant la position de chaque élément Xamarin.Forms dans la présentation de formulaire, je crée un SkPath reliant tous les éléments de formulaire, puis dessine le SkPath créé sur le SKCanvasView vue. Voici comment SkPath complet se présente comme suit:

 COMPLE ~ 1 "data-displaymode =" Original "title =" COMPLE ~ 1 "/></p data-recalc-dims=

Pour faciliter la mise en oeuvre, c'est Il est important que le SKCanvasView ait les mêmes coordonnées d'écran en haut à gauche que la présentation de formulaire StackLayout ce qui facilite le calcul de la traduction entre la position de l'élément Xamarin.Forms dans le StackLayout à la position SkiaSharp utilisée pour dessiner le SkPath sur le SKCanvasView . Voici le XAML, qui montre le SkCanvasView et le formulaire enveloppé. dans une grille :

 < Grille > 
 < Grille.Définitions > 
 < ColumnDefinition   ] =  " Auto "   /> 
 </  Grid.ColumnDefinitions > 
 <[19659224] skiaSharp:  SKCanvasView   x:  Name  =  " _skCanvasView " 
 PaintSurface  =  "
 SizeChanged  = "  SkCanvasViewSizeChanged  "   /> 19659125] < StackLayout   x: Images de référence ] =  " _formLayout "   ... > 
 ...
 </  StackLayout > 
 </  Grille >  

Création du SkPath basé sur la position de Xamarin. Les éléments de formulaire sont implémentés dans la méthode CreatePathHighlightInfo ici .

Rendre certaines parties de SkPath visibles à l'aide de l'effet Chemin du tiret

Lorsqu'un élément reçoit le focus, je ne rend visible que la partie. du SkPath destiné à représenter l'élément mis en évidence:

 DASH_P ~ 1 "data-displaymode =" Original "title =" DASH_P ~ 1 "/></p data-recalc-dims=

Ceci est accomplit en créant un effet de chemin en trait ( SkPathEffect ) et en peignant avec lui le SkPath :

 paint .  PathEffect  =  SKPathEffect .  CreateDash  ( intervalles :  strokeDash .  Intervalle  phase : : . 04] strokeDash .  Phase ) ; 
skCanvas .  DrawPath  ( skPath  paint ) ; 

Comme vous pouvez le voir, le CreatesDash prend un tableau d'intervalles et une phase .

Les intervalles sont un tableau de valeurs flottantes indiquant la longueur de l'intervalle d'activation. et la longueur de l'intervalle “off” . Par exemple, un tableau d'intervalles avec les éléments 10, 5 placés sur un chemin de ligne crée l'effet de voir 10 pixels suivis d'un intervalle de 5 pixels (en supposant que la largeur du trait est de 1 pixel), et cette succession se répète le long du chemin: [19659003]  DASH_I ~ 1 "data-displaymode =" Original "title =" DASH_I ~ 1 "/></p data-recalc-dims=

La règle de ce tableau d'intervalles est que le tableau doit contenir au moins deux valeurs et doit être de type pair nombre de valeurs, et les valeurs sont interprétées comme une succession d'intervalles "on" et "off".

La valeur phase représente le décalage utilisé pour tracer le début de la Par exemple, si nous avons un intervalle de 10, 5 et la phase est 5, nous verrons quelque chose comme:

 DASH_I ~ 2 "data-displaymode =" Original "title =" DASH_I ~ 2 "/></p data-recalc-dims=

Pour mettre en évidence le premier Entrée par exemple, l'intervalle d'activation correspond à la largeur de l'entrée l'intervalle" arrêt "correspond à l'intervalle rem

Vous pouvez en savoir plus sur l’influence de la largeur de trait et de la casquette sur le trajet, que vous pouvez consulter dans l’excellente documentation Xamarin pour Skia.Sharp ici .

Dans le cadre de la création du chemin du point culminant, à côté de la construction du SkPath je construis également un tableau de tirets représentant les intervalles du chemin correspondant à la mise en évidence de chaque Entrée . et Élément Button :

 DASH_F ~ 1 "data-displaymode =" Original "title =" DASH_F ~ 1 "/></p data-recalc-dims=


 class   HighlightPath 
 {
 en lecture seule  Dictionnaire  < int  de la série StrokeDash >  de [1945927]]. ] new   Dictionary  < int  StrokeDash >  () ; 
. . . 
} 
 class   StrokeDash 
 {
 public   float  []  Intervalles  {  get ;  ; ] set ;  } 
 public   float  Phase  {  get ;   set ;  ] 
. . . 
} 

J'utilise la position de l'élément sur la présentation du formulaire comme une clé pour savoir comment obtenir le tiret basé sur l'élément ciblé.

J'ai trois éléments Entry et un bouton . La liste de tirets contient quatre entrées représentant les valeurs de tirets, ce qui rend le chemin visible lorsque chaque élément a le focus. Voici une capture d'écran avec les valeurs de tiret du débogueur:

 DASH_F ~ 2 "title =" DASH_F ~ 2 "/></p data-recalc-dims=

Animation du surlignage entre éléments

Pour que le surlignage apparaisse comme tel En me déplaçant entre les éléments de formulaire, j'anime les valeurs de tiret (intervalles et phase), des valeurs de tiret actuelles aux valeurs de tiret précalculées correspondant à l'élément devant apparaître en surbrillance.

J'ai commencé par créer mon propre StrokeDashAnimation classe, qui encapsule animant le trait dans le trait les intervalles et phase valeurs:

  classe   StrokeDashAnimation 
 {
StrokeDash _currStrokeDash ; 
 public  StrokeDash de  {  get ;  } 
 public  StrokeDash jusqu'à  [  ];  } 
 public  Durée du temps  {  get ;  } 
 public  Amélioration de la vitesse  {   } 
 public   StrokeDashAnimation  ( StrokeDash  de  de StrokeDash à  de temps []] ] {
De  =   de ; 
À  =  à ; 
Durée  =  durée ; 
} 
. . . 
} 

J'utilise la classe StrokeDash pour encapsuler valeur de tiret actuelle, dont les animations et les propriétés de phase sont mises à jour séparément pour chaque animation.

Si vous n'avez pas utilisé d'animation dans Xamarin.Forms, le cadre dispose d'un support très simple mais très puissant pour la création d'animations basées sur l'animation d'un double valeur.

Le fonctionnement de Animation est très simple: vous lui donnez un début double un double fin valeur et un type d'accélération. L'animation utilise l'accélération pour calculer la valeur interpolée entre les valeurs de début et de fin. Une fois que vous avez commencé à utiliser la méthode Commit une instance de Animation appellera votre rappel pour chaque valeur calculée, en commençant par la valeur initiale donnée jusqu'à atteindre la valeur finale.

Animation peut contenir d'autres instances de Animation . Lorsque vous démarrez l'animation parent, ses animations enfants commencent.

Pour en savoir plus sur l'animation Xamarin.Forms et ses fonctionnalités, cliquez ici: https: //docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/animation/[19459012_rev19199003]Dans ma mise en œuvre, je crée une animation contenant trois animations internes pour chaque propriété de trait d'un trait: intervalle “ on ”, intervalle“ off ”et phase:

  class   StrokeDashAnimation 
 {
StrokeDash _currStrokeDash ; 
 public  StrokeDash de  {  get ;  } 
 public  StrokeDash jusqu'à  [  ];  } 
 public  Durée du temps  {  get ;  } 
 public  Amélioration de la vitesse  {   } 
 public   StrokeDashAnimation  ( StrokeDash  de  de StrokeDash à  de temps []] ] {
De  =   de ; 
À  =  à ; 
Durée  =  Durée ; 
} 
 public   void   Start  ( Action  < StrokeDash >  onValueCallback ) 
 {
_currStrokeDash  =  De ; 
 var  anim  =   nouveau   Animation  ( ( v ). 19659389] = >   surValueCallback  ( _currStrokeDash ) ) ; 
anim .  Ajouter  [ 0   1   nouveau   Animation  (
callback :  v  = >  _currStrokeDash .  Phase  =   ( float ). 
début :  à partir de .  Phase 
fin :  à .  Phase 
assouplissement :  assouplissement ) ) ; 
anim .  Ajouter  [ 0   1   nouveau   Animation  (
callback :  v  = >  _currStrokeDash .  Intervalles  [ 0 ]   =   19659080] float )  v 
début :  à partir de .  intervalles  [ 0 ] 
fin :  à .  Intervalles  [ 0 ] 
assouplissement :  assouplissement ) ) ; 
anim .  Ajouter  [ 0   1   nouveau   Animation  (
rappel :  v  = >  _currStrokeDash .  Intervalles  [ 1 ]   =   19659080] float )  v 
début :  à partir de .  intervalles  [ 1 ] 
fin :  à .  Intervalles  [ 1 ] 
assouplissement :  assouplissement ) ) ; 
anim .  Commit  (
owner :  Application .  Actuelle .  Page principale 
nom :   "highlightAnimation" 
longueur :   ( uint )  Durée .  TotalMillisecondes ) ; 
} 
} 
 le focus est changé en un  Entrée  ou  Bouton  est cliqué, je lance l'animation en passant des valeurs de tiret actuelles aux valeurs de tiret précalculées: 

  void   DrawDash  ( SKCanvasView skCanvasView  StrokeDash fromDash  StrokeDash toDash ) 
 {
 si   de [1945904] deDash [1945904]. ! =   null ) 
 {
 var  anim  =   new   StrokeDashAnimation  (
 de :  duDash 
à :  àDash 
durée :  _highlightSettings .  AnimationDuration ) ; 
anim .  Début  ( ( strokeDashToDraw )   = >   RequestDraw  ( skCanvasView  strokeDashToDraw ) ) ; 
} 
 autre 
 RequestDraw  ( skCanasView  duDash  ; 
} 
 void   RequestDraw  ( SKCanvasView skCanvasView  StrokeDash strokeDashToDraw ) 
 [
_highlightState .  StrokeDash  =  strokeDashToDraw ; 
skCanvasView .  InvalidateSurface  () ; 
} 

Pour chaque nouvelle valeur de trait de trait calculé, j'invalide la surface SkCanvasView afin d'invalider faites-le déclencher son événement PaintSurface . Sur le gestionnaire d'événement paint, je trace le chemin avec les nouvelles valeurs de tiret conservées par _highlightState.StrokeDash :

  public   nul   Draw  ( SKCanView skCanvasView  SKCanvas skCanvas ) 
{
skCanvas . Clear () ;
if ( _highlightState == null )
retour ;
if ( _skPaint == null )
_skPaint = CreateHighlightSkPaint ( skCanvasView _highlightSettings _highlightState
StrokeDash strokeDash = _highlightState . StrokeDash ;
// Commentez la ligne suivante pour afficher le chemin complet sans effet de tiret
_skPaint . PathEffect = SKPathEffect . CreateDash ( strokeDash . [19459904]. [19459264]. . Phase ) ;
skCanvas . DrawPath ( _highlightState . HighlightPath . Tracé




Source link