Oluşturulan Grafikler

Birçok uygulamanın ekranda tam olarak neyin çizildiğini hassas bir şekilde kontrol edebilmesi gerekir. Ekranda doğru yere bir kutu veya daire yerleştirmek kadar küçük bir şey de olabilir, pek çok farklı stilde grafik öğelerin ayrıntılı bir şekilde düzenlenmiş olarak gösterilmesi de olabilir.

Değiştiriciler ve DrawScope içeren temel çizim

Compose'da özel öğeler çizmenin temel yolu Modifier.drawWithContent, Modifier.drawBehind ve Modifier.drawWithCache gibi düzenleyiciler kullanmaktır.

Örneğin, composable'ınızın arkasına bir şey çizmek için drawBehind değiştiricisini kullanarak çizim komutlarını yürütmeye başlayabilirsiniz:

Spacer(
    modifier = Modifier
        .fillMaxSize()
        .drawBehind {
            // this = DrawScope
        }
)

Yalnızca çizim yapan bir composable'a ihtiyacınız varsa Canvas composable'ı kullanabilirsiniz. Canvas composable, Modifier.drawBehind için uygun bir sarmalayıcıdır. Canvas öğesini, düzeninize diğer herhangi bir Compose kullanıcı arayüzü öğesiyle aynı şekilde yerleştirirsiniz. Canvas içinde stilleri ve konumları üzerinde hassas kontrole sahip öğeler çizebilirsiniz.

Tüm çizim değiştiricileri, kendi durumunu koruyan, kapsamlı bir çizim ortamı olan DrawScope'ı gösterir. Bu, bir grup grafik öğesi için parametreleri ayarlayabilmenizi sağlar. DrawScope, DrawScope öğesinin mevcut boyutlarını belirten bir Size nesnesi olan size gibi çeşitli yararlı alanlar sağlar.

Bir şeyler çizmek için DrawScope cihazındaki çok sayıda çizim işlevinden birini kullanabilirsiniz. Örneğin, aşağıdaki kod ekranın sol üst köşesinde bir dikdörtgen çizer:

Canvas(modifier = Modifier.fillMaxSize()) {
    val canvasQuadrantSize = size / 2F
    drawRect(
        color = Color.Magenta,
        size = canvasQuadrantSize
    )
}

Ekranın dörtte birini kaplayan beyaz bir arka plan üzerine çizilmiş pembe dikdörtgen
Şekil 1. Compose'da Tuval kullanılarak çizilen dikdörtgen.

Farklı çizim değiştiricileri hakkında daha fazla bilgi edinmek için Grafik Değiştiriciler dokümanlarına bakın.

Koordinat sistemi

Ekranda bir şey çizmek için öğenizin ofsetini (x ve y) ve boyutunu bilmeniz gerekir. DrawScope üzerindeki çizim yöntemlerinin çoğunda konum ve boyut, varsayılan parametre değerleri tarafından sağlanır. Varsayılan parametreler genellikle öğeyi kanvasın [0, 0] noktasında konumlandırır ve yukarıdaki örnekte olduğu gibi tüm çizim alanını dolduran varsayılan bir size sağlar. Dikdörtgenin sol üste yerleştirildiğini görebilirsiniz. Öğenizin boyutunu ve konumunu ayarlamak için Compose'daki koordinat sistemini anlamanız gerekir.

Koordinat sisteminin başlangıç noktası ([0,0]), çizim alanında en soldaki pikseldedir. x sağa hareket ettikçe, y aşağıya doğru hareket ettikçe artar.

Sol üst [0, 0] ve sağ alt [genişlik, yükseklik] koordinat sistemini gösteren ızgara
Şekil 2. Koordinat sistemi / çizim ızgarası.

Örneğin, kanvas alanının sağ üst köşesinden sol alt köşeye doğru çapraz bir çizgi çizmek isterseniz DrawScope.drawLine() işlevini kullanarak karşılık gelen x ve y konumları ile bir başlangıç ve bitiş ofseti belirtebilirsiniz:

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

Temel dönüşümler

DrawScope, çizim komutlarının nerede ve nasıl yürütüleceğini değiştirmek için dönüşümler sunar.

Ölçek

Çizim işlemlerinizin boyutunu bir faktör oranında artırmak için DrawScope.scale() değerini kullanın. scale() gibi işlemler, ilgili lambda içindeki tüm çizim işlemleri için geçerlidir. Örneğin, aşağıdaki kod scaleX değerini 10 kez, scaleY değerini 15 kez artırır:

