Grafik değiştiriciler

Canvas composable'ın yanı sıra Compose'da da özel içerik çizmeye yardımcı olan birkaç faydalı grafik Modifiers bulunur. Bu değiştiriciler tüm composable'lara uygulanabileceğinden yararlıdır.

Çizim değiştiricileri

Tüm çizim komutları, Oluştur'da bir çizim değiştiriciyle yapılır. Oluşturma'da üç ana çizim değiştiricisi vardır:

Çizim için temel değiştirici olan drawWithContent. Burada, Composable'ın çizim sırasını ve düzenleyicide verilen çizim komutlarını belirleyebilirsiniz. drawBehind, çizim sırası composable'ın içeriğinin arkasına ayarlanmış drawWithContent için uygun bir sarmalayıcıdır. drawWithCache, içindeki onDrawBehind veya onDrawWithContent değerlerini çağırır ve bunlarda oluşturulan nesneleri önbelleğe alma mekanizması sağlar.

Modifier.drawWithContent: Çizim sırasını seç

Modifier.drawWithContent, composable'ın içeriğinden önce veya sonra DrawScope işlemlerini yürütmenizi sağlar. Daha sonra composable'ın gerçek içeriğini oluşturmak için drawContent yöntemini çağırdığınızdan emin olun. İçeriğinizin özel çizim işlemlerinizden önce veya sonra çizilmesini istiyorsanız bu değiştiriciyi kullanarak işlemlerin sırasına karar verebilirsiniz.

Örneğin, kullanıcı arayüzünde bir el feneri anahtar deliği efekti oluşturmak için içeriğinizin üzerinde dairesel gradyan oluşturmak isterseniz aşağıdakileri yapabilirsiniz:

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
}

Şekil 1: El feneri türünde bir kullanıcı arayüzü deneyimi oluşturmak için Composable'ın üzerinde Modifier.drawWithContent kullanılır.

Modifier.drawBehind: Bir composable'ın arkasında çizim yapma

Modifier.drawBehind, ekranda çizilen composable içeriğin arkasında DrawScope işlemi gerçekleştirmenizi sağlar. Canvas uygulamasına göz atarsanız bunun Modifier.drawBehind için kullanılan uygun bir sarmalayıcı olduğunu fark edebilirsiniz.

Text öğesinin arkasında yuvarlak bir dikdörtgen çizmek için:

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

Bu da aşağıdaki sonucu verir:

Modifier.drawBehind kullanılarak çizilen metin ve arka plan
Şekil 2: Modifier.drawBehind kullanılarak çizilen metin ve arka plan

Modifier.drawWithCache: Çizim nesnelerini çizme ve önbelleğe alma

Modifier.drawWithCache, içinde oluşturulan nesneleri önbelleğe alır. Çizim alanının boyutu aynı olduğu veya okunan durum nesneleri değişmediği sürece nesneler önbelleğe alınır. Bu değiştirici, çizim sırasında oluşturulan nesnelerin (Brush, Shader, Path vb.) yeniden tahsis edilmesi ihtiyacını ortadan kaldırdığından çizim çağrılarının performansını iyileştirmek için yararlıdır.

Alternatif olarak, nesneleri değiştiricinin dışında remember kullanarak da önbelleğe alabilirsiniz. Ancak besteye her zaman erişiminiz olmadığından bu her zaman mümkün değildir. Nesneler yalnızca çizim için kullanılıyorsa drawWithCache kullanmak daha etkili olabilir.

Örneğin, Text arkasında bir gradyan çizmek için bir Brush kullanırsanız drawWithCache kullandığınızda, çizim alanının boyutu değişinceye kadar Brush nesnesi önbelleğe alınır:

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

drawWithCache ile Fırça nesnesini önbelleğe alma
Şekil 3: drawWithCache ile Fırça nesnesini önbelleğe alma

Grafik değiştiriciler

Modifier.graphicsLayer: composable'lara dönüşüm uygulama

