Kerngrafiken in Xamarin.iOS
In diesem Artikel werden die Core Graphics iOS-Frameworks erläutert. Es zeigt, wie Sie mit Core Graphics Geometrie, Bilder und PDF-Dateien zeichnen.
iOS enthält das Core Graphics Framework, um Unterstützung für Die Zeichnung auf niedriger Ebene bereitzustellen. Diese Frameworks ermöglichen die umfangreichen grafischen Funktionen in UIKit.
Core Graphics ist ein 2D-Grafikframework auf niedriger Ebene, das unabhängige Grafiken für Das Zeichnen von Geräten ermöglicht. Alle 2D-Zeichnung in UIKit verwendet Core Graphics intern.
Kerngrafiken unterstützen das Zeichnen in einer Reihe von Szenarien, einschließlich:
- Zeichnen auf dem Bildschirm über ein
UIView
. - Zeichnen von Bildern im Arbeitsspeicher oder auf dem Bildschirm
- Erstellen und Zeichnen in einer PDF-Datei.
- Lesen und Zeichnen einer vorhandenen PDF-Datei.
Geometrischer Raum
Unabhängig vom Szenario erfolgt die gesamte Zeichnung mit Core Graphics im geometrischen Raum, was bedeutet, dass sie in abstrakten Punkten und nicht in Pixeln funktioniert. Sie beschreiben, was In Bezug auf Geometrie und Zeichnungszustand gezeichnet werden soll, z. B. Farben, Linienarten usw. und Kerngrafikhandles, die alles in Pixel übersetzen. Dieser Zustand wird einem Grafikkontext hinzugefügt, den Sie sich wie die Canvas eines Malers vorstellen können.
Für diesen Ansatz gibt es einige Vorteile:
- Zeichnungscode wird dynamisch und kann anschließend Grafiken zur Laufzeit ändern.
- Die Verringerung der Notwendigkeit statischer Bilder im Anwendungsbundle kann die Anwendungsgröße verringern.
- Grafiken werden widerstandsfähiger für Auflösungsänderungen auf allen Geräten.
Zeichnen in einer UIView-Unterklasse
Jedes UIView
verfügt über eine Draw
Methode, die vom System aufgerufen wird, wenn sie gezeichnet werden muss. So fügen Sie einer Ansicht, Unterklasse UIView
und Außerkraftsetzung Draw
Zeichnungscode hinzu:
public class TriangleView : UIView
{
public override void Draw (CGRect rect)
{
base.Draw (rect);
}
}
Draw sollte niemals direkt aufgerufen werden. Es wird vom System während der Ausführungsschleifenverarbeitung aufgerufen. Wenn eine Ansicht der Ansichtshierarchie zum ersten Mal durch die Ausführungsschleife hinzugefügt wurde, wird die Draw
Methode aufgerufen. Nachfolgende Aufrufe, die auftreten, Draw
wenn die Ansicht als gezeichnet werden muss, indem sie entweder SetNeedsDisplay
oder SetNeedsDisplayInRect
in der Ansicht aufgerufen werden muss.
Muster für Grafikcode
Der Code in der Draw
Implementierung sollte beschreiben, was gezeichnet werden soll. Der Zeichnungscode folgt einem Muster, in dem er einen Zeichnungszustand festlegt und eine Methode aufruft, um die Zeichnung anzufordern. Dieses Muster kann wie folgt generalisiert werden:
Rufen Sie einen Grafikkontext ab.
Einrichten von Zeichnungsattributen.
Erstellen Sie einige Geometrien aus Zeichnungsgrundtypen.
Rufen Sie eine Draw- oder Stroke-Methode auf.
Beispiel für einfache Zeichnung
Sehen Sie sich z. B. folgenden Codeausschnitt an:
//get graphics context
using (CGContext g = UIGraphics.GetCurrentContext ()) {
//set up drawing attributes
g.SetLineWidth (10);
UIColor.Blue.SetFill ();
UIColor.Red.SetStroke ();
//create geometry
var path = new CGPath ();
path.AddLines (new CGPoint[]{
new CGPoint (100, 200),
new CGPoint (160, 100),
new CGPoint (220, 200)});
path.CloseSubpath ();
//add geometry to graphics context and draw it
g.AddPath (path);
g.DrawPath (CGPathDrawingMode.FillStroke);
}
Lassen Sie uns diesen Code aufschlüsseln:
using (CGContext g = UIGraphics.GetCurrentContext ()) {
...
}
Mit dieser Linie wird zunächst der aktuelle Grafikkontext für die Zeichnung verwendet. Sie können sich einen Grafikkontext vorstellen, da der Zeichenbereich, auf dem die Zeichnung ausgeführt wird, den gesamten Zustand der Zeichnung enthält, z. B. Strich- und Füllfarben, sowie die zu zeichnende Geometrie.
g.SetLineWidth (10);
UIColor.Blue.SetFill ();
UIColor.Red.SetStroke ();
Nach dem Abrufen eines Grafikkontexts richtet der Code einige Attribute ein, die beim Zeichnen verwendet werden sollen, wie oben gezeigt. In diesem Fall werden die Linienbreite, Strich- und Füllfarben festgelegt. Jede nachfolgende Zeichnung verwendet dann diese Attribute, da sie im Zustand des Grafikkontexts beibehalten werden.
Zum Erstellen der Geometrie verwendet der Code einen CGPath
, der es ermöglicht, einen Grafikpfad aus Linien und Kurven zu beschreiben. In diesem Fall fügt der Pfad Linien hinzu, die ein Array von Punkten verbinden, um ein Dreieck zu bilden. Wie unten dargestellt, verwendet Core Graphics ein Koordinatensystem für die Ansichtszeichnung, wobei sich der Ursprung oben links befindet, mit positivem x-direkt nach rechts und der positiven Richtung nach unten:
var path = new CGPath ();
path.AddLines (new CGPoint[]{
new CGPoint (100, 200),
new CGPoint (160, 100),
new CGPoint (220, 200)});
path.CloseSubpath ();
Nachdem der Pfad erstellt wurde, wird er dem Grafikkontext hinzugefügt, sodass der Aufruf AddPath
bzw DrawPath
. er gezeichnet werden kann.
Die resultierende Ansicht wird unten angezeigt:
Erstellen von Farbverlaufsfüllungen
Umfangreichere Zeichnungsarten sind ebenfalls verfügbar. Beispielsweise ermöglicht Core Graphics das Erstellen von Farbverlaufsfüllungen und das Anwenden von Clippingpfaden. Um eine Farbverlaufsfüllung innerhalb des Pfads aus dem vorherigen Beispiel zu zeichnen, muss zuerst der Pfad als Clippingpfad festgelegt werden:
// add the path back to the graphics context so that it is the current path
g.AddPath (path);
// set the current path to be the clipping path
g.Clip ();
Durch Festlegen des aktuellen Pfads als Clippingpfad wird die gesamte nachfolgende Zeichnung innerhalb der Geometrie des Pfads eingeschränkt, z. B. der folgende Code, der einen linearen Farbverlauf zeichnet:
// the color space determines how Core Graphics interprets color information
using (CGColorSpace rgb = CGColorSpace.CreateDeviceRGB()) {
CGGradient gradient = new CGGradient (rgb, new CGColor[] {
UIColor.Blue.CGColor,
UIColor.Yellow.CGColor
});
// draw a linear gradient
g.DrawLinearGradient (
gradient,
new CGPoint (path.BoundingBox.Left, path.BoundingBox.Top),
new CGPoint (path.BoundingBox.Right, path.BoundingBox.Bottom),
CGGradientDrawingOptions.DrawsBeforeStartLocation);
}
Diese Änderungen erzeugen eine Farbverlaufsfüllung wie unten dargestellt:
Ändern von Linienmustern
Die Zeichnungsattribute von Linien können auch mit Core Graphics geändert werden. Dazu gehören das Ändern der Linienbreite und der Strichfarbe sowie des Linienmusters selbst, wie im folgenden Code dargestellt:
//use a dashed line
g.SetLineDash (0, new nfloat[] { 10, 4 * (nfloat)Math.PI });
Wenn Sie diesen Code hinzufügen, bevor zeichnungsvorgänge 10 Striche lang sind, mit 4 Einheiten Abstand zwischen Strichen, wie unten dargestellt:
Beachten Sie, dass bei Verwendung der einheitlichen API in Xamarin.iOS der Arraytyp ein nfloat
Arraytyp sein muss und auch explizit in Math.PI umgestellt werden muss.
Zeichnungsbilder und Text
Neben Zeichnungspfaden im Grafikkontext einer Ansicht unterstützt Core Graphics auch Zeichnungsbilder und Text. Um ein Bild zu zeichnen, erstellen Sie einfach ein CGImage
Bild, und übergeben Sie es an einen DrawImage
Anruf:
public override void Draw (CGRect rect)
{
base.Draw (rect);
using(CGContext g = UIGraphics.GetCurrentContext ()){
g.DrawImage (rect, UIImage.FromFile ("MyImage.png").CGImage);
}
}
Dies erzeugt jedoch ein Bild, das auf dem Kopf gezeichnet wird, wie unten dargestellt:
Der Grund dafür ist core Graphics origin for image drawing is in the lower left, while the view has its origin in the upper left. Damit das Bild korrekt angezeigt wird, muss der Ursprung geändert werden, der durch Ändern der Current Transformation Matrix (CTM) erreicht werden kann. Das CTM definiert, wo Punkte leben, auch als Benutzerbereich bezeichnet. Das Umkehren des CTM in die y-Richtung und das Verschieben durch die Höhe der Grenzen in der negativen Y-Richtung kann das Bild kippen.
Der Grafikkontext verfügt über Hilfsmethoden zum Transformieren des CTM. In diesem Fall ScaleCTM
wird die Zeichnung gedreht und TranslateCTM
nach oben links verschoben, wie unten dargestellt:
public override void Draw (CGRect rect)
{
base.Draw (rect);
using (CGContext g = UIGraphics.GetCurrentContext ()) {
// scale and translate the CTM so the image appears upright
g.ScaleCTM (1, -1);
g.TranslateCTM (0, -Bounds.Height);
g.DrawImage (rect, UIImage.FromFile ("MyImage.png").CGImage);
}
Das resultierende Bild wird dann aufrecht angezeigt:
Wichtig
Änderungen am Grafikkontext gelten für alle nachfolgenden Zeichnungsvorgänge. Wenn das CTM transformiert wird, wirkt es sich daher auf jede zusätzliche Zeichnung aus. Wenn Sie z. B. das Dreieck nach der CTM-Transformation gezeichnet haben, erscheint es auf dem Kopf.
Hinzufügen von Text zum Bild
Wie bei Pfaden und Bildern umfasst das Zeichnen von Text mit Core Graphics dasselbe grundlegende Muster zum Festlegen eines Grafikzustands und aufrufen einer Methode zum Zeichnen. Im Fall von Text lautet ShowText
die Methode zum Anzeigen von Text . Wenn Sie dem Beispiel für die Bildzeichnung hinzugefügt werden, zeichnet der folgende Code Text mithilfe von Core Graphics:
public override void Draw (RectangleF rect)
{
base.Draw (rect);
// image drawing code omitted for brevity ...
// translate the CTM by the font size so it displays on screen
float fontSize = 35f;
g.TranslateCTM (0, fontSize);
// set general-purpose graphics state
g.SetLineWidth (1.0f);
g.SetStrokeColor (UIColor.Yellow.CGColor);
g.SetFillColor (UIColor.Red.CGColor);
g.SetShadow (new CGSize (5, 5), 0, UIColor.Blue.CGColor);
// set text specific graphics state
g.SetTextDrawingMode (CGTextDrawingMode.FillStroke);
g.SelectFont ("Helvetica", fontSize, CGTextEncoding.MacRoman);
// show the text
g.ShowText ("Hello Core Graphics");
}
Wie Sie sehen können, ähnelt das Festlegen des Grafikzustands für die Textzeichnung der Zeichnungsgeometrie. Bei der Textzeichnung werden jedoch auch der Textzeichnungsmodus und die Schriftart angewendet. In diesem Fall wird auch ein Schatten angewendet, obwohl das Anwenden von Schatten für die Pfadzeichnung identisch ist.
Der resultierende Text wird wie unten dargestellt mit dem Bild angezeigt:
Speichergestützte Bilder
Neben dem Zeichnen auf den Grafikkontext einer Ansicht unterstützt Core Graphics das Zeichnen von Hintergrundbildern, auch als Offscreen-Zeichnung bezeichnet. Dazu ist Folgendes erforderlich:
- Erstellen eines Grafikkontexts, der von einer Speicherbitmap unterstützt wird
- Festlegen des Zeichnungszustands und Ausstellen von Zeichenbefehlen
- Abrufen des Bilds aus dem Kontext
- Entfernen des Kontexts
Im Gegensatz zu der Draw
Methode, in der der Kontext von der Ansicht bereitgestellt wird, erstellen Sie in diesem Fall den Kontext auf eine von zwei Arten:
Durch Aufrufen
UIGraphics.BeginImageContext
(oderBeginImageContextWithOptions
)Durch Erstellen eines neuen
CGBitmapContextInstance
CGBitmapContextInstance
ist nützlich, wenn Sie direkt mit den Bildbits arbeiten, z. B. für Fälle, in denen Sie einen benutzerdefinierten Bildmanipulationsalgorithmus verwenden. In allen anderen Fällen sollten Sie verwenden BeginImageContext
oder BeginImageContextWithOptions
.
Sobald Sie einen Bildkontext haben, ist das Hinzufügen von Zeichnungscode genau wie in einer UIView
Unterklasse. Das Codebeispiel, das zuvor zum Zeichnen eines Dreiecks verwendet wurde, kann z. B. zum Zeichnen auf ein Bild im Arbeitsspeicher anstelle in einem UIView
, wie unten dargestellt, verwendet werden:
UIImage DrawTriangle ()
{
UIImage triangleImage;
//push a memory backed bitmap context on the context stack
UIGraphics.BeginImageContext (new CGSize (200.0f, 200.0f));
//get graphics context
using(CGContext g = UIGraphics.GetCurrentContext ()){
//set up drawing attributes
g.SetLineWidth(4);
UIColor.Purple.SetFill ();
UIColor.Black.SetStroke ();
//create geometry
path = new CGPath ();
path.AddLines(new CGPoint[]{
new CGPoint(100,200),
new CGPoint(160,100),
new CGPoint(220,200)});
path.CloseSubpath();
//add geometry to graphics context and draw it
g.AddPath(path);
g.DrawPath(CGPathDrawingMode.FillStroke);
//get a UIImage from the context
triangleImage = UIGraphics.GetImageFromCurrentImageContext ();
}
return triangleImage;
}
Eine häufige Verwendung der Zeichnung auf eine speichergestützte Bitmap besteht darin, ein Bild aus einem beliebigen UIView
Objekt zu erfassen. Der folgende Code rendert z. B. die Ebene einer Ansicht in einem Bitmapkontext und erstellt daraus eine UIImage
:
UIGraphics.BeginImageContext (cellView.Frame.Size);
//render the view's layer in the current context
anyView.Layer.RenderInContext (UIGraphics.GetCurrentContext ());
//get a UIImage from the context
UIImage anyViewImage = UIGraphics.GetImageFromCurrentImageContext ();
UIGraphics.EndImageContext ();
Zeichnen von PDF-Dateien
Neben Bildern unterstützt Core Graphics die PDF-Zeichnung. Wie Bilder können Sie eine PDF-Datei im Arbeitsspeicher rendern sowie eine PDF-Datei zum Rendern in einer UIView
Datei lesen.
PDF in einer UIView
Kerngrafiken unterstützen auch das Lesen einer PDF-Datei aus einer Datei und das Rendern in einer Ansicht mithilfe der CGPDFDocument
Klasse. Die CGPDFDocument
Klasse stellt eine PDF-Datei im Code dar und kann zum Lesen und Zeichnen von Seiten verwendet werden.
Der folgende Code in einer UIView
Unterklasse liest z. B. eine PDF-Datei aus einer Datei in eine CGPDFDocument
:
public class PDFView : UIView
{
CGPDFDocument pdfDoc;
public PDFView ()
{
//create a CGPDFDocument from file.pdf included in the main bundle
pdfDoc = CGPDFDocument.FromFile ("file.pdf");
}
public override void Draw (Rectangle rect)
{
...
}
}
Mit Draw
der CGPDFDocument
Methode können Sie dann eine Seite CGPDFPage
lesen und rendern, indem sie aufgerufen wird DrawPDFPage
, wie unten dargestellt:
public override void Draw (CGRect rect)
{
base.Draw (rect);
//flip the CTM so the PDF will be drawn upright
using (CGContext g = UIGraphics.GetCurrentContext ()) {
g.TranslateCTM (0, Bounds.Height);
g.ScaleCTM (1, -1);
// render the first page of the PDF
using (CGPDFPage pdfPage = pdfDoc.GetPage (1)) {
//get the affine transform that defines where the PDF is drawn
CGAffineTransform t = pdfPage.GetDrawingTransform (CGPDFBox.Crop, rect, 0, true);
//concatenate the pdf transform with the CTM for display in the view
g.ConcatCTM (t);
//draw the pdf page
g.DrawPDFPage (pdfPage);
}
}
}
Speichergestützte PDF-Datei
Für eine im Arbeitsspeicher gespeicherte PDF-Datei müssen Sie einen PDF-Kontext erstellen, indem Sie aufrufen BeginPDFContext
. Das Zeichnen auf PDF ist für Seiten präzise. Jede Seite wird gestartet, indem sie durch Aufrufen BeginPDFPage
und Abschließen des Grafikcodes dazwischen aufgerufen EndPDFContent
und abgeschlossen wird. Ebenso wie bei der Bildzeichnung verwendet die zurückgesicherte PDF-Zeichnung einen Ursprung in der unteren linken Ecke, der durch Ändern des CTM wie bei Bildern berücksichtigt werden kann.
Der folgende Code zeigt, wie Text in eine PDF-Datei gezeichnet wird:
//data buffer to hold the PDF
NSMutableData data = new NSMutableData ();
//create a PDF with empty rectangle, which will configure it for 8.5x11 inches
UIGraphics.BeginPDFContext (data, CGRect.Empty, null);
//start a PDF page
UIGraphics.BeginPDFPage ();
using (CGContext g = UIGraphics.GetCurrentContext ()) {
g.ScaleCTM (1, -1);
g.TranslateCTM (0, -25);
g.SelectFont ("Helvetica", 25, CGTextEncoding.MacRoman);
g.ShowText ("Hello Core Graphics");
}
//complete a PDF page
UIGraphics.EndPDFContent ();
Der resultierende Text wird auf die PDF-Datei gezeichnet, die dann in einer NSData
gespeicherten, hochgeladenen, per E-Mail gesendeten usw. gespeichert werden kann.
Zusammenfassung
In diesem Artikel haben wir uns die Grafikfunktionen angesehen, die über das Core Graphics Framework bereitgestellt werden. Wir haben gesehen, wie Sie mit Core Graphics Geometrie, Bilder und PDF-Dateien im Kontext einer UIView,
sowie speichergestützter Grafikkontexte zeichnen können.