Compose'da Canvas
composable'ın yanı sıra kullanışlı birkaç grafik bulunur
Özel içerik çizimine yardımcı olan Modifiers
. Bu değiştiriciler,
çünkü tüm composable'lara uygulanabilir.
Çizim değiştiricileri
Tüm çizim komutları, Oluşturma'da bir çizim değiştiriciyle yapılır. Her biri 100'den az gösterim alan Oluşturma'daki üç ana çizim değiştiricisi:
Çizimin temel değiştiricisi drawWithContent
. Burada
özel çizim sırası ve içindeki çizim komutlarını
kullanabilirsiniz. drawBehind
, aşağıdaki özelliklere sahip drawWithContent
için uygun bir sarmalayıcıdır:
composable'ın içeriğinin arkasına ayarlanan çizim sırası. drawWithCache
.
içinden onDrawBehind
veya onDrawWithContent
yöntemini çağırır ve
nesneleri önbelleğe alma mekanizmasıdır.
Modifier.drawWithContent
: Çizim sırasını seçin
Modifier.drawWithContent
şunları yapmanıza olanak tanır:
öncesinde veya sonrasında DrawScope
işlemlerini yürütecek,
composable'dan bahsetmek istiyorum. Mevcut içeriği oluşturmak için drawContent
işlevini çağırdığınızdan emin olun
composable. Bu değiştiriciyi kullanarak, rastgele bir seçim yapmak
İçeriğinizin özel çiziminizden önce veya sonra çizilmesini istiyorsanız
anlamına gelir.
Örneğin, içeriğinizin üzerinde dairesel bir renk geçişi kullanıcı arayüzünde bir el feneri anahtar deliği efekti oluşturmak için aşağıdaki adımları uygulayabilirsiniz:
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ına çizim yapma
Modifier.drawBehind
şunları yapmanıza olanak tanır:
Ekranda çizilen composable içeriğin arkasındaki DrawScope
işlemleri. Eğer
Canvas
uygulamasına göz atarken,
Modifier.drawBehind
etiketi için uygun bir sarmalayıcıdır.
Text
öğesinin arkasına yuvarlak bir dikdörtgen çizmek için:
Text( "Hello Compose!", modifier = Modifier .drawBehind { drawRoundRect( Color(0xFFBBAAEE), cornerRadius = CornerRadius(10.dp.toPx()) ) } .padding(4.dp) )
Aşağıdaki sonucu verir:
![Değiştirici.drawBehind kullanılarak çizilmiş bir metin ve bir arka plan](https://developer.android.com/static/develop/ui/compose/images/graphics/modifiers/modifier_draw_behind.png?authuser=5&hl=tr)
Modifier.drawWithCache
: Çizim nesnelerini çizme ve önbelleğe alma
Modifier.drawWithCache
, nesneleri korur
otomatik olarak oluşturulur. Boyutu büyük olduğu sürece nesneler önbelleğe alınır
aynı veya okunan durum nesnelerinin hiçbiri
değiştirildi. Bu değiştirici, hem çizim çağrılarının performansını iyileştirmek için
nesnelerin (örneğin: Brush, Shader, Path
vb.) yeniden tahsis edilmesi ihtiyacını önler
otomatik olarak oluşturulur.
Alternatif olarak, remember
öğesini kullanarak
kullanabilirsiniz. Ancak, her zaman erişim sahibi olmadığınızdan bu işlemi yapmak her zaman mümkün olmayabilir.
bileşime dahil edilir. drawWithCache
,
nesne yalnızca çizim için kullanılır.
Örneğin, Text
arkasına bir renk geçişi çizmek için şunu kullanarak bir Brush
oluşturursanız:
drawWithCache
, çizim alanının boyutuna kadar Brush
nesnesini önbelleğe alır
değişiklikler:
Text( "Hello Compose!", modifier = Modifier .drawWithCache { val brush = Brush.linearGradient( listOf( Color(0xFF9E82F0), Color(0xFF42A5F5) ) ) onDrawBehind { drawRoundRect( brush, cornerRadius = CornerRadius(10.dp.toPx()) ) } } )
![Brush nesnesinidrawWithCache ile önbelleğe alma](https://developer.android.com/static/develop/ui/compose/images/graphics/modifiers/modifier_draw_with_cache.png?authuser=5&hl=tr)
Grafik değiştiriciler
Modifier.graphicsLayer
: Dönüşüm işlemlerini composable'lara uygulama
Modifier.graphicsLayer
composable çizim içeriğini bir çizim katmanına dönüştüren bir değiştiricidir. CEVAP
katmanı, aşağıdakiler gibi birkaç farklı işlev sağlar:
- Çizim talimatları için izolasyon (
RenderNode
benzeri). Çizim bir katmanın parçası olarak yakalanan talimatların, uygulama kodunu yeniden çalıştırmadan ardışık düzeni oluşturur. - Bir tablodaki tüm çizim talimatlarına uygulanan katmanıdır.
- Kompozisyon özellikleri için pikselleştirme. Bir katman pikselleştirildiğinde, Çizim talimatları uygulanır ve çıktı, ekranın dışındaki bir ekrana arabellek. Sonraki kareler için böyle bir arabelleğin birleştirilmesi, ancak her bir işlem için bir bit eşlem olarak davranır ve dönüştürme veya döndürme gibi dönüşümler uygulanır.
Dönüşümler
Modifier.graphicsLayer
, çizim talimatları için yalıtım sağlar; şunun için:
Modifier.graphicsLayer
kullanılarak çeşitli dönüştürme işlemleri uygulanabilir.
Bunlar, çizimi yeniden yürütmeye gerek kalmadan canlandırılabilir veya değiştirilebilir
lambda.
Modifier.graphicsLayer
, cihazınızın ölçülen boyutunu veya yerleşimini değiştirmez.
composable, çünkü yalnızca çizim aşamasını etkiliyor. Bu, composable projenizin
Düzen sınırlarının dışında çizimle sonuçlanıyorsa diğerleriyle çakışabilir.
Bu değiştiriciyle aşağıdaki dönüşümler uygulanabilir:
Ölçek - boyutu artır
scaleX
ve scaleY
, yatay veya dikey içeriği büyütür ya da küçültür
girin. 1.0f
değeri, ölçekte değişiklik olmadığını gösterir. Bir değer
0.5f
, boyutun yarısı anlamına gelir.
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 taşır. translationY
,
aşağı yukarı composable'ı seçtim.
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
Yatay döndürmek için rotationX
simgesini, dikey olarak döndürmek için rotationY
değerine ayarlayın.
Z ekseninde döndürmek için rotationZ
tuşuna basın (standart döndürme). Bu değer belirtilir
(0-360) olarak ayarlanır.
Image( painter = painterResource(id = R.drawable.sunset), contentDescription = "Sunset", modifier = Modifier .graphicsLayer { this.rotationX = 90f this.rotationY = 275f this.rotationZ = 180f } )
Köken
transformOrigin
belirtilebilir. Daha sonra, bu hedefin
gerçekleşmesidir. Şimdiye kadarki tüm örneklerde
TransformOrigin.Center
, şurada: (0.5f, 0.5f)
. Kalkış noktasını
(0f, 0f)
, ardından dönüşümler sayfanın sol üst köşesinden başlar.
composable'dan bahsetmek istiyorum.
Kaynağı rotationZ
dönüşümüyle değiştirirseniz
öğe, composable'ın sol üst etrafında döner:
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 } )
Klip ve şekil
Şekil, clip = true
sırasında içeriğin klibinin ana hatlarını belirtir. İçinde
Bu örnekte, iki farklı klibe sahip olmak için iki kutu seçtik. Biri;
graphicsLayer
klip değişkeni, diğeri ise uygun sarmalayıcıyı kullanarak
Modifier.clip
.
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 ("Merhaba Oluştur" yazan metin) şu şekilde kırpılır: daire şekli:
![Klip, Box'taki composable'a uygulandı](https://developer.android.com/static/develop/ui/compose/images/graphics/modifiers/clip_applied.png?authuser=5&hl=tr)
Daha sonra üstteki pembe daireye bir translationY
uygularsanız sınırların
Üçgen tarafından yapılabilir.
daire (ve sınırları dışında) üzerinde çalışır.
![Klip, çeviriY ve dış çizgi için kırmızı kenarlık uygulandı](https://developer.android.com/static/develop/ui/compose/images/graphics/modifiers/clip_applied_red_border.png?authuser=5&hl=tr)
composable'ı çizildiği bölgeye göre klip oluşturmak için başka bir öğe ekleyebilirsiniz
Değiştirici zincirinin başında Modifier.clip(RectangleShape)
. İçerik
orijinal sınırların 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)) ) }
![Grafik Katmanı dönüşümünün üzerine klip uygulandı](https://developer.android.com/static/develop/ui/compose/images/graphics/modifiers/clip_applied_everything.png?authuser=5&hl=tr)
Alfa
Modifier.graphicsLayer
, tamamı için alpha
(opaklık) ayarlamak üzere kullanılabilir
katmanıdır. 1.0f
tamamen opak ve 0.0f
görünmez.
Image( painter = painterResource(id = R.drawable.sunset), contentDescription = "clock", modifier = Modifier .graphicsLayer { this.alpha = 0.5f } )
![Alfa uygulanmış resim](https://developer.android.com/static/develop/ui/compose/images/graphics/modifiers/image_alpha.png?authuser=5&hl=tr)
Birleştirme stratejisi
Alfa sürümü ve şeffaflıkla çalışmak, tek bir
veri deneyimini sağlamak kadar kolay olmayabilir.
alfa değeri. Bir alfa sürümünü değiştirmenin yanı sıra,
graphicsLayer
cihazda CompositingStrategy
. CompositingStrategy
,
composable'ın içeriği, composable'ın diğer
zaten ekranda çizilir.
Farklı stratejiler şunlardır:
Otomatik (varsayılan)
Birleştirme stratejisi, graphicsLayer
parametreleridir. Alfa, şundan küçükse katmanı ekran dışı bir arabellekte oluşturur:
1.0f veya RenderEffect
olarak ayarlanmıştır. Alfa 1f'den düşük olduğunda
birleştirme katmanı otomatik olarak oluşturulur.
bu ekran dışı arabelleği ilgili alfa ile hedefe yönlendirir. Bir
RenderEffect
veya üzerine kaydırma yapıldığında içerik her zaman ekran dışı olarak oluşturulur
CompositingStrategy
grubundan bağımsız olarak arabelleğe alınır.
Ekran dışı
composable'ın içeriği her zaman ekran dışı olacak şekilde pikselleştiriliyor
doku veya bit eşlem oluşturun. Bu, özellikle
içeriği maskelemek ve performansı artırmak için BlendMode
işlemleri
bir dizi çizim talimatını oluşturmamıza yardımcı oluyor.
BlendModes
, CompositingStrategy.Offscreen
kullanımına örnek olarak verilebilir. Aşağıdaki örneğe göz atalım.
Image
composable'ın bazı bölümlerini kaldırmak istediğinizi varsayalım. Bunun için
BlendMode.Clear
kullanır. compositingStrategy
özelliğini
CompositingStrategy.Offscreen
, BlendMode
tüm içeriklerle etkileşimde bulunur
dokunun.
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( Rect( topLeft = Offset.Zero, bottomRight = Offset(size.width, size.height) ) ) onDrawWithContent { clipPath(path) { // this draws the actual image - if you don't call drawContent, it wont // render anything this@onDrawWithContent.drawContent() } val dotSize = size.width / 8f // Clip a white border for the content drawCircle( Color.Black, radius = dotSize, center = Offset( x = size.width - dotSize, y = size.height - dotSize ), blendMode = BlendMode.Clear ) // draw the red circle indication drawCircle( Color(0xFFEF5350), radius = dotSize * 0.8f, center = Offset( x = size.width - dotSize, y = size.height - dotSize ) ) } } )
CompositingStrategy
, Offscreen
değerine ayarlandığında ekran dışı bir görüntü oluşturulur
dokusuyla (BlendMode
yalnızca
. Daha sonra, videoyu önceden
zaten çizilmiş olan içeriği etkilemez.
![Daire şeklinde bir gösterimin gösterildiği ve BlendMode.Clear uygulamasının içinde bulunan Değiştirici.drawWithContent](https://developer.android.com/static/develop/ui/compose/images/graphics/modifiers/complex_modifier_example_drawWithCache_background.png?authuser=5&hl=tr)
CompositingStrategy.Offscreen
kullanmadıysanız
BlendMode.Clear
, hatanın ne olduğundan bağımsız olarak hedefteki tüm pikselleri temizler
zaten ayarlanmış. Pencerenin oluşturma arabelleği (siyah) görünür durumda kalır. Çoğu
alfa içeren BlendModes
,
arabelleğe alma’yı tıklayın. Kırmızı daire göstergesinin etrafındaki siyah halkaya dikkat edin:
![Bir resimde BlendMode.Clear ve Compositingstratejisi yok olarak daire şeklinde bir işaret gösteren Modifier.drawWithContent](https://developer.android.com/static/develop/ui/compose/images/graphics/modifiers/blendmode_without_compositing_strategy.png?authuser=5&hl=tr)
Bunu biraz daha iyi anlamak için: Uygulamanın yarı saydam bir penceresi olsaydı
ve CompositingStrategy.Offscreen
kullanmadıysanız
BlendMode
uygulamanın tamamı ile etkileşim kurar. Bu, gösterilecek tüm pikselleri temizler
aşağıdaki örnekte olduğu gibi, altındaki uygulama veya duvar kağıdı:
![CompositingPolicy ayarlanmamış ve BlendMode.Clear adlı uygulama, saydam pencere arka planına sahip bir uygulamayla kullanılıyor. Pembe duvar kağıdı, kırmızı durum dairesinin çevresinde gösterilir.](https://developer.android.com/static/develop/ui/compose/images/graphics/modifiers/compositing_strategy_punch_through_to_wallpaper.png?authuser=5&hl=tr)
Şunu belirtmek gerekir ki, CompositingStrategy.Offscreen
kullanırken ekran dışında
boyutundaki bir doku oluşturulur ve tekrar
tıklayın. Bu stratejiyle yapılan çizim komutları, varsayılan olarak
bu bölgeye kırpılıyor. Aşağıdaki kod snippet'i,
ekran dışı dokuları kullanmaya geçiş yapma:
@Composable fun CompositingStrategyExamples() { Column( modifier = Modifier .fillMaxSize() .wrapContentSize(Alignment.Center) ) { /** Does not clip content even with a graphics layer usage here. By default, graphicsLayer does not allocate + rasterize content into a separate layer but instead is used for isolation. That is draw invalidations made outside of this graphicsLayer will not re-record the drawing instructions in this composable as they have not changed **/ Canvas( modifier = Modifier .graphicsLayer() .size(100.dp) // Note size of 100 dp here .border(2.dp, color = Color.Blue) ) { // ... and drawing a size of 200 dp here outside the bounds drawRect(color = Color.Magenta, size = Size(200.dp.toPx(), 200.dp.toPx())) } Spacer(modifier = Modifier.size(300.dp)) /** Clips content as alpha usage here creates an offscreen buffer to rasterize content into first then draws to the original destination **/ Canvas( modifier = Modifier // force to an offscreen buffer .graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen) .size(100.dp) // Note size of 100 dp here .border(2.dp, color = Color.Blue) ) { /** ... and drawing a size of 200 dp. However, because of the CompositingStrategy.Offscreen usage above, the content gets clipped **/ drawRect(color = Color.Red, size = Size(200.dp.toPx(), 200.dp.toPx())) } } }
![Compositingstrateji.Auto ve Compositingstratejisi.Offscreen, otomatik oynatmanın mümkün olmadığı bölgeye yönelik ekran dışı klipler](https://developer.android.com/static/develop/ui/compose/images/graphics/modifiers/graphics_compositing_strategy.png?authuser=5&hl=tr)
ModulateAlpha
Bu beste stratejisi, çizimlerin her biri için alfayı değiştirir.
graphicsLayer
içinde kaydedildi. Herhangi bir
RenderEffect
ayarlanmadığı sürece alfa 1, 0f'nin altında alfa için ekran dışı arabellek.Böylece
alfa oluşturma için daha verimli
olduğunu gördük. Ancak farklı sonuçlar verebilir
farklı olabilir. İçeriğin önceden bilindiği kullanım alanları için
olduğundan daha iyi performans sağlayabilir.
alfa değerleri 1'den küçük olan CompositingStrategy.Auto
.
Farklı beste stratejilerine ilişkin başka bir örnek aşağıda verilmiştir:
alfa öğelerini composable'ların farklı bölümlerine eklemek ve Modulate
uygulamak
strateji:
@Preview @Composable fun CompositingStratgey_ModulateAlpha() { Column( modifier = Modifier .fillMaxSize() .padding(32.dp) ) { // Base drawing, no alpha applied Canvas( modifier = Modifier.size(200.dp) ) { drawSquares() } Spacer(modifier = Modifier.size(36.dp)) // Alpha 0.5f applied to whole composable Canvas(modifier = Modifier .size(200.dp) .graphicsLayer { alpha = 0.5f }) { drawSquares() } Spacer(modifier = Modifier.size(36.dp)) // 0.75f alpha applied to each draw call when using ModulateAlpha Canvas(modifier = Modifier .size(200.dp) .graphicsLayer { compositingStrategy = CompositingStrategy.ModulateAlpha alpha = 0.75f }) { drawSquares() } } } private fun DrawScope.drawSquares() { val size = Size(100.dp.toPx(), 100.dp.toPx()) drawRect(color = Red, size = size) drawRect( color = Purple, size = size, topLeft = Offset(size.width / 4f, size.height / 4f) ) drawRect( color = Yellow, size = size, topLeft = Offset(size.width / 4f * 2f, size.height / 4f * 2f) ) } val Purple = Color(0xFF7E57C2) val Yellow = Color(0xFFFFCA28) val Red = Color(0xFFEF5350)
![ModlateAlpha, alfa kümesini her çizim komutuna uygular](https://developer.android.com/static/develop/ui/compose/images/graphics/modifiers/modulate_alpha.png?authuser=5&hl=tr)
Bir composable'ın içeriğini bit eşlem olarak yazma
Yaygın kullanım alanlarından biri, bir composable'dan Bitmap
oluşturmaktır. Kopyalamak için
içeriğini bir Bitmap
olarak ayarlamak için aşağıdaki kodu kullanarak bir GraphicsLayer
oluşturun:
rememberGraphicsLayer()
.
Çizim komutlarını drawWithContent()
komutunu kullanarak yeni katmana yönlendirin ve
graphicsLayer.record{}
. Daha sonra, aşağıdakini kullanarak katmanı görünür tuvalde çizin:
drawLayer
:
val coroutineScope = rememberCoroutineScope() val graphicsLayer = rememberGraphicsLayer() Box( modifier = Modifier .drawWithContent { // call record to capture the content in the graphics layer graphicsLayer.record { // draw the contents of the composable into the graphics layer this@drawWithContent.drawContent() } // draw the graphics layer on the visible canvas drawLayer(graphicsLayer) } .clickable { coroutineScope.launch { val bitmap = graphicsLayer.toImageBitmap() // do something with the newly acquired bitmap } } .background(Color.White) ) { Text("Hello Android", fontSize = 26.sp) }
Bit eşlemi diske kaydedebilir ve paylaşabilirsiniz. Daha fazla bilgi için örnek snippet'i inceleyin. Denemeden önce cihaz üzerindeki izinleri kontrol ettiğinizden emin olun diske kaydedin.
Özel çizim değiştirici
Kendi özel değiştiricinizi oluşturmak için DrawModifier
arayüzünü uygulayın. Bu
size, gösterilenle aynı ContentDrawScope
erişimi sunar.
(Modifier.drawWithContent()
kullanırken) Ardından, yaygın kullanılan çizimleri
özel çizim değiştiricilerine dönüştürerek kodu temizlemek ve
uygun sarmalayıcılar; Örneğin, Modifier.background()
dönüşüm sağlamak için
DrawModifier
.
Örneğin, dikey olarak dönen bir Modifier
uygulamak istiyorsanız
aşağıdaki gibi bir şablon oluşturabilirsiniz:
class FlippedModifier : DrawModifier { override fun ContentDrawScope.draw() { scale(1f, -1f) { this@draw.drawContent() } } } fun Modifier.flipped() = this.then(FlippedModifier())
Ardından, Text
tarihinde uygulanan ters çevrilmiş bu değiştiriciyi kullanın:
Text( "Hello Compose!", modifier = Modifier .flipped() )
![Metinde Özel Çevrilmiş Değiştirici](https://developer.android.com/static/develop/ui/compose/images/graphics/modifiers/modifier_flipped.png?authuser=5&hl=tr)
Ek kaynaklar
graphicsLayer
ve özel çizimin kullanıldığı daha fazla örnek için şuraya göz atın:
şu kaynakları inceleyin:
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir
- Compose'daki grafikler
- Bir resmi özelleştirme {:#customize-image}
- Jetpack Compose için Kotlin