Viele Apps müssen in der Lage sein, genau zu steuern, was auf dem Bildschirm gezeichnet wird. Dies kann so klein sein wie die Platzierung eines Kästchens oder eines Kreises auf dem Bildschirm an der richtigen Stelle oder eine komplexe Anordnung von Grafikelementen in vielen verschiedenen Stilen.
Einfache Zeichnung mit Modifikatoren und DrawScope
Benutzerdefinierten Text lassen sich in „Compose“ hauptsächlich mit Modifizierern zeichnen, z. B. Modifier.drawWithContent
, Modifier.drawBehind
und Modifier.drawWithCache
.
Wenn Sie beispielsweise etwas aus der zusammensetzbaren Funktion zeichnen möchten, können Sie den drawBehind
-Modifikator verwenden, um mit der Ausführung von Zeichenbefehlen zu beginnen:
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
Wenn Sie nur eine zusammensetzbare Funktion benötigen, die etwas zeichnet, können Sie die zusammensetzbare Funktion Canvas
verwenden. Die zusammensetzbare Funktion Canvas
ist ein praktischer Wrapper um Modifier.drawBehind
. Platzieren Sie das Canvas
-Objekt in Ihrem Layout genauso wie andere Compose-UI-Elemente. In Canvas
können Sie Elemente zeichnen und dabei ihren Stil und ihre Position genau steuern.
Alle Zeichenmodifikatoren stellen ein DrawScope
bereit. Dies ist eine auf einen Bereich reduzierte Zeichenumgebung, die einen eigenen Status behält. So können Sie die Parameter für eine Gruppe grafischer Elemente festlegen. Das DrawScope
bietet mehrere nützliche Felder, z. B. size
, ein Size
-Objekt, das die aktuellen Dimensionen von DrawScope
festlegt.
Um etwas zu 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 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 die Position und Größe durch Standardparameterwerte bereitgestellt. Die Standardparameter positionieren das Element im Allgemeinen am Punkt [0, 0]
des Canvas und stellen einen Standard-size
bereit, der den gesamten Zeichenbereich ausfüllt (siehe Beispiel oben). Das Rechteck befindet sich oben links. Um die Größe und Position eines Elements anzupassen, müssen Sie das Koordinatensystem in Compose verstehen.
Der Ursprung des Koordinatensystems ([0,0]
) befindet sich im Zeichenbereich am oberen linken Rand des Pixels. x
erhöht sich, wenn er nach rechts bewegt wird, und y
steigt, wenn er nach unten bewegt wird.
Wenn Sie beispielsweise eine diagonale Linie von der oberen rechten Ecke des Canvas-Bereichs bis 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.
Skalieren
Mit DrawScope.scale()
können Sie die Größe Ihrer Zeichenvorgänge um einen Faktor erhöhen. Vorgänge wie scale()
gelten für alle Zeichenvorgänge innerhalb der entsprechenden Lambda-Funktion. Mit dem folgenden Code werden scaleX
beispielsweise um das 10-Fache und scaleY
um das 15-Fache 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 Ihre Zeichenvorgänge nach oben, unten, links oder rechts verschieben. Durch den 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 Zeichenvorgänge 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 ) } }
Einsatz
Mit DrawScope.inset()
können Sie die Standardparameter des aktuellen DrawScope
anpassen, indem Sie die Begrenzungen der Zeichnung ändern und die Zeichnungen entsprechend übersetzen:
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 effektiv ein Padding hinzugefügt:
Mehrere Transformationen
Wenn Sie mehrere Transformationen auf Ihre Zeichnungen anwenden möchten, verwenden Sie die Funktion DrawScope.withTransform()
. Diese erstellt und wendet eine einzelne Transformation an, die alle gewünschten Änderungen kombiniert. Die Verwendung von withTransform()
ist effizienter als verschachtelte Aufrufe einzelner Transformationen, da alle Transformationen gemeinsam in einem einzigen Vorgang ausgeführt werden, anstatt dass Compose jede der verschachtelten Transformationen berechnen und speichern muss.
Mit dem folgenden Code werden beispielsweise sowohl eine Übersetzung 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
Um Text in „Schreiben“ zu zeichnen, können Sie normalerweise die zusammensetzbare Funktion Text
verwenden. Wenn Sie sich jedoch in einem DrawScope
befinden oder den Text manuell und mit Anpassungen zeichnen möchten, können Sie die Methode DrawScope.drawText()
verwenden.
Um Text zu zeichnen, erstellen Sie mit rememberTextMeasurer
ein TextMeasurer
und rufen Sie drawText
mit dem Measurer auf:
val textMeasurer = rememberTextMeasurer() Canvas(modifier = Modifier.fillMaxSize()) { drawText(textMeasurer, "Hello") }
Text messen
Das Zeichnen von Text unterscheidet sich etwas von anderen Zeichenbefehlen. Normalerweise geben Sie dem Zeichenbefehl die Größe (Breite und Höhe) zum Zeichnen der Form/des Bilds an. Bei Text gibt es einige Parameter, die die Größe des gerenderten Textes steuern, z. B. Schriftgröße, Schriftart, Ligaturen und Buchstabenabstand.
Mit der Funktion „Schreiben“ können Sie einen TextMeasurer
verwenden, um abhängig von den oben genannten Faktoren Zugriff auf die gemessene Textgröße zu erhalten. Wenn Sie einen Hintergrund hinter dem Text 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() )
Bei diesem Code-Snippet wird der Text mit einem rosa Hintergrund versehen:
Wenn Sie die Einschränkungen, die Schriftgröße oder andere Eigenschaften anpassen, die sich auf die gemessene Größe auswirken, wird eine neue Größe im Bericht angezeigt. Sie können sowohl für width
als auch für height
eine feste Größe festlegen. Der Text folgt dann dem festgelegten TextOverflow
. Mit dem folgenden Code wird beispielsweise Text in 1⁄3 der Höhe und 1⁄3 der Breite des zusammensetzbaren Bereichs gerendert und TextOverflow
auf TextOverflow.Ellipsis
gesetzt:
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 in den Einschränkungen mit Auslassungspunkten am Ende gezeichnet:
Bild zeichnen
Um ein ImageBitmap
mit DrawScope
zu zeichnen, 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 wie drawCircle
:
val purpleColor = Color(0xFFBA68C8) Canvas( modifier = Modifier .fillMaxSize() .padding(16.dp), onDraw = { drawCircle(purpleColor) } )
API |
Ausgang |
Pfad zeichnen
Ein Pfad ist eine Reihe mathematischer Anweisungen, die nach der 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() )
Auf Canvas
-Objekt zugreifen
Mit DrawScope
haben Sie keinen direkten Zugriff auf ein Canvas
-Objekt. Mit DrawScope.drawIntoCanvas()
erhalten Sie Zugriff auf das Canvas
-Objekt selbst, für das Sie Funktionen aufrufen können.
Wenn Sie beispielsweise ein benutzerdefiniertes Drawable
auf den Canvas zeichnen möchten, können Sie auf den Canvas zugreifen, Drawable#draw()
aufrufen und das Objekt Canvas
ü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:
- Grafikmodifikatoren – Informationen zu den verschiedenen Arten von Zeichenmodifikatoren
- Pinsel: Hier erfährst du, wie du die Darstellung deiner Inhalte anpassen kannst.
- Benutzerdefinierte Layouts und Grafiken in Compose – Android Dev Summit 2022: Hier erfährst du, wie du eine benutzerdefinierte UI in „Compose with Layouts and Graphics“ erstellst.
- JetLagged-Beispiel – Beispiel verfassen, das zeigt, wie ein benutzerdefiniertes Diagramm gezeichnet wird.
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Grafikmodifikatoren
- Grafiken in „Compose“
- Ausrichtungslinien in Jetpack Compose