Bei vielen Apps muss genau gesteuert werden können, was auf dem Bildschirm gezeichnet wird. Das kann so einfach sein wie das Platzieren eines Quadrats oder Kreises an der richtigen Stelle auf dem Bildschirm oder eine ausgefeilte Anordnung von grafischen Elementen in vielen verschiedenen Stilen.
Einfache Zeichnung mit Modifikatoren und DrawScope
Die Hauptmethode zum Zeichnen benutzerdefinierter Elemente in Compose sind Modifikatoren wie Modifier.drawWithContent
, Modifier.drawBehind
und Modifier.drawWithCache
.
Wenn Sie beispielsweise etwas hinter Ihrem Composeable zeichnen möchten, können Sie mit der Tastenkombination drawBehind
Zeichenbefehle ausführen:
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
Wenn Sie nur ein grafisches Element benötigen, können Sie das Canvas
-Element verwenden. Das Canvas
-Komposit ist eine praktische Ummantelung für Modifier.drawBehind
. Sie platzieren das Canvas
in Ihrem Layout genauso wie jedes andere Compose-UI-Element. In der Canvas
können Sie Elemente zeichnen und dabei Stil und Position genau festlegen.
Alle Zeichenmodifikatoren stellen eine DrawScope
bereit, eine begrenzte Zeichenumgebung, die ihren eigenen Status beibehält. So können Sie die Parameter für eine Gruppe von grafischen Elementen festlegen. Das DrawScope
-Objekt bietet mehrere nützliche Felder, z. B. size
, ein Size
-Objekt, das die aktuellen Dimensionen des DrawScope
angibt.
Zum Zeichnen können Sie eine der vielen Zeichenfunktionen in DrawScope
verwenden. Mit dem folgenden Code wird beispielsweise ein Rechteck in der oberen linken Ecke des Bildschirms gezeichnet:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F drawRect( color = Color.Magenta, size = canvasQuadrantSize ) }
Weitere Informationen zu den verschiedenen Zeichenmodifikatoren finden Sie in der Dokumentation zu Grafikmodifikatoren.
Koordinatensystem
Wenn Sie etwas auf dem Bildschirm zeichnen möchten, müssen Sie den Versatz (x
und y
) und die Größe des Elements kennen. Bei vielen der Zeichenmethoden für DrawScope
werden Position und Größe durch Standardparameterwerte angegeben. Mit den Standardparametern wird das Element in der Regel am [0, 0]
-Punkt auf dem Canvas positioniert und ein Standardsize
festgelegt, der den gesamten Zeichenbereich füllt, wie im Beispiel oben. Das Rechteck ist hier links oben zu sehen. Wenn Sie die Größe und Position eines Elements anpassen möchten, müssen Sie das Koordinatensystem in Compose kennen.
Der Ursprung des Koordinatensystems ([0,0]
) befindet sich im linken oberen Pixel des Zeichenbereichs. x
nimmt zu, wenn der Wert nach rechts und y
zunimmt, wenn der Wert nach unten verschoben wird.
Wenn Sie beispielsweise eine Diagonale von der rechten oberen Ecke des Canvas-Bereichs zur linken unteren Ecke zeichnen möchten, können Sie die Funktion DrawScope.drawLine()
verwenden und einen Start- und Endversatz mit den entsprechenden x- und y-Positionen angeben:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasWidth = size.width val canvasHeight = size.height drawLine( start = Offset(x = canvasWidth, y = 0f), end = Offset(x = 0f, y = canvasHeight), color = Color.Blue ) }
Grundlegende Transformationen
DrawScope
bietet Transformationen, mit denen Sie ändern können, wo oder wie die Zeichenbefehle ausgeführt werden.
Reichweite
Mit DrawScope.scale()
können Sie die Größe Ihrer Zeichenvorgänge um einen bestimmten Faktor erhöhen. Vorgänge wie scale()
werden auf alle Zeichenvorgänge innerhalb des entsprechenden Lambdas angewendet. Im folgenden Code wird scaleX
beispielsweise zehnmal und scaleY
fünfzehnmal erhöht:
Canvas(modifier = Modifier.fillMaxSize()) { scale(scaleX = 10f, scaleY = 15f) { drawCircle(Color.Blue, radius = 20.dp.toPx()) } }
Übersetzen
Mit DrawScope.translate()
können Sie die Zeichnungen nach oben, unten, links oder rechts verschieben. Mit dem folgenden Code wird die Zeichnung beispielsweise um 100 Pixel nach rechts und 300 Pixel nach oben verschoben:
Canvas(modifier = Modifier.fillMaxSize()) { translate(left = 100f, top = -300f) { drawCircle(Color.Blue, radius = 200.dp.toPx()) } }
Drehen
Mit DrawScope.rotate()
können Sie Ihre Zeichnungen um einen Drehpunkt drehen. Mit dem folgenden Code wird beispielsweise ein Rechteck um 45 Grad gedreht:
Canvas(modifier = Modifier.fillMaxSize()) { rotate(degrees = 45F) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }
Eingebettet
Mit DrawScope.inset()
können Sie die Standardparameter des aktuellen DrawScope
anpassen, die Zeichnungsgrenzen ändern und die Zeichnungen entsprechend verschieben:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F inset(horizontal = 50f, vertical = 30f) { drawRect(color = Color.Green, size = canvasQuadrantSize) } }
Mit diesem Code wird den Zeichenbefehlen ein Abstand hinzugefügt:
Mehrere Transformationen
Wenn Sie mehrere Transformationen auf Ihre Zeichnungen anwenden möchten, verwenden Sie die Funktion DrawScope.withTransform()
. Damit wird eine einzelne Transformation erstellt und angewendet, die alle gewünschten Änderungen kombiniert. Die Verwendung von withTransform()
ist effizienter als verschachtelte Aufrufe einzelner Transformationen, da alle Transformationen in einem einzigen Vorgang ausgeführt werden, anstatt dass Compose jede der verschachtelten Transformationen berechnen und speichern muss.
Im folgenden Code wird beispielsweise sowohl eine Verschiebung als auch eine Drehung auf das Rechteck angewendet:
Canvas(modifier = Modifier.fillMaxSize()) { withTransform({ translate(left = size.width / 5F) rotate(degrees = 45F) }) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }
Gängige Zeichenvorgänge
Text zeichnen
Wenn Sie in Compose Text zeichnen möchten, können Sie in der Regel das Text
-Element verwenden. Wenn Sie sich jedoch in einer DrawScope
befinden oder den Text manuell mit Anpassungen zeichnen möchten, können Sie die Methode DrawScope.drawText()
verwenden.
Wenn Sie Text zeichnen möchten, erstellen Sie mit rememberTextMeasurer
eine TextMeasurer
und rufen Sie drawText
mit dem Messwert auf:
val textMeasurer = rememberTextMeasurer() Canvas(modifier = Modifier.fillMaxSize()) { drawText(textMeasurer, "Hello") }
Text messen
Das Zeichnen von Text funktioniert etwas anders als andere Zeichenbefehle. Normalerweise geben Sie dem Zeichenbefehl die Größe (Breite und Höhe) an, in der die Form/das Bild gezeichnet werden soll. Bei Text gibt es einige Parameter, die die Größe des gerenderten Texts steuern, z. B. Schriftgröße, Schriftart, Ligaturen und Buchstabenabstand.
In Compose können Sie mithilfe eines TextMeasurer
auf die gemessene Textgröße zugreifen, die von den oben genannten Faktoren abhängt. Wenn Sie hinter dem Text einen Hintergrund zeichnen möchten, können Sie anhand der gemessenen Informationen die Größe des Bereichs ermitteln, den der Text einnimmt:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixedWidth((size.width * 2f / 3f).toInt()), style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
Mit diesem Code-Snippet wird ein rosa Hintergrund für den Text erzeugt:
Wenn Sie die Einschränkungen, die Schriftgröße oder eine andere Eigenschaft anpassen, die sich auf die gemessene Größe auswirkt, wird eine neue Größe erfasst. Sie können sowohl für width
als auch für height
eine feste Größe festlegen. Der Text folgt dann der festgelegten TextOverflow
. Mit dem folgenden Code wird beispielsweise Text in ⅓ der Höhe und ⅓ der Breite des zusammensetzbaren Bereichs gerendert und TextOverflow
auf TextOverflow.Ellipsis
festgelegt:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixed( width = (size.width / 3f).toInt(), height = (size.height / 3f).toInt() ), overflow = TextOverflow.Ellipsis, style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
Der Text wird jetzt innerhalb der Begrenzungen mit Auslassungspunkten am Ende dargestellt:
Bild zeichnen
Wenn Sie mit DrawScope
ein ImageBitmap
zeichnen möchten, laden Sie das Bild mit ImageBitmap.imageResource()
und rufen Sie dann drawImage
auf:
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog) Canvas(modifier = Modifier.fillMaxSize(), onDraw = { drawImage(dogImage) })
Grundformen zeichnen
In DrawScope
gibt es viele Funktionen zum Zeichnen von Formen. Verwenden Sie zum Zeichnen einer Form eine der vordefinierten Zeichenfunktionen, z. B. drawCircle
:
val purpleColor = Color(0xFFBA68C8) Canvas( modifier = Modifier .fillMaxSize() .padding(16.dp), onDraw = { drawCircle(purpleColor) } )
API |
Ausgabe |
Pfad zeichnen
Ein Pfad ist eine Reihe von mathematischen Anweisungen, die nach Ausführung zu einer Zeichnung führen. DrawScope
kann mit der Methode DrawScope.drawPath()
einen Pfad zeichnen.
Angenommen, Sie möchten ein Dreieck zeichnen. Sie können einen Pfad mit Funktionen wie lineTo()
und moveTo()
anhand der Größe des Zeichenbereichs generieren.
Rufen Sie dann drawPath()
mit diesem neu erstellten Pfad auf, um ein Dreieck zu erhalten.
Spacer( modifier = Modifier .drawWithCache { val path = Path() path.moveTo(0f, 0f) path.lineTo(size.width / 2f, size.height / 2f) path.lineTo(size.width, 0f) path.close() onDrawBehind { drawPath(path, Color.Magenta, style = Stroke(width = 10f)) } } .fillMaxSize() )
Zugriff auf Canvas
-Objekt
Mit DrawScope
haben Sie keinen direkten Zugriff auf ein Canvas
-Objekt. Mit DrawScope.drawIntoCanvas()
können Sie auf das Canvas
-Objekt selbst zugreifen, für das Sie Funktionen aufrufen können.
Wenn Sie beispielsweise ein benutzerdefiniertes Drawable
haben, das Sie auf dem Canvas zeichnen möchten, können Sie auf den Canvas zugreifen und Drawable#draw()
aufrufen, wobei Sie das Canvas
-Objekt übergeben:
val drawable = ShapeDrawable(OvalShape()) Spacer( modifier = Modifier .drawWithContent { drawIntoCanvas { canvas -> drawable.setBounds(0, 0, size.width.toInt(), size.height.toInt()) drawable.draw(canvas.nativeCanvas) } } .fillMaxSize() )
Weitere Informationen
Weitere Informationen zum Zeichnen in Compose finden Sie in den folgenden Ressourcen:
- Grafische Modifikatoren: Hier erfahren Sie mehr über die verschiedenen Arten von Zeichenmodifikatoren.
- Pinsel: Hier erfahren Sie, wie Sie das Malen Ihrer Inhalte anpassen.
- Benutzerdefinierte Layouts und Grafiken in Compose – Android Dev Summit 2022: Hier erfahren Sie, wie Sie mit Layouts und Grafiken eine benutzerdefinierte Benutzeroberfläche in Compose erstellen.
- JetLagged Sample: Beispiel für die Erstellung eines benutzerdefinierten Diagramms.
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Grafiken-Modifikatoren
- Grafiken in Compose
- Ausrichtungslinien in Jetpack Compose