Unités indépendantes de l’appareil et pixels
Explorer les différences entre les coordonnées et Xamarin.Forms les coordonnées SkiaSharp
Cet article explore les différences dans le système de coordonnées utilisé dans SkiaSharp et Xamarin.Forms. Vous pouvez obtenir des informations à convertir entre les deux systèmes de coordonnées et dessiner des graphiques qui remplissent une zone particulière :
Si vous avez été en Xamarin.Forms programmation depuis un certain temps, vous pouvez avoir une impression de Xamarin.Forms coordonnées et de tailles. Les cercles dessinés dans les deux articles précédents peuvent sembler un peu petits pour vous.
Ces cercles sont petits par rapport aux Xamarin.Forms tailles. Par défaut, SkiaSharp dessine en unités de pixels tandis que Xamarin.Forms les coordonnées et tailles de base sur une unité indépendante de l’appareil établie par la plateforme sous-jacente. (Pour plus d’informations sur le système de coordonnées, consultez le Xamarin.Forms chapitre 5. Gestion des tailles du livre Création d’applications mobiles avec Xamarin.Forms.)
La page de l’exemple de programme intitulé Surface Size utilise la sortie de texte SkiaSharp pour afficher la taille de l’aire d’affichage à partir de trois sources différentes :
- Xamarin.Forms
Width
Normal etHeight
propriétés de l’objetSKCanvasView
. - Propriété
CanvasSize
de l'objetSKCanvasView
. - Propriété
Size
de laSKImageInfo
valeur, qui est cohérente avec lesWidth
Height
propriétés utilisées dans les deux pages précédentes.
La SurfaceSizePage
classe montre comment afficher ces valeurs. Le constructeur enregistre l’objet SKCanvasView
en tant que champ, afin qu’il soit accessible dans le PaintSurface
gestionnaire d’événements :
SKCanvasView canvasView;
public SurfaceSizePage()
{
Title = "Surface Size";
canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
SKCanvas
comprend six méthodes différentes DrawText
, mais cette DrawText
méthode est la plus simple :
public void DrawText (String text, Single x, Single y, SKPaint paint)
Vous spécifiez la chaîne de texte, les coordonnées X et Y où le texte doit commencer et un SKPaint
objet. La coordonnée X spécifie où le côté gauche du texte est positionné, mais attention : la coordonnée Y spécifie la position de la ligne de base du texte. Si vous avez déjà écrit à la main sur du papier aligné, la ligne de base est la ligne sur laquelle les caractères s’assoient et sous lesquels descendent les décroissants (tels que ceux des lettres g, p, q et y) descendent.
L’objet SKPaint
vous permet de spécifier la couleur du texte, la famille de polices et la taille du texte. Par défaut, la TextSize
propriété a la valeur 12, ce qui entraîne un texte minuscule sur des appareils haute résolution tels que les téléphones. Dans les applications les plus simples, vous aurez également besoin d’informations sur la taille du texte que vous affichez. La SKPaint
classe définit une FontMetrics
propriété et plusieurs MeasureText
méthodes, mais pour des besoins moins sophistiqués, la FontSpacing
propriété fournit une valeur recommandée pour l’espacement des lignes successives de texte.
Le gestionnaire suivant PaintSurface
crée un SKPaint
objet pour un TextSize
objet de 40 pixels, qui correspond à la hauteur verticale souhaitée du texte du haut des croissants au bas des décroissants. La FontSpacing
valeur retournée par l’objet SKPaint
est un peu plus grande que celle-ci, soit environ 47 pixels.
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
SKPaint paint = new SKPaint
{
Color = SKColors.Black,
TextSize = 40
};
float fontSpacing = paint.FontSpacing;
float x = 20; // left margin
float y = fontSpacing; // first baseline
float indent = 100;
canvas.DrawText("SKCanvasView Height and Width:", x, y, paint);
y += fontSpacing;
canvas.DrawText(String.Format("{0:F2} x {1:F2}",
canvasView.Width, canvasView.Height),
x + indent, y, paint);
y += fontSpacing * 2;
canvas.DrawText("SKCanvasView CanvasSize:", x, y, paint);
y += fontSpacing;
canvas.DrawText(canvasView.CanvasSize.ToString(), x + indent, y, paint);
y += fontSpacing * 2;
canvas.DrawText("SKImageInfo Size:", x, y, paint);
y += fontSpacing;
canvas.DrawText(info.Size.ToString(), x + indent, y, paint);
}
La méthode commence la première ligne de texte avec une coordonnée X de 20 (pour une petite marge à gauche) et une coordonnée Y de fontSpacing
, qui est un peu plus que ce qui est nécessaire pour afficher la hauteur complète du premier trait de texte en haut de la surface d’affichage. Après chaque appel à DrawText
, la coordonnée Y est augmentée par un ou deux incréments de fontSpacing
.
Voici le programme en cours d’exécution :
Comme vous pouvez le voir, la CanvasSize
propriété et SKCanvasView
la Size
propriété de la SKImageInfo
valeur sont cohérentes dans la création de rapports sur les dimensions de pixels. Les Height
propriétés et Width
les propriétés sont Xamarin.Forms SKCanvasView
des propriétés et signalent la taille de la vue dans les unités indépendantes de l’appareil définies par la plateforme.
Le simulateur iOS sept sur la gauche a deux pixels par unité indépendante de l’appareil, et Android Nexus 5 dans le centre a trois pixels par unité. C’est pourquoi le cercle simple présenté précédemment a des tailles différentes sur différentes plateformes.
Si vous préférez travailler entièrement dans des unités indépendantes de l’appareil, vous pouvez le faire en définissant la IgnorePixelScaling
propriété sur true
SKCanvasView
. Toutefois, vous n’aurez peut-être pas l’impression des résultats. SkiaSharp restitue les graphiques sur une surface d’appareil plus petite, avec une taille de pixel égale à la taille de la vue dans les unités indépendantes de l’appareil. (Par exemple, SkiaSharp utilise une surface d’affichage de 360 x 512 pixels sur le Nexus 5.) Il effectue ensuite un scale-up de cette image en taille, ce qui entraîne des jaggies bitmap notables.
Pour maintenir la même résolution d’images, une meilleure solution consiste à écrire vos propres fonctions simples pour effectuer une conversion entre les deux systèmes de coordonnées.
En plus de la DrawCircle
méthode, SKCanvas
définit également deux DrawOval
méthodes qui dessinent un ellipse. Un ellipse est défini par deux rayons plutôt qu’un rayon unique. Il s’agit du rayon principal et du rayon mineur. La DrawOval
méthode dessine un ellipse avec les deux rayons parallèles aux axes X et Y. (Si vous devez dessiner un ellipse avec des axes qui ne sont pas parallèles aux axes X et Y, vous pouvez utiliser une transformation de rotation comme indiqué dans l’article La transformation de rotation ou un chemin graphique, comme indiqué dans l’article Trois façons de dessiner un arc. Cette surcharge de la DrawOval
méthode nomme les deux paramètres rx
radii et ry
indique qu’ils sont parallèles aux axes X et Y :
public void DrawOval (Single cx, Single cy, Single rx, Single ry, SKPaint paint)
Est-il possible de dessiner un ellipse qui remplit la surface d’affichage ? La page Ellipse Fill montre comment procéder. Le PaintSurface
gestionnaire d’événements de la classe EllipseFillPage.xaml.cs soustrait la moitié de la largeur du trait à partir des valeurs et yRadius
à l’ensemble xRadius
des points de suspension et de son contour dans la surface d’affichage :
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
float strokeWidth = 50;
float xRadius = (info.Width - strokeWidth) / 2;
float yRadius = (info.Height - strokeWidth) / 2;
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Blue,
StrokeWidth = strokeWidth
};
canvas.DrawOval(info.Width / 2, info.Height / 2, xRadius, yRadius, paint);
}
Ici, il est en cours d’exécution :
L’autre DrawOval
méthode a un SKRect
argument, qui est un rectangle défini en termes de coordonnées X et Y de son angle supérieur gauche et du coin inférieur droit. L’ovale remplit ce rectangle, ce qui suggère qu’il peut être possible de l’utiliser dans la page Ellipse Fill comme suit :
SKRect rect = new SKRect(0, 0, info.Width, info.Height);
canvas.DrawOval(rect, paint);
Toutefois, cela tronque tous les bords du contour de l’ellipse sur les quatre côtés. Vous devez ajuster tous les arguments du SKRect
constructeur en fonction de ce strokeWidth
qui suit :
SKRect rect = new SKRect(strokeWidth / 2,
strokeWidth / 2,
info.Width - strokeWidth / 2,
info.Height - strokeWidth / 2);
canvas.DrawOval(rect, paint);