Grafikmodifikatoren

Zusätzlich zu den zusammensetzbaren Funktionen für Canvas bietet „Compose“ einige nützliche Grafiken Modifiers, die beim Zeichnen benutzerdefinierter Inhalte helfen. Diese Modifikatoren sind nützlich, da sie auf jede zusammensetzbare Funktion angewendet werden können.

Zeichenmodifikatoren

Alle Zeichenbefehle werden in Compose mit einem Zeichenmodifikator ausgeführt. Es gibt drei Hauptmodifikatoren für Zeichnungen in Compose:

Der Basismodifikator für das Zeichnen ist drawWithContent. Hier können Sie festlegen, der zusammensetzbaren Zeichen und der Zeichenbefehle, die im Modifikator. drawBehind ist ein praktischer Wrapper um drawWithContent, die Zeichenreihenfolge hinter dem Inhalt der zusammensetzbaren Funktion. drawWithCache ruft entweder onDrawBehind oder onDrawWithContent darin auf und stellt eine zum Zwischenspeichern der darin erstellten Objekte.

Modifier.drawWithContent: Zeichnungsreihenfolge auswählen

Mit Modifier.drawWithContent können Sie DrawScope-Vorgänge vor oder nach dem Inhalt der zusammensetzbar. Rufen Sie unbedingt drawContent auf, damit der eigentliche Inhalt der zusammensetzbaren Funktion. Mit diesem Modifikator können Sie die Reihenfolge der Vorgänge festlegen, wenn Ihre Inhalte vor oder nach Ihren benutzerdefinierten Zeichenvorgängen gezeichnet werden sollen.

Wenn Sie beispielsweise einen radialen Farbverlauf über Ihren Inhalten einen Keyhole-Effekt für die Taschenlampe in der Benutzeroberfläche erzeugen möchten, können Sie so vorgehen:

var pointerOffset by remember {
    mutableStateOf(Offset(0f, 0f))
}
Column(
    modifier = Modifier
        .fillMaxSize()
        .pointerInput("dragging") {
            detectDragGestures { change, dragAmount ->
                pointerOffset += dragAmount
            }
        }
        .onSizeChanged {
            pointerOffset = Offset(it.width / 2f, it.height / 2f)
        }
        .drawWithContent {
            drawContent()
            // draws a fully black area with a small keyhole at pointerOffset that’ll show part of the UI.
            drawRect(
                Brush.radialGradient(
                    listOf(Color.Transparent, Color.Black),
                    center = pointerOffset,
                    radius = 100.dp.toPx(),
                )
            )
        }
) {
    // Your composables here
}

Abbildung 1: Modifier.drawWithContent wird auf einem Composable verwendet, um eine Benutzeroberfläche vom Typ "Taschenlampe" zu erstellen.

Modifier.drawBehind: Hinter einem Composeable zeichnen

Mit Modifier.drawBehind können Sie DrawScope-Vorgänge hinter den zusammensetzbaren Inhalten, die auf dem Bildschirm gezeichnet werden. Wenn Wenn Sie sich die Implementierung von Canvas ansehen, stellen Sie möglicherweise fest, ist nur ein praktischer Wrapper um Modifier.drawBehind.

So zeichnen Sie ein abgerundetes Rechteck hinter Text:

Text(
    "Hello Compose!",
    modifier = Modifier
        .drawBehind {
            drawRoundRect(
                Color(0xFFBBAAEE),
                cornerRadius = CornerRadius(10.dp.toPx())
            )
        }
        .padding(4.dp)
)

Das führt zu folgendem Ergebnis:

Text und ein mit Modifier.drawBehind gezeichneter Hintergrund
Abbildung 2: Mit Modifier.drawBehind gezeichneter Text und ein Hintergrund

Modifier.drawWithCache: Zeichenobjekte zeichnen und im Cache speichern

Modifier.drawWithCache behält die Objekte bei die im Cache erstellt wurden. Die Objekte werden im Cache gespeichert, oder Statusobjekte, die gelesen werden, geändert. Dieser Modifikator ist nützlich, um die Leistung von Zeichenaufrufen zu verbessern, Dadurch müssen Objekte nicht neu zugewiesen werden (z. B. Brush, Shader, Path). die durch Zeichnen erstellt wurden.

Alternativ können Sie Objekte auch mithilfe von remember außerhalb des Modifikator. Dies ist jedoch nicht immer möglich, da Sie nicht immer Zugriff haben auf die Komposition. drawWithCache kann leistungsfähiger sein, wenn die -Objekte werden nur zum Zeichnen verwendet.

Wenn Sie beispielsweise ein Brush erstellen, um einen Farbverlauf hinter einem Text zu zeichnen, verwenden Sie drawWithCache speichert das Brush-Objekt im Cache, bis die Größe des Zeichenbereichs erreicht ist Änderungen:

Text(
    "Hello Compose!",
    modifier = Modifier
        .drawWithCache {
            val brush = Brush.linearGradient(
                listOf(
                    Color(0xFF9E82F0),
                    Color(0xFF42A5F5)
                )
            )
            onDrawBehind {
                drawRoundRect(
                    brush,
                    cornerRadius = CornerRadius(10.dp.toPx())
                )
            }
        }
)

Brush-Objekt mitdrawWithCache im Cache speichern
Abbildung 3: Brush-Objekt mitdrawWithCache im Cache speichern

Grafikmodifikatoren

Modifier.graphicsLayer: Transformationen auf zusammensetzbare Funktionen anwenden

Modifier.graphicsLayer ist ein Modifikator, mit dem der Inhalt des Composeables in eine Zeichenebene gezeichnet wird. Eine Schicht bietet verschiedene Funktionen, z. B.:

  • Isolation für die zugehörigen Zeichenanweisungen (ähnlich RenderNode). Zeichnen als Teil einer Ebene erfasste Anweisungen können effizient vom Rendering-Pipeline aus, ohne den Anwendungscode noch einmal auszuführen.
  • Transformationen, die für alle Zeichenanweisungen in einem Ebene.
  • Rasterung für Kompositionsfunktionen. Wenn eine Ebene gerastert wird, Die Zeichenanweisungen werden ausgeführt und die Ausgabe wird außerhalb des Bildschirms festgehalten. Puffer. Das Compositing eines solchen Buffers für nachfolgende Frames ist schneller als die Ausführung der einzelnen Anweisungen. Er verhält sich jedoch wie eine Bitmap, wenn Transformationen wie Skalierung oder Drehung angewendet werden.

Transformation

Modifier.graphicsLayer isoliert die Zeichenanweisungen. für können verschiedene Transformationen mit Modifier.graphicsLayer angewendet werden. Diese können animiert oder geändert werden, ohne dass die Zeichnung erneut ausgeführt werden muss. Lambda.

Modifier.graphicsLayer hat keinen Einfluss auf die gemessene Größe oder Position des Geräts zusammensetzbar, da es sich nur auf die Zeichenphase auswirkt. Das bedeutet, dass Ihre zusammensetzbare Funktion können andere überlappen, wenn sie außerhalb der Layoutgrenzen gezeichnet wird.

Die folgenden Transformationen können mit diesem Modifikator angewendet werden:

Skalieren – Größe erhöhen

Mit scaleX und scaleY wird der Inhalt horizontal oder vertikal vergrößert oder verkleinert. Richtung. Der Wert 1.0f gibt an, dass die Skalierung nicht geändert wurde, 0.5f steht für die Hälfte der Dimension.

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "Sunset",
    modifier = Modifier
        .graphicsLayer {
            this.scaleX = 1.2f
            this.scaleY = 0.8f
        }
)

Abbildung 4: scaleX und scaleY auf eine zusammensetzbare Funktion des Bildes angewendet
Übersetzung

translationX und translationY können mit graphicsLayer geändert werden, translationX verschiebt die zusammensetzbare Funktion nach links oder rechts. translationY verschiebt den die zusammensetzbar sind.

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "Sunset",
    modifier = Modifier
        .graphicsLayer {
            this.translationX = 100.dp.toPx()
            this.translationY = 10.dp.toPx()
        }
)

Abbildung 5: TranslationX und TranslationY mit Modifier.graphicsLayer auf das Bild angewendet
Ausrichtung

Stellen Sie rotationX für eine horizontale Drehung, rotationY für eine vertikale Drehung und Mit rotationZ können Sie sie um die Z-Achse drehen (Standardrotation). Dieser Wert ist angegeben in Grad (0–360) angegeben.

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "Sunset",
    modifier = Modifier
        .graphicsLayer {
            this.rotationX = 90f
            this.rotationY = 275f
            this.rotationZ = 180f
        }
)

Abbildung 6: „rotationX“, „rotationY“ und „rotationZ“ werden für das Bild von „Modifier.graphicsLayer“ festgelegt
Origin

