Oluşturulan Grafikler

Birçok uygulamanın ekranda tam olarak nelerin çizileceğini kontrol edebilmesi gerekir. Bu, ekrana tam olarak doğru yere bir kutu veya daire yerleştirmek kadar küçük veya birçok farklı stildeki grafik öğelerinin ayrıntılı bir düzenlemesi kadar büyük 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
        }
)

Tek ihtiyacınız çizim yapan bir bileşense Canvas bileşenini kullanabilirsiniz. Canvas bileşeni, Modifier.drawBehind etrafında kullanışlı 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, stil ve konumları üzerinde hassas kontrol sahibi olarak öğeler çizebilirsiniz.

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

Bir şey çizmek için DrawScope'teki birçok çizim işlevinden birini kullanabilirsiniz. Örneğin, aşağıdaki kod ekranın sol üst köşesine bir dikdörtgen çizer:

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

Beyaz arka plan üzerinde ekranın dörtte birini kaplayan 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 birçok çizim yönteminde 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 Oluştur'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 doğru ç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üşü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üzensiz şekilde ölçeklendirilmiş bir 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 daireye taşıma işlemi uygulama.

Döndür

Çizim işlemlerinizi bir pivot noktası 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, dikdörtgeni 45 derece döndürür.

İçe doğru

Mevcut DrawScope'ın varsayılan parametrelerini ayarlamak için DrawScope.inset()'u kullanarak çizim sınırlarını değiştirin ve çizimleri buna göre ç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 bir kaydırma 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. Hem döndürme hem de taşıma işlemi uygulamak için withTransform simgesini kullanarak dikdörtgeni döndürün ve sola kaydırın.

Sık kullanılan çizim işlemleri

Metin çizme

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 ile, 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. Arka plan dikdörtgeni içeren, tüm alanın ⅔'ünü kaplayan çok satırlı metin.

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 kodda metin, derlenebilir alanın yüksekliğinin ⅓'ünde ve genişliğinin ⅓'ünde oluşturulur ve TextOverflow, TextOverflow.Ellipsis olarak ayarlanır:

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

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'te birçok şekil çizme işlevi vardır. Şekil çizmek için önceden tanımlanmış çizim işlevlerinden birini (ör. drawCircle) 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()

draw rounded rect

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 elde etmek 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 nesnesine erişim

DrawScope ile Canvas nesnesine doğrudan erişiminiz yoktur. İşlev çağırabileceğiniz Canvas nesnesine erişmek için DrawScope.drawIntoCanvas() kullanabilirsiniz.

Örneğin, kanvas üzerine çizmek istediğiniz özel bir Drawable'iniz varsa kanvasa erişebilir ve Canvas nesnesini ileterek Drawable#draw()'i ç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

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