Modifier.graphicsLayer, composable çizim içeriğinin içeriğini çizim katmanına dönüştüren bir düzenleyicidir. Katman birkaç farklı işlev sağlar. Örneğin:

  • Çizim talimatları için izolasyon (RenderNode'e benzer). Bir katmanın parçası olarak yakalanan çizim talimatları, uygulama kodu yeniden çalıştırılmadan oluşturma ardışık düzeni tarafından verimli bir şekilde yeniden yayınlanabilir.
  • Bir katmanda yer alan çizim talimatlarının tamamına uygulanan dönüşümlerdir.
  • Kompozisyon özellikleri için pikselleştirme. Bir katman pikselleştirildiğinde, çizim talimatları yürütülür ve çıkış ekran dışı bir arabelleğe alınır. Sonraki kareler için bu tür bir arabelleğin birleştirilmesi, tek tek talimatların yürütülmesinden daha hızlıdır ancak ölçeklendirme veya döndürme gibi dönüşümler uygulandığında bit eşlem görevi görür.

Dönüşümler

Modifier.graphicsLayer, çizim talimatları için yalıtım sağlar. Örneğin, Modifier.graphicsLayer kullanılarak çeşitli dönüşümler uygulanabilir. Bunlar, çizim lambda'nın yeniden çalıştırılmasına gerek kalmadan canlandırılabilir veya değiştirilebilir.

Modifier.graphicsLayer, yalnızca çizim aşamasını etkilediğinden composable'ın ölçülen boyutunu veya yerleşimini değiştirmez. Diğer bir deyişle, composable'ınız düzen sınırlarının dışında çizim yapılırsa diğer öğelerle çakışabilir.

Bu değiştiriciyle aşağıdaki dönüşümler uygulanabilir:

Ölçek - boyutu büyütme

scaleX ve scaleY, içeriği sırasıyla yatay veya dikey yönde büyütür ya da küçültür. 1.0f değeri, ölçekte değişiklik olmadığını gösterir. 0.5f değeri, boyutun yarısı anlamına gelir.

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

Şekil 4: Image composable'a uygulanan ölçekX veScaleY
Çeviri

translationX ve translationY, graphicsLayer ile değiştirilebilir. translationX, composable'ı sola veya sağa taşır. translationY, composable'ı yukarı veya aşağı taşır.

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

Şekil 5: Modifier.graphicsLayer ile Görüntüye uygulanan çeviriX ve çeviriY işlemi
Döndürme

Yatay olarak döndürmek için rotationX, dikey olarak döndürmek için rotationY ve Z ekseninde döndürmek için rotationZ (standart döndürme) değerini ayarlayın. Bu değer derece (0-360) cinsinden belirtilir.

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

Şekil 6: Modifier.graphicslayer tarafından Görüntü'de ayarlanmış X, döndürmeY ve döndürmeZ
Kalkış noktası

Bir transformOrigin belirtilebilir. Daha sonra dönüşümlerin gerçekleştiği nokta olarak kullanılır. Şimdiye kadar tüm örneklerde TransformOrigin.Center kullanıldı. Bu, (0.5f, 0.5f). Kaynağı (0f, 0f) konumunda belirtirseniz dönüşümler composable'ın sol üst köşesinden başlar.

Kaynağı rotationZ dönüşümüyle değiştirirseniz öğenin composable'ın sol üst kısmı çevresinde döndüğünü görebilirsiniz:

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
        }
)

Şekil 7: TransformOrigin 0f, 0f olarak ayarlanmış rotasyon uygulama

Klip ve şekil

Şekil, clip = true olduğunda içeriğin kırpılacağı ana hatları belirtir. Bu örnekte, biri graphicsLayer klip değişkenini ve diğeri uygun sarmalayıcıyı (Modifier.clip) kullanan iki farklı klibe sahip iki kutuyu ayarladık.

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))
    )
}

İlk kutunun içeriği ("Hello Compose" yazan metin) daire şekline kesilir:

Klip, Box composable'a uygulandı
Şekil 8: Box composable'a uygulanan klip

Daha sonra, üstteki pembe daireye bir translationY uygularsanız Composable'ın sınırlarının hâlâ aynı olduğunu, ancak dairenin alt dairenin altına (ve sınırlarının dışına) çizildiğini görürsünüz.

Klip çevirme Y ve dış çizgi için kırmızı kenarlıkla uygulandı
Şekil 9: Çevirme Y ve dış çizgi için kırmızı kenarlık

composable'ı, çizildiği bölgeye kırpmak için değiştirici zincirinin başına başka bir Modifier.clip(RectangleShape) ekleyebilirsiniz. Böylece içerik orijinal sınırların içinde kalır.

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))
    )
}

Grafik katmanı dönüşümünün üzerine uygulanan klip
Şekil 10: Grafik katmanı dönüşümünün üzerine uygulanan klip

Alfa

Modifier.graphicsLayer, tüm katman için bir alpha (opaklık) değeri ayarlamak amacıyla kullanılabilir. 1.0f tamamen opak ve 0.0f görünmez.

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

Alfa uygulanmış resim
Şekil 11: Alfa uygulanmış resim

Oluşturma stratejisi

Alfa ve şeffaflıkla çalışmak, tek bir alfa değerini değiştirmek kadar basit olmayabilir. Alfa sürümünü değiştirmenin yanı sıra, graphicsLayer cihazında CompositingStrategy ayarlama seçeneği de vardır. CompositingStrategy, composable'ın içeriğinin ekranda çizilen diğer içerikle nasıl birleştirileceğini (bir araya getirileceğini) belirler.

Farklı stratejiler şunlardır:

Otomatik (varsayılan)

Birleştirme stratejisi, geri kalan graphicsLayer parametreleri tarafından belirlenir. Alfa 1.0f'den düşükse veya bir RenderEffect ayarlanmışsa katmanı ekran dışı arabelleğe oluşturur. Alfa 1f'den düşük olduğunda, içerikleri oluşturmak için otomatik olarak bir birleştirme katmanı oluşturulur ve daha sonra bu ekran dışı arabelleği karşılık gelen alfa ile hedefe çizin. RenderEffect veya fazla kaydırma ayarlamak, CompositingStrategy grubu ne olursa olsun içeriği her zaman ekran dışı arabelleğe oluşturur.

Ekran dışı

composable'ın içeriği, hedef için oluşturulmadan önce her zaman ekran dışı doku veya bit eşlem halinde pikselleştirilir. Bu, içeriği maskelemek için BlendMode işlemleri uygulanırken ve karmaşık çizim talimatı gruplarını oluştururken performans açısından yararlıdır.

BlendModes ile CompositingStrategy.Offscreen kullanımına bir örnek verilebilir. Aşağıdaki örneğe göz atarken, BlendMode.Clear kullanan bir çizim komutu yayınlayarak Image composable'ının bazı bölümlerini kaldırmak istediğinizi varsayalım. compositingStrategy öğesini CompositingStrategy.Offscreen olarak ayarlamazsanız BlendMode, altındaki tüm içeriklerle etkileşime geçer.

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
                   )
               )
           }

       }
)

CompositingStrategy, Offscreen olarak ayarlandığında komutların yürütüleceği ekran dışı bir doku oluşturur (BlendMode öğesi yalnızca bu composable'ın içeriğine uygulanır). Daha sonra, çizilen içeriği etkilemeden bu resmi ekranda oluşturulmuş öğelerin üzerinde oluşturur.

Daire şeklinde gösterilen bir resimdeki Modifier.drawWithContent ve uygulamanın içinde BlendMode.Clear
Şekil 12: Daire işareti bulunan bir resim üzerinde Modifier.drawWithContent; uygulama içinde BlendMode.Clear and CompositingStrategy.Offscreen

CompositingStrategy.Offscreen kullanmadıysanız BlendMode.Clear uygulamasının sonuçları, daha önce yapılan ayardan bağımsız olarak hedefteki tüm pikselleri temizler. Böylece pencerenin oluşturma arabelleği (siyah) görünür durumda kalır. Alfa içeren BlendModes öğelerinin çoğu, ekran dışı arabellek olmadan beklendiği gibi çalışmaz. Kırmızı daire göstergesinin etrafındaki siyah halkaya dikkat edin:

Daire işareti gösteren, BlendMode.Clear ve CompositingStrategy değerinin ayarlandığı bir resim üzerinde Modifier.drawWithContent
Şekil 13: Daire işareti bulunan, BlendMode.Clear ve CompositingStrategy değerinin ayarlandığı bir resim üzerinde Modifier.drawWithContent

Bunu biraz daha ayrıntılı bir şekilde anlamak isteriz: Uygulamanın yarı saydam bir pencere arka planı varsa ve CompositingStrategy.Offscreen öğesini kullanmadıysanız BlendMode, uygulamanın tamamıyla etkileşimde bulunur. Aşağıdaki örnekte olduğu gibi, uygulamanın veya duvar kağıdının altında gösterilmesi için tüm pikseller temizlenir:

No CompositingStrategy ayarlanmamış ve BlendMode.Clear, yarı saydam pencere arka planı olan bir uygulamayla kullanılıyor. Pembe duvar kağıdı, kırmızı durum dairesinin etrafındaki alanda gösterilir.
Şekil 14: CompositingStrategy yoksa ve BlendMode.Clear, yarı saydam pencere arka planı olan bir uygulamayla kullanılır. Kırmızı durum dairesinin çevresindeki alanda pembe duvar kağıdının nasıl gösterildiğine dikkat edin.

CompositingStrategy.Offscreen kullanılırken, çizim alanının büyüklüğünde ekran dışı doku oluşturulur ve ekranda tekrar görüntülenir. Bu strateji ile yapılan tüm çizim komutları, varsayılan olarak bu bölgeye kırpılır. Aşağıdaki kod snippet'i, ekran dışı dokuları kullanmaya geçişteki farkları göstermektedir:

@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 - CompositingStrategy.Auto-CompositingStrategy.Kapalı ekran - otomatik görüntülerin uygulanmadığı bölgeye ekran dışı klipler
Şekil 15: CompositingStrategy.Auto ve CompositingStrategy.Çevrimdışı - bölge için ekran dışı klipler (otomatik olmayan yerlerde)
ModulateAlpha

Bu kompozisyon stratejisi, graphicsLayer içinde kaydedilen her çizim talimatının alfa sürümünü değiştirir. RenderEffect ayarlanmadığı sürece 1.0f'nin altında alfa için ekran dışı arabellek oluşturmaz. Böylece alfa oluşturma için daha verimli olabilir. Ancak çakışan içerikler için farklı sonuçlar sağlayabilir. İçeriğin çakışmadığının önceden bilindiği kullanım durumlarında bu, 1'den küçük alfa değerlerine sahip CompositingStrategy.Auto uygulamasından daha iyi performans sağlayabilir.

Farklı beste stratejilerine başka bir örnek de şöyledir: composable'ların farklı bölümlerine farklı alfalar uygulama ve bir Modulate stratejisi uygulama:

@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)

ModlateAlpha, alfa kümesini ayrı ayrı her çizim komutuna uygular
Şekil 16: ModlateAlpha, her bir çizim komutuna alfa setini uygular

composable'ın içeriğini bit eşlem olarak yazma

Yaygın bir kullanım alanı, composable'dan Bitmap oluşturmaktır. Beste dosyanızın içeriğini Bitmap dosyasına kopyalamak için rememberGraphicsLayer() ile bir GraphicsLayer oluşturun.

drawWithContent() ve graphicsLayer.record{} kullanarak çizim komutlarını yeni katmana yönlendirin. Ardından, görünür tuvalde drawLayer kullanarak katmanı çizin:

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)
}

Bit eşlemi diske kaydedip paylaşabilirsiniz. Daha ayrıntılı bilgi için tam örnek snippet'e bakın. Diske kaydetmeye çalışmadan önce cihaz üzerinde izin olup olmadığını kontrol edin.

Özel çizim değiştirici

Kendi özel değiştiricinizi oluşturmak için DrawModifier arayüzünü uygulayın. Bu şekilde bir ContentDrawScope için erişim izni verilir. Bu, Modifier.drawWithContent() kullanılırken gösterilen erişimle aynıdır. Daha sonra, kodu temizlemek ve kullanışlı sarmalayıcılar sağlamak için özel çizim değiştiricilere genel çizim işlemlerini ayıklayabilirsiniz. Örneğin, Modifier.background() kullanışlı bir DrawModifier'dır.

Örneğin, içeriği dikey olarak çeviren bir Modifier uygulamak istiyorsanız aşağıdaki gibi oluşturabilirsiniz:

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

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

Ardından, Text üzerinde uygulanan bu çevrilmiş değiştiriciyi kullanın:

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

Metin Üzerinde Özel Ters Yüz Edilmiş Değiştirici
Şekil 17: Metin Üzerinde Özel Ters Yüz Edilmiş Değiştirici

Ek kaynaklar

graphicsLayer ve özel çizim kullanımıyla ilgili daha fazla örnek için aşağıdaki kaynaklara göz atın: