Oluşturulan Grafikler

Birçok uygulamanın ekranda tam olarak nelerin çizileceğ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ştirici ve DrawScope içeren temel çizim

Oluşturma'da özel bir şey çizmenin temel yolu, Modifier.drawWithContent, Modifier.drawBehind ve Modifier.drawWithCache gibi değiştiricileri kullanmaktır.

Örneğin, kompozisyonunuzun arkasında bir şey çizmek için çizim komutlarını yürütmeye başlamak üzere drawBehind değiştiricisini kullanabilirsiniz:

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, diğer tüm Oluştur kullanıcı arayüzü öğelerinde yaptığınız gibi düzeninize 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 sayede, bir grup grafik öğesinin parametrelerini ayarlayabilirsiniz. DrawScope, DrawScope'nin 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. Oluşturma bölümünde Tuval kullanılarak çizilen dikdörtgen.

Farklı çizim değiştiricileri hakkında daha fazla bilgi edinmek için Grafik Değiştiriciler belgelerine 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 kanvastaki [0, 0] noktasına yerleştirir ve yukarıdaki örnekte olduğu gibi çizim alanının tamamını dolduran bir varsayılan size sağlar. Dikdörtgenin sol üstte konumlandırıldığını 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ının sol üst köşesindeki en soldaki pikseldir. x sağa doğru hareket ettikçe artar ve y aşağı doğru hareket ettikçe artar.

Sol üst [0, 0] ve sağ alt [width, height] noktalarını gösteren koordinat sistemini gösteren bir ızgara
Şekil 2. Çizim koordinat sistemi / çizim ızgarası.

Örneğin, tuval alanının sağ üst köşesinden sol alt köşeye çapraz çizgi çizmek istiyorsanız DrawScope.drawLine() işlevini kullanabilir ve karşılık gelen x ve y konumlarıyla 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 veya nasıl yürütüldüğünü değiştirmek için dönüşümler sunar.

Ölçek

Çizim işlemlerinizin boyutunu bir faktörle artırmak için DrawScope.scale() simgesini 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 ise 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çekleme işlemi uygulama.

Çeviri

Ç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ılmış 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üş bir dikdörtgen bulunan telefon
Şekil 5. Geçerli çizim kapsamına bir rotasyon uygulamak için rotate() kullanırız. 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ı dolgu yapılmış bir dikdörtgen
Şekil 6. Çizim komutlarına iç içe yerleştirilmiş resim uygulama

Birden fazla dönüşüm

Çizimlerinize birden fazla dönüşüm uygulamak için DrawScope.withTransform() işlevini kullanın. Bu işlev, istediğiniz tüm değişiklikleri birleştiren tek bir dönüşüm oluşturup uygular. withTransform() kullanmak, tüm dönüşümlerin tek bir işlemde birlikte gerçekleştirilmesi nedeniyle, Compose'un iç içe yerleştirilmiş dönüşümlerin her birini hesaplayıp kaydetmesi gerekmediğinden, bağımsız dönüşümlere 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
        )
    }
}

Ekranın kenarına kaydırılmış, döndürülmüş bir dikdörtgen içeren 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

Oluşturma bölümünde metin çizmek için genellikle Text kompozisyonunu kullanabilirsiniz. Ancak DrawScope içindeyseniz veya metninizi özelleştirmeyle manuel olarak çizmek istiyorsanız DrawScope.drawText() yöntemini kullanabilirsiniz.

Metin çizmek için rememberTextMeasurer kullanarak bir TextMeasurer oluşturun ve ölçer ile drawText'yi çağırın:

val textMeasurer = rememberTextMeasurer()

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

Canvas'ta çizilen Merhaba yazısını gösteren resim
Şekil 8. Kanvas'ta metin çizme.

Metni ölçme

Metin çizme, diğer çizim komutlarından biraz farklı çalışır. Normalde, çizim komutuna şekli/resmi çizmek için boyutu (genişlik ve yükseklik) belirtirsiniz. Metinlerde, oluşturulan metnin boyutunu kontrol eden yazı tipi boyutu, yazı tipi, ligatür ve harf aralığı gibi birkaç parametre vardır.

Compose'da, yukarıdaki faktörlere bağlı olarak metnin ölçülen boyutuna erişmek için 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:

Arka plan dikdörtgeni içeren, tüm alanın ⅔'ünü kaplayan çok satırlı metin
Ş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 ayarlamak, raporlanan yeni bir boyuta neden olur. Hem width hem de height için sabit bir boyut ayarlayabilirsiniz. Ardından metin, ayarlanan TextOverflow değerini takip eder. Ö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ıtlamalara uygun şekilde çizilir ve sonuna üç nokta eklenir:

Pembe arka plan üzerinde çizilen metin, üç noktayla kesilmiş.
Şekil 10. TextOverflow.Ellipsis, metin ölçümüyle ilgili sabit kısıtlamalara sahiptir.

Resim çizin

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

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

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

Tuval üzerine çizilmiş bir köpeğin resmi
Şekil 11. Canvas'ta ImageBitmap çizme.

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 çizme

drawRect()

draw rect

drawRoundedRect()

yuvarlak dikdörtgen çiz

drawLine()

çizgi çizme

drawOval()

oval çizme

drawArc()

yay çizme

drawPoints()

çizim noktaları

Yol çizme

Yol, uygulandığında bir çizimle sonuçlanan bir dizi matematiksel talimattır. DrawScope, DrawScope.drawPath() yöntemini kullanarak bir yol çizebilir.

Örneğin, bir üçgen çizmek istediğinizi varsayalım. Çizim alanının boyutunu kullanarak lineTo() ve moveTo() gibi işlevlerle bir yol oluşturabilirsiniz. Ardından, üçgen oluşturmak için yeni oluşturulan bu yolu kullanarak drawPath() işlevini ç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()
)

Oluştur'da çizilen ters mor yol üçgeni
Şekil 12. Oluşturma bölümünde Path oluşturma ve çizme

Canvas nesneye erişiliyor

DrawScope ile bir Canvas nesnesine doğrudan erişiminiz yok. İşlev çağırabileceğiniz Canvas nesnesine erişmek için DrawScope.drawIntoCanvas() 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 boyutta yer kaplayan oval siyah bir ShapeDrawable
Şekil 13. Drawable çizmek için tuvale erişme.

Daha fazla bilgi

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