Ein transformOrigin kann angegeben werden. Er wird dann als der Punkt verwendet, von dem aus finden Transformationen statt. Bei allen bisherigen Beispielen wurde TransformOrigin.Center, Ort: (0.5f, 0.5f). Wenn Sie den Ursprung in (0f, 0f) beginnen, beginnen die Transformationen dann links oben im zusammensetzbar.

Wenn Sie den Ursprung mit einer rotationZ-Transformation ändern, sehen Sie, dass sich das Element oben links im Composeable dreht:

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "Sunset",
    modifier = Modifier
        .graphicsLayer {
            this.transformOrigin = TransformOrigin(0f, 0f)
            this.rotationX = 90f
            this.rotationY = 275f
            this.rotationZ = 180f
        }
)

Abbildung 7: Rotation angewendet, wobei TransformOrigin auf 0f, 0f gesetzt ist

Zuschneiden und Formen

Die Form gibt den Umriss an, an dem der Inhalt abgeschnitten wird, wenn clip = true. In In diesem Beispiel haben wir zwei Felder mit zwei verschiedenen Clips eingerichtet: graphicsLayer-Variable des Typs „Clip“ und die andere mit dem praktischen Wrapper Modifier.clip.

Column(modifier = Modifier.padding(16.dp)) {
    Box(
        modifier = Modifier
            .size(200.dp)
            .graphicsLayer {
                clip = true
                shape = CircleShape
            }
            .background(Color(0xFFF06292))
    ) {
        Text(
            "Hello Compose",
            style = TextStyle(color = Color.Black, fontSize = 46.sp),
            modifier = Modifier.align(Alignment.Center)
        )
    }
    Box(
        modifier = Modifier
            .size(200.dp)
            .clip(CircleShape)
            .background(Color(0xFF4DB6AC))
    )
}

Der Inhalt des ersten Feldes (der Text „Hallo Nachricht“) wird auf die Kreisform:

Clip wurde auf zusammensetzbare Box in Box angewendet
Abbildung 8: Clip auf zusammensetzbare Box angewendet

Wenn Sie dann ein translationY auf den oberen rosa Kreis anwenden, sehen Sie, dass die Grenzen der zusammensetzbaren Elemente sind immer noch dieselben, aber der Kreis wird unterhalb der Unterseite angezeigt. Kreis (und außerhalb der Grenzen) liegt.

Der Clip wurde mit der Übersetzung Y und dem roten Rahmen als Umriss angewendet.
Abbildung 9: Clip mit Umsetzung Y und roter Rahmen für den Umriss

Um die zusammensetzbare Funktion auf den dargestellten Bereich zu beschneiden, können Sie eine weitere Modifier.clip(RectangleShape) am Anfang der Modifikatorkette. Inhalt bleibt innerhalb der ursprünglichen Grenzen.

Column(modifier = Modifier.padding(16.dp)) {
    Box(
        modifier = Modifier
            .clip(RectangleShape)
            .size(200.dp)
            .border(2.dp, Color.Black)
            .graphicsLayer {
                clip = true
                shape = CircleShape
                translationY = 50.dp.toPx()
            }
            .background(Color(0xFFF06292))
    ) {
        Text(
            "Hello Compose",
            style = TextStyle(color = Color.Black, fontSize = 46.sp),
            modifier = Modifier.align(Alignment.Center)
        )
    }

    Box(
        modifier = Modifier
            .size(200.dp)
            .clip(RoundedCornerShape(500.dp))
            .background(Color(0xFF4DB6AC))
    )
}

Clip, der auf die Grafikebenentransformation angewendet wird
Abbildung 10: Clip wird auf „graphicLayer“-Transformation angewendet

Alpha

Mit Modifier.graphicsLayer können Sie eine alpha (Deckkraft) für die gesamte Ebene festlegen. 1.0f ist vollständig deckend und 0.0f nicht sichtbar.

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "clock",
    modifier = Modifier
        .graphicsLayer {
            this.alpha = 0.5f
        }
)

Bild mit angewendetem Alphatest
Abbildung 11: Bild mit angewendetem Alpha-Test

Compositing-Strategie

Die Arbeit mit Alpha und Transparenz ist möglicherweise nicht so einfach wie das Ändern eines Alphawert. Neben dem Ändern eines Alpha-Werts gibt es auch die Option, eine CompositingStrategy auf graphicsLayer. Ein CompositingStrategy bestimmt, wie die Inhalt der zusammensetzbaren Funktion mit den anderen die bereits auf dem Bildschirm zu sehen sind.

Die verschiedenen Strategien sind:

Automatisch (Standard)

Die Compositing-Strategie wird durch den Rest der graphicsLayer bestimmt. Parameter. Er rendert die Ebene in einen Offscreen-Zwischenspeicher, wenn Alpha kleiner als ist. 1.0f oder ein RenderEffect ist festgelegt. Immer wenn der Alphawert kleiner als 1f ist, wird ein Compositing-Ebene wird automatisch erstellt, um den Inhalt zu rendern, und mit dem entsprechenden Alpha-Track an das Ziel übergeben. Festlegen eines Durch RenderEffect oder Overscroll werden Inhalte immer außerhalb des Bildschirms gerendert Puffer unabhängig vom festgelegten CompositingStrategy fest.

Nicht im Bild

Der Inhalt der zusammensetzbaren Funktion wird immer außerhalb des Bildschirms gerastert. Textur oder Bitmap vor dem Rendern im Ziel. Dies ist nützlich für Anwenden von BlendMode-Vorgängen zum Maskieren von Inhalten und für die Leistung, wenn komplexe Reihen von Zeichenanweisungen gerendert.

Ein Beispiel für die Verwendung von CompositingStrategy.Offscreen ist BlendModes. Sehen wir uns das Beispiel unten an. Sie möchten Teile einer zusammensetzbaren Image-Funktion entfernen, indem Sie einen Draw-Befehl ausführen, verwendet BlendMode.Clear. Wenn Sie compositingStrategy nicht auf CompositingStrategy.Offscreen, interagiert der BlendMode mit allen Inhalten darunter.

Image(painter = painterResource(id = R.drawable.dog),
   contentDescription = "Dog",
   contentScale = ContentScale.Crop,
   modifier = Modifier
       .size(120.dp)
       .aspectRatio(1f)
       .background(
           Brush.linearGradient(
               listOf(
                   Color(0xFFC5E1A5),
                   Color(0xFF80DEEA)
               )
           )
       )
       .padding(8.dp)
       .graphicsLayer {
           compositingStrategy = CompositingStrategy.Offscreen
       }
       .drawWithCache {
           val path = Path()
           path.addOval(
               Rect(
                   topLeft = Offset.Zero,
                   bottomRight = Offset(size.width, size.height)
               )
           )
           onDrawWithContent {
               clipPath(path) {
                   // this draws the actual image - if you don't call drawContent, it wont
                   // render anything
                   this@onDrawWithContent.drawContent()
               }
               val dotSize = size.width / 8f
               // Clip a white border for the content
               drawCircle(
                   Color.Black,
                   radius = dotSize,
                   center = Offset(
                       x = size.width - dotSize,
                       y = size.height - dotSize
                   ),
                   blendMode = BlendMode.Clear
               )
               // draw the red circle indication
               drawCircle(
                   Color(0xFFEF5350), radius = dotSize * 0.8f,
                   center = Offset(
                       x = size.width - dotSize,
                       y = size.height - dotSize
                   )
               )
           }

       }
)

Wenn du „CompositingStrategy“ auf Offscreen setzt, wird ein Out-of-Screen erstellt, Textur, auf die die Befehle ausgeführt werden sollen. Dabei wird BlendMode nur auf die Inhalt dieser zusammensetzbaren Funktion). Dann wird sie auf Basis des bereits vorhandenen ohne Auswirkungen auf den bereits gezeichneten Inhalt zu haben.

Modifier.drawWithContent auf einem Bild mit einer Kreisangabe, mit BlendMode.Clear in der App
Abbildung 12: Modifier.drawWithContent auf einem Bild mit einem Kreis, mit BlendMode.Clear und CompositingStrategy.Offscreen in der App

Wenn Sie CompositingStrategy.Offscreen nicht verwendet haben, BlendMode.Clear löscht alle Pixel im Ziel, unabhängig davon, wurde bereits festgelegt, sodass der Rendering-Zwischenspeicher (schwarz) des Fensters sichtbar blieb. Viele von BlendModes, die Alpha beinhalten, funktionieren ohne eine aus. Beachten Sie den schwarzen Ring um den roten Kreis:

Modifier.drawWithContent auf einem Bild mit einem Kreissymbol, mit dem Modus BlendMode.Clear und ohne CompositingStrategy
Abbildung 13: Modifier.drawWithContent auf einem Bild mit einem Kreis, BlendMode.Clear und keine CompositingStrategy festgelegt

Zum besseren Verständnis: Hat die App ein durchscheinendes Fenster? Hintergrund und Sie haben CompositingStrategy.Offscreen nicht verwendet, die BlendMode würde mit der gesamten App interagieren. Es werden alle Pixel gelöscht, darunter die App oder den Hintergrund, wie in diesem Beispiel:

Keine CompositingStrategy festgelegt und BlendMode.Clear wird mit einer App mit einem durchscheinenden Fensterhintergrund verwendet. Der rosafarbene Hintergrund ist im Bereich um den roten Statuskreis zu sehen.
Abbildung 14: Keine CompositingStrategy festgelegt und Verwendung von BlendMode.Clear bei einer App mit durchscheinendem Fensterhintergrund. Beachten Sie, wie der rosa Hintergrund um den roten Statuskreis herum angezeigt wird.

Beachten Sie, dass bei der Verwendung von CompositingStrategy.Offscreen ein nicht auf dem Bildschirm Textur, die die Größe des Zeichenbereichs hat, wird erstellt und auf dem Bildschirm. Alle Zeichenbefehle, die mit dieser Strategie ausgeführt werden, sind standardmäßig auf diesen Bereich zugeschnitten. Das folgende Code-Snippet veranschaulicht die Unterschiede beim zur Verwendung von Texturen außerhalb des sichtbaren Bereichs:

@Composable
fun CompositingStrategyExamples() {
   Column(
       modifier = Modifier
           .fillMaxSize()
           .wrapContentSize(Alignment.Center)
   ) {
       /** Does not clip content even with a graphics layer usage here. By default, graphicsLayer
       does not allocate + rasterize content into a separate layer but instead is used
       for isolation. That is draw invalidations made outside of this graphicsLayer will not
       re-record the drawing instructions in this composable as they have not changed **/
       Canvas(
           modifier = Modifier
               .graphicsLayer()
               .size(100.dp) // Note size of 100 dp here
               .border(2.dp, color = Color.Blue)
       ) {
           // ... and drawing a size of 200 dp here outside the bounds
           drawRect(color = Color.Magenta, size = Size(200.dp.toPx(), 200.dp.toPx()))
       }

       Spacer(modifier = Modifier.size(300.dp))

       /** Clips content as alpha usage here creates an offscreen buffer to rasterize content
       into first then draws to the original destination **/
       Canvas(
           modifier = Modifier
               // force to an offscreen buffer
               .graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
               .size(100.dp) // Note size of 100 dp here
               .border(2.dp, color = Color.Blue)
       ) {
           /** ... and drawing a size of 200 dp. However, because of the CompositingStrategy.Offscreen usage above, the
           content gets clipped **/
           drawRect(color = Color.Red, size = Size(200.dp.toPx(), 200.dp.toPx()))
       }
   }
}

CompositingStrategy.Auto vs CompositingStrategy.Offscreen - Aus dem Bildschirm wird die Region abgeschnitten, in der dies nicht der Fall ist.
Abbildung 15: CompositingStrategy.Auto vs. CompositingStrategy.Offscreen – Offscreen-Video wird an die Region angepasst, in der dies nicht der Fall ist.
ModulateAlpha

Diese Kompositionsstrategie moduliert den Alpha-Track für jede der Anweisungen, die in graphicsLayer aufgezeichnet wurden. Es wird kein Offscreen-Puffer für Alphawerte unter 1.0f erstellt, es sei denn, RenderEffect ist festgelegt. Das kann für das Alpha-Rendering effizienter sein. Sie kann jedoch zu anderen Ergebnissen führen, für sich überschneidende Inhalte. Für Anwendungsfälle, bei denen im Voraus bekannt ist, nicht überlappen, kann dies eine bessere Leistung erzielen als CompositingStrategy.Auto mit Alphawerten unter 1.

Ein weiteres Beispiel für verschiedene Kompositionsstrategien finden Sie unten. Alphas auf verschiedene Teile der zusammensetzbaren Funktionen anwenden und eine Modulate Strategie:

@Preview
@Composable
fun CompositingStratgey_ModulateAlpha() {
  Column(
      modifier = Modifier
          .fillMaxSize()
          .padding(32.dp)
  ) {
      // Base drawing, no alpha applied
      Canvas(
          modifier = Modifier.size(200.dp)
      ) {
          drawSquares()
      }

      Spacer(modifier = Modifier.size(36.dp))

      // Alpha 0.5f applied to whole composable
      Canvas(modifier = Modifier
          .size(200.dp)
          .graphicsLayer {
              alpha = 0.5f
          }) {
          drawSquares()
      }
      Spacer(modifier = Modifier.size(36.dp))

      // 0.75f alpha applied to each draw call when using ModulateAlpha
      Canvas(modifier = Modifier
          .size(200.dp)
          .graphicsLayer {
              compositingStrategy = CompositingStrategy.ModulateAlpha
              alpha = 0.75f
          }) {
          drawSquares()
      }
  }
}

private fun DrawScope.drawSquares() {

  val size = Size(100.dp.toPx(), 100.dp.toPx())
  drawRect(color = Red, size = size)
  drawRect(
      color = Purple, size = size,
      topLeft = Offset(size.width / 4f, size.height / 4f)
  )
  drawRect(
      color = Yellow, size = size,
      topLeft = Offset(size.width / 4f * 2f, size.height / 4f * 2f)
  )
}

val Purple = Color(0xFF7E57C2)
val Yellow = Color(0xFFFFCA28)
val Red = Color(0xFFEF5350)

ModulateAlpha wendet den Alpha-Satz auf jeden einzelnen Zeichenbefehl an
Abbildung 16: ModulateAlpha wendet das Alpha-Dataset auf jeden einzelnen Zeichenbefehl an.

Inhalte einer zusammensetzbaren Funktion in eine Bitmap schreiben

Ein häufiger Anwendungsfall ist das Erstellen einer Bitmap aus einer zusammensetzbaren Funktion. Zum Kopieren der zu Bitmap erstellen Sie ein GraphicsLayer mit rememberGraphicsLayer()

Leiten Sie die Zeichenbefehle mit drawWithContent() an die neue Ebene um und graphicsLayer.record{}. Zeichnen Sie dann die Ebene mit drawLayer:

val coroutineScope = rememberCoroutineScope()
val graphicsLayer = rememberGraphicsLayer()
Box(
    modifier = Modifier
        .drawWithContent {
            // call record to capture the content in the graphics layer
            graphicsLayer.record {
                // draw the contents of the composable into the graphics layer
                this@drawWithContent.drawContent()
            }
            // draw the graphics layer on the visible canvas
            drawLayer(graphicsLayer)
        }
        .clickable {
            coroutineScope.launch {
                val bitmap = graphicsLayer.toImageBitmap()
                // do something with the newly acquired bitmap
            }
        }
        .background(Color.White)
) {
    Text("Hello Android", fontSize = 26.sp)
}

Du kannst die Bitmap auf der Festplatte speichern und teilen. Weitere Informationen finden Sie in der vollständigen Beispiel-Snippet. Prüfe die Geräteberechtigungen, bevor du es versuchst zum Speichern auf der Festplatte.

Modifikator für benutzerdefinierte Zeichnungen

Implementieren Sie die DrawModifier-Schnittstelle, um einen eigenen benutzerdefinierten Modifizierer zu erstellen. So erhalten Sie Zugriff auf einen ContentDrawScope, der mit dem identisch ist, der bei Verwendung von Modifier.drawWithContent() freigegeben wird. Sie können dann häufig verwendete Zeichenvorgänge in benutzerdefinierte Zeichenmodifikatoren extrahieren, um den Code zu bereinigen und praktische Wrapper bereitzustellen. Modifier.background() ist beispielsweise eine praktische DrawModifier.

Wenn Sie z. B. eine Modifier implementieren möchten, die den können Sie wie folgt einen erstellen:

class FlippedModifier : DrawModifier {
    override fun ContentDrawScope.draw() {
        scale(1f, -1f) {
            this@draw.drawContent()
        }
    }
}

fun Modifier.flipped() = this.then(FlippedModifier())

Verwenden Sie dann diesen umgedrehten Modifikator auf Text:

Text(
    "Hello Compose!",
    modifier = Modifier
        .flipped()
)

Benutzerdefinierter umgedrehter Modifizierer für Text
Abbildung 17: Benutzerdefinierter umgedrehter Modifizierer für Text

Weitere Informationen

Weitere Beispiele für die Verwendung von graphicsLayer und benutzerdefinierten Zeichnungen finden Sie in den folgenden Ressourcen: