Oluşturulan Grafikler

Birçok uygulamanın, ekranda çizilenleri tam olarak kontrol edebilmesi gerekir. Bu, ekranda doğru yere bir kutu veya daire yerleştirmek gibi küçük bir şey olabileceği gibi, grafik öğelerinin birçok farklı stilde ayrıntılı bir düzenlemesi de olabilir.

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

Oluşturma'da özel bir şey çizmenin temel yöntemi, Modifier.drawWithContent, Modifier.drawBehind ve Modifier.drawWithCache gibi değiştiricileri 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 kullanışlı bir sarmalayıcıdır. Canvas öğesini, düzeninize diğer tüm Compose kullanıcı arayüzü öğeleriyle aynı şekilde yerleştirirsiniz. Canvas içerisinde, stilleri ve konumları üzerinde hassas kontrol kontrolüne sahip öğeler çizebilirsiniz.

Tüm çizim değiştiricileri, kendi durumunu koruyan kapsamlı bir çizim ortamı olan DrawScope'i açığa çıkarır. Böylece, bir grup grafik öğesi için parametreleri ayarlayabilirsiniz. DrawScope, DrawScope öğesinin mevcut boyutlarını belirten bir Size nesnesi olan size gibi birçok yararlı alan sağlar.

Bir şey çizmek için DrawScope ürünündeki birçok ç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 çizilmiş 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 belirli uzaklıkta kopyasını (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 konumlandırır ve yukarıdaki örnekte olduğu gibi, çizim alanının tamamını kaplayan 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 pikselde bulunur. x sağa hareket ettikçe, y aşağı hareket ettikçe artar.

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

Örneğin, tuval alanının sağ üst köşesinden sol alt köşeye çapraz bir ç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üleceğini değiştirmek için dönüştürme işlemleri sunar.

Ölçek

Çizim işlemlerinizin boyutunu bir kat artırmak için DrawScope.scale() 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())
    }
}

Eşit olmayan şekilde ölçeklendirilmiş bir daire
Şekil 3. Canvas'ta bir daireye ölçekleme işlemi uygulama.

Çevir

Çizim işlemlerinizi yukarı, aşağı, sola veya sağa taşımak için DrawScope.translate() aracını 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 uzaklaşmış bir daire
Şekil 4. Canvas'ta bir çevreye çeviri işlemi uygulama.

Döndür

Çizim işlemlerinizi bir pivot nokta etrafında döndürmek için DrawScope.rotate() 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 olan telefon
Şekil 5. Dikdörtgeni 45 derece döndüren geçerli çizim kapsamına bir döndürme uygulamak için rotate() kullanırız.

İçe doğru

Çizim sınırlarını değiştirerek ve çizimleri uygun şekilde çevirerek mevcut DrawScope öğesinin varsayılan parametrelerini ayarlamak için DrawScope.inset() aracını kullanın:

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 dolu bir dikdörtgen
Şekil 6. Çizim komutlarına bir iç küme uygulama.

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şturup uygulayan DrawScope.withTransform() işlevini kullanın. Compose'un iç içe yerleştirilmiş her dönüşümü hesaplayıp kaydetmesi gerekmeden tüm dönüşümler tek bir işlemde birlikte gerçekleştirilir. Bu nedenle withTransform() kullanımı, bağımsız dönüşümlere iç içe geçmiş ç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üş bir dikdörtgen ekranın kenarına kaydırılmış bir telefon
Şekil 7. Hem döndürme hem de çevirme uygulamak için withTransform işlevini kullanın ve dikdörtgeni döndürüp sola kaydırın.

Genel çizim işlemleri

Metin çizin

Oluştur'da metin çizmek için genellikle Text composable'ı kullanabilirsiniz. Ancak, DrawScope kullanıyorsanız 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 cihazıyla drawText çağırın:

val textMeasurer = rememberTextMeasurer()

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

Tuval üzerinde çizilmiş bir Hello gösterme
Şekil 8. Tuval üzerine metin çizme.

Metni ölç

Metin çizme işlemi, diğer çizim komutlarından biraz farklı çalışır. Normalde, çizim komutuna şekli/görüntüyü çizeceği boyutu (genişlik ve yükseklik) verirsiniz. Metinde, oluşturulan metnin boyutunu kontrol eden yazı tipi boyutu, yazı tipi, bağ işaretleri ve harf aralıkları gibi birkaç parametre vardır.

Oluşturma özelliğinde, yukarıdaki unsurlara bağlı olarak ölçülen metin boyutuna erişmek için TextMeasurer kullanabilirsiniz. Metnin arkasına bir arka plan çizmek istiyorsanız ölçülen bilgileri kullanarak metnin kapladığı alanın boyutunu öğrenebilirsiniz:

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 metin üzerinde pembe bir arka plan oluşturur:

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

Kısıtlamaları, yazı tipi boyutunu veya ölçülen boyutu etkileyen herhangi bir özelliği ayarlamak, yeni bir boyutun raporlanmasına neden olur. Hem width hem de height için sabit bir boyut ayarlayabilirsiniz. Ardından metin, TextOverflow kümesini izler. Ö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 sonunda üç nokta ile kısıtlamalarla çizilir:

Pembe arka plan üzerine üç noktayla çizilmiş metin ve metin kesiliyor.
Şekil 10. Metin ölçümünde sabit kısıtlamalarla TextOverflow.Ellipsis.

Resim çizin

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

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

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

Tuval üzerine çizilmiş bir köpek resmi
Şekil 11. Tuval üzerinde ImageBitmap çizme.

Basit şekiller çizme

DrawScope ürününde birçok ş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()

dikdörtgen çizim

drawRoundedRect()

yuvarlak dikdörtgen çizme

drawLine()

çizgi çizme

drawOval()

oval çiz

drawArc()

çizim yay

drawPoints()

çizim noktaları

Yol çizin

Yol, bir çizimin yürütülmesini sağlayan bir dizi matematiksel talimattır. DrawScope, DrawScope.drawPath() yöntemini kullanarak bir yol çizebilir.

Örneğin, üç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 elde etmek için yeni oluşturulan bu yolla drawPath() yöntemini ç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 çizilmiş ters mor bir yol üçgeni
Şekil 12. Compose'da Path oluşturup çizme.

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

Örneğin, tuvale çizmek istediğiniz özel bir Drawable varsa tuvale erişebilir ve Canvas nesnesini geçirerek 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: