Compose, Canvas composable'a ek olarak özel içerik çizmeye yardımcı olan çeşitli kullanışlı grafiklere Modifiers sahiptir. Bu değiştiriciler, herhangi bir composable'a uygulanabildikleri için kullanışlıdır.
Çizim değiştiriciler
Tüm çizim komutları, Compose'da çizim değiştiriciyle yapılır. Compose'da üç ana çizim değiştirici vardır:
Çizim için temel değiştirici drawWithContent'dır. Burada, Composable'ınızın çizim sırasına ve değiştiricinin içinde verilen çizim komutlarına karar verebilirsiniz. drawBehind, çizim sırası composable'ın içeriğinin arkasına ayarlanmış olan drawWithContent için uygun bir sarmalayıcıdır. drawWithCache
içinde onDrawBehind veya onDrawWithContent çağrıları yapar ve bunlarda oluşturulan nesneleri önbelleğe almak için bir mekanizma sağlar.
Modifier.drawWithContent: Çizim sırasını seçin
Modifier.drawWithContent, DrawScope işlemlerini composable'ın içeriğinden önce veya sonra yürütmenize olanak tanır. Daha sonra composable'ın gerçek içeriğini oluşturmak için drawContent işlevini çağırdığınızdan emin olun. Bu değiştiriciyle, içeriklerinizin özel çizim işlemlerinizden önce mi yoksa sonra mı çizilmesini istediğinize karar vererek işlemlerin sırasını belirleyebilirsiniz.
Örneğin, kullanıcı arayüzünde el feneri anahtar deliği efekti oluşturmak için içeriğinizin üzerinde dairesel renk geçişi oluşturmak istiyorsanız 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 }
Modifier.drawBehind: Bir composable'ın arkasında çizim yapma
Modifier.drawBehind, ekranda çizilen composable içeriğin arkasında DrawScope işlemlerini gerçekleştirmenize olanak tanır. Canvas uygulamasını incelerseniz bunun yalnızca Modifier.drawBehind için uygun bir sarmalayıcı olduğunu fark edebilirsiniz.
Text simgesinin arkasına yuvarlatılmış bir dikdörtgen çizmek için:
Text( "Hello Compose!", modifier = Modifier .drawBehind { drawRoundRect( Color(0xFFBBAAEE), cornerRadius = CornerRadius(10.dp.toPx()) ) } .padding(4.dp) )
Bu işlem aşağıdaki sonucu verir:
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 üzerinde oluşturulan nesnelerin (ör. Brush, Shader, Path vb.) yeniden ayrılmasına gerek kalmadığı için çizim çağrılarının performansını artırmak için kullanışlıdır.
Alternatif olarak, değiştiricinin dışında remember kullanarak da nesneleri önbelleğe alabilirsiniz. Ancak kompozisyona 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 iyi performans sağlayabilir.
Örneğin, Text arkasına gradyan çizmek için Brush oluşturursanız drawWithCache, çizim alanının boyutu değişene kadar Brush nesnesini önbelleğe alır:
Text( "Hello Compose!", modifier = Modifier .drawWithCache { val brush = Brush.linearGradient( listOf( Color(0xFF9E82F0), Color(0xFF42A5F5) ) ) onDrawBehind { drawRoundRect( brush, cornerRadius = CornerRadius(10.dp.toPx()) ) } } )
Grafik değiştiriciler
Modifier.graphicsLayer: Composables'a dönüşüm uygulama
Modifier.graphicsLayer, composable'ın içeriğini bir çizim katmanına çizmesini sağlayan bir değiştiricidir. Bir katman, aşağıdakiler gibi birkaç farklı işlev sunar:
- Çizim talimatları için yalıtım (
RenderNode'a benzer). Bir katman kapsamında yakalanan çizim talimatları, uygulama kodu yeniden yürütülmeden oluşturma ardışık düzeni tarafından verimli bir şekilde yeniden verilebilir. - Bir katmanda bulunan tüm çizim talimatlarına uygulanan dönüşümler.
- Beste özelliklerinde rasterleştirme. Bir katman rasterleştirildiğinde çizim talimatları yürütülür ve çıkış, ekran dışı bir arabelleğe kaydedilir. Sonraki kareler için böyle bir birleştirme işlemi, tek tek talimatları yürütmekten daha hızlıdır ancak ölçeklendirme veya döndürme gibi dönüşümler uygulandığında bit eşlem olarak davranır.
Dönüşümler
Modifier.graphicsLayer, çizim talimatları için izolasyon sağlar;
örneğin, Modifier.graphicsLayer kullanılarak çeşitli dönüşümler uygulanabilir. Bunlar, çizim lambdasını yeniden yürütmeye gerek kalmadan animasyonlu hale getirilebilir veya değiştirilebilir.
Modifier.graphicsLayer yalnızca çizim aşamasını etkilediğinden, birleştirilebilir öğenizin ölçülen boyutunu veya yerleşimini değiştirmez. Bu, düzen sınırlarının dışında çizim yaparsa composable'ınızın diğerleriyle çakışabileceği anlamına gelir.
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ı, 0.5f değeri ise boyutun yarısı olduğunu gösterir.
Image( painter = painterResource(id = R.drawable.sunset), contentDescription = "Sunset", modifier = Modifier .graphicsLayer { this.scaleX = 1.2f this.scaleY = 0.8f } )
Çeviri
translationX ve translationY, graphicsLayer ile değiştirilebilir.
translationX, composable'ı sola veya sağa hareket ettirir. 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() } )
Döndürme
rotationX seçeneğini yatay döndürme, rotationY seçeneğini dikey döndürme ve rotationZ seçeneğini Z ekseninde döndürme (standart döndürme) olarak ayarlayın. Bu değer, derece (0-360) olarak belirtilir.
Image( painter = painterResource(id = R.drawable.sunset), contentDescription = "Sunset", modifier = Modifier .graphicsLayer { this.rotationX = 90f this.rotationY = 275f this.rotationZ = 180f } )
Kaynak
transformOrigin belirtilebilir. Ardından, dönüşümlerin gerçekleştiği nokta olarak kullanılır. Şimdiye kadarki tüm örneklerde TransformOrigin.Center kullanıldı. Bu karakter (0.5f, 0.5f) konumundadır. Başlangıç noktasını (0f, 0f) olarak belirtirseniz dönüşümler, birleştirilebilir öğenin sol üst köşesinden başlar.
Kaynak noktayı rotationZ dönüşümüyle değiştirirseniz öğenin, birleştirilebilir öğenin sol üst kısmı etrafında 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 } )
Kırpma ve Şekil
Şekil, clip = true olduğunda içeriğin kırpıldığı ana hattı belirtir. Bu örnekte, iki kutuyu iki farklı klip içerecek şekilde ayarlıyoruz. Biri graphicsLayer klip değişkenini, diğeri ise kullanışlı sarmalayıcı Modifier.clip'yı kullanıyor.
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 (metin, "Hello Compose" diyor) daire şekline kırpılır:
Ardından üstteki pembe daireye translationY uygularsanız Composable'ın sınırlarının aynı kaldığını ancak dairenin alttaki dairenin altında (ve sınırlarının dışında) çizildiğini görürsünüz.
Birleştirilebilir öğeyi çizildiği bölgeye kırpmak için değiştirici zincirinin başına başka bir Modifier.clip(RectangleShape) ekleyebilirsiniz. İçerik daha sonra orijinal sınırlar 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)) ) }
Alfa
Modifier.graphicsLayer, katmanın tamamı için alpha (opaklık) ayarlamak üzere kullanılabilir. 1.0f tamamen opak, 0.0f ise görünmezdir.
Image( painter = painterResource(id = R.drawable.sunset), contentDescription = "clock", modifier = Modifier .graphicsLayer { this.alpha = 0.5f } )
Birleştirme stratejisi
Alfa ve şeffaflıkla çalışmak her zaman tek bir alfa değerini değiştirmek kadar kolay olmayabilir. Alfa değerini değiştirmenin yanı sıra graphicsLayer üzerinde CompositingStrategy ayarlama seçeneği de vardır. Bir CompositingStrategy, composable'ın içeriğinin ekranda zaten çizilmiş olan diğer içeriklerle nasıl birleştirileceğini (bir araya getirileceğini) belirler.
Farklı stratejiler şunlardır:
Otomatik (varsayılan)
Birleştirme stratejisi, graphicsLayer parametrelerin geri kalanı tarafından belirlenir. Alfa değeri 1,0f'den küçükse veya RenderEffect ayarlanmışsa katmanı ekran dışı bir arabelleğe işler. Alfa değeri 1f'den küçük olduğunda, içerikleri oluşturmak için otomatik olarak bir birleştirme katmanı oluşturulur ve ardından bu ekran dışı arabellek, ilgili alfa değeriyle hedefte çizilir. RenderEffect veya kaydırma sonu ayarlandığında, CompositingStrategy ayarından bağımsız olarak içerik her zaman ekran dışı bir arabelleğe oluşturulur.
Ekran dışında
Birleştirilebilir öğelerin içerikleri, hedefte oluşturulmadan önce her zaman ekran dışı bir doku veya bit eşleme olarak rasterleştirilir. Bu, içeriği maskelemek için BlendMode işlemlerini uygulamak ve karmaşık çizim talimatlarını oluştururken performansı artırmak için kullanışlıdır.
CompositingStrategy.Offscreen kullanımına örnek olarak BlendModes verilebilir.
Aşağıdaki örnekte, Image kullanarak çizim komutu vererek BlendMode.Clear birleştirilebilir öğesinin bazı bölümlerini kaldırmak istediğinizi varsayalım. compositingStrategy değerini CompositingStrategy.Offscreen olarak ayarlamazsanız BlendMode, arka plandaki tüm içeriklerle etkileşime girer.
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(