Canvas(modifier = Modifier.fillMaxSize()) {
    scale(scaleX = 10f, scaleY = 15f) {
        drawCircle(Color.Blue, radius = 20.dp.toPx())
    }
}

Düzgün olmayan bir şekilde ölçeklenmiş daire
Şekil 3. Canvas'ta bir daireye ölçek işlemi uygulanıyor.

Çevir

Çizim işlemlerinizi yukarı, aşağı, sola veya sağa taşımak için DrawScope.translate() simgesini kullanın. Örneğin, aşağıdaki kod çizimi 100 piksel sağa ve 300 piksel yukarı taşır:

Canvas(modifier = Modifier.fillMaxSize()) {
    translate(left = 100f, top = -300f) {
        drawCircle(Color.Blue, radius = 200.dp.toPx())
    }
}

Merkezden ayrılan bir daire
Şekil 4. Canvas'ta bir çevreye çeviri işlemi uygulanıyor.

Döndür

Çizim işlemlerinizi bir pivot nokta etrafında döndürmek için DrawScope.rotate() simgesini kullanın. Örneğin, aşağıdaki kod bir dikdörtgeni 45 derece döndürür:

Canvas(modifier = Modifier.fillMaxSize()) {
    rotate(degrees = 45F) {
        drawRect(
            color = Color.Gray,
            topLeft = Offset(x = size.width / 3F, y = size.height / 3F),
            size = size / 3F
        )
    }
}

Ekranın ortasında 45 derece döndürülmüş dikdörtgen bir telefon
Şekil 5. Geçerli çizim kapsamına döndürme uygulamak için rotate() kullanılır. Bu işlem, dikdörtgeni 45 derece döndürür.

İçe doğru

Geçerli DrawScope öğesinin varsayılan parametrelerini ayarlamak için DrawScope.inset() aracını kullanın, çizim sınırlarını değiştirin ve çizimleri uygun şekilde çevirin:

Canvas(modifier = Modifier.fillMaxSize()) {
    val canvasQuadrantSize = size / 2F
    inset(horizontal = 50f, vertical = 30f) {
        drawRect(color = Color.Green, size = canvasQuadrantSize)
    }
}

Bu kod, çizim komutlarına etkili bir şekilde dolgu ekler:

Etrafıyla doldurulmuş bir dikdörtgen
Şekil 6. Çizim komutlarına ek ekleme.

Birden fazla dönüşüm

Çizimlerinize birden fazla dönüşüm uygulamak için istediğiniz tüm değişiklikleri birleştiren tek bir dönüşüm oluşturan ve uygulayan DrawScope.withTransform() işlevini kullanın. Tüm dönüşümler tek bir işlemde birlikte gerçekleştirildiğinden, iç içe yerleştirilmiş dönüşümlerin her birini hesaplayıp kaydetmesi gerekmez. Bunun yerine withTransform() kullanmak, ayrı ayrı dönüşümler için iç içe yerleştirilmiş çağrılar yapmaktan daha verimlidir.

Örneğin, aşağıdaki kod dikdörtgene hem çevirme hem de döndürme uygular:

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

Döndürülmüş dikdörtgeni ekranın yan tarafına kaydırılmış bir telefon
Şekil 7. withTransform hareketini kullanarak hem döndürme hem de çevirme işlemi uygulayın. Dikdörtgeni döndürüp sola kaydırın.

Genel çizim işlemleri

Metin çizin

Compose'da metin çizmek için genellikle Text composable'ı kullanabilirsiniz. Ancak DrawScope içindeyseniz veya metninizi özelleştirme ile manuel olarak çizmek istiyorsanız DrawScope.drawText() yöntemini kullanabilirsiniz.

Metin çizmek için rememberTextMeasurer kullanarak bir TextMeasurer oluşturun ve ölçüm aracıyla drawText öğesini çağırın:

val textMeasurer = rememberTextMeasurer()

Canvas(modifier = Modifier.fillMaxSize()) {
    drawText(textMeasurer, "Hello")
}

Tuval üzerinde çizilmiş merhaba gösteriliyor
Şekil 8. Tuvale metin çizimi.

Metni ölçün

Metin çizimi, diğer çizim komutlarından biraz farklı şekilde çalışır. Normalde, çizim komutuna şekli/görüntüyü çizmek için boyut (genişlik ve yükseklik) verirsiniz. Metinde, oluşturulan metnin boyutunu kontrol eden, yazı tipi boyutu, yazı tipi, bitiş çizgisi ve harf aralığı gibi birkaç parametre vardır.

Oluştur'da, yukarıdaki faktörlere bağlı olarak ölçülen metin boyutuna erişmek için bir TextMeasurer kullanabilirsiniz. Metnin arkasına bir arka plan çizmek istiyorsanız metnin kapladığı alanın boyutunu öğrenmek için ölçülen bilgileri kullanabilirsiniz:

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

Bu kod snippet'i, metinde pembe bir arka plan oluşturur:

Tüm alanın 2⁄3'ünü kaplayan ve arka planı dikdörtgen olan çok satırlı metinler
Şekil 9. Tüm alanın 2⁄3'ünü kaplayan ve arka planı dikdörtgen olan çok satırlı metinler.

Kısıtlamaları, yazı tipi boyutunu veya ölçülen boyutu etkileyen herhangi bir özelliği ayarladığınızda, yeni bir boyut raporlanır. Hem width hem de height için sabit bir boyut ayarlayabilirsiniz. Ardından metin, TextOverflow grubundan sonra gelir. Örneğin, aşağıdaki kod, metni composable alanın yüksekliğinin 1⁄3'ü ve genişliğinin 1⁄3'ünde oluşturur ve TextOverflow değerini TextOverflow.Ellipsis olarak ayarlar:

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

Metin artık kısıtlamalar içinde üç nokta ile çizilir:

Pembe arka plan üzerine çizilmiş metin. Metni kesen üç nokta var.
Şekil 10. Metin ölçümünde sabit kısıtlamalarla TextOverflow.Ellipsis.

Resim çizin

DrawScope ile ImageBitmap çizmek için ImageBitmap.imageResource() uygulamasını kullanarak resmi yükleyin ve drawImage işlevini çağırın:

val dogImage = ImageBitmap.imageResource(id = R.drawable.dog)

Canvas(modifier = Modifier.fillMaxSize(), onDraw = {
    drawImage(dogImage)
})

Tuval'e çizilmiş köpek resmi
Şekil 11. Tuval üzerinde ImageBitmap çiziliyor.

Temel şekiller çizme

DrawScope üzerinde çok sayıda şekil çizim işlevi var. Şekil çizmek için drawCircle gibi önceden tanımlanmış çizim işlevlerinden birini kullanın:

val purpleColor = Color(0xFFBA68C8)
Canvas(
    modifier = Modifier
        .fillMaxSize()
        .padding(16.dp),
    onDraw = {
        drawCircle(purpleColor)
    }
)

API

Çıkış

drawCircle()

daire çizin

drawRect()

dikdörtgen çizin

drawRoundedRect()

yuvarlak dikdörtgen çiz

drawLine()

çizgi çizme

drawOval()

oval çiz

drawArc()

yay çizme

drawPoints()

çizim noktaları

Yol çizin

Yol, bir çizim çalıştırıldıktan sonra elde edilen bir dizi matematiksel talimattır. DrawScope, DrawScope.drawPath() yöntemini kullanarak yol çizebilir.

Örneğin, bir üçgen çizmek istediğinizi düşünelim. Çizim alanının boyutunu kullanarak lineTo() ve moveTo() gibi işlevlerle yol oluşturabilirsiniz. Ardından, bir üçgen elde etmek için yeni oluşturulan bu yolla drawPath() komutunu çağırın.

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

Compose'da baş aşağı mor bir yol üçgeni çizilmiş
Şekil 12. Compose'da Path oluşturup çizim.

Canvas nesneye erişiliyor

DrawScope ile bir Canvas nesnesine doğrudan erişiminiz yok. İşlevleri çağırabileceğiniz Canvas nesnesine erişmek için DrawScope.drawIntoCanvas() aracını kullanabilirsiniz.

Örneğin, tuvale çizmek istediğiniz özel bir Drawable varsa tuvale erişebilir ve Canvas nesnesini ileterek Drawable#draw() yöntemini çağırabilirsiniz:

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

Tam boyutu kaplayan oval siyah ShapeDrawable
Şekil 13. Drawable çizmek için tuvale erişiliyor.

Daha fazla bilgi

Compose'da Çizim yapma hakkında daha fazla bilgi için aşağıdaki kaynaklara göz atın: