Grafik değiştiriciler

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
}

Şekil 1: El feneri türü bir kullanıcı arayüzü deneyimi oluşturmak için Composable'ın üst kısmında kullanılan Modifier.drawWithContent.

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
Şekil 2: Değiştirici.drawBehind kullanılarak çizilen bir metin ve bir arka plan

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
Şekil 3: Fırça nesnesinidrawWithCache ile önbelleğe alma

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
        }
)

Şekil 4: composable'a uygulanan scaleX ve scaleY
Ç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()
        }
)

Şekil 5: Değiştirici.graphicsKatmanlar ile Resim'e çeviriX ve çeviriY uygulandı
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
        }
)

Şekil 6: Değiştirici.graphicsKatman tarafından Resim üzerinde ayarlanan rotasyonX, döndürmeY ve döndürmeZ
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
        }
)

Şekil 7: TransformOrigin 0f, 0f olarak ayarlandığında uygulanan döndürme

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ı
Şekil 8: Kutu, composable'a uygulanan klip

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ı
Şekil 9: Klip çevrilebilirY ve dış çizgi için kırmızı kenarlık uygulanmıştır

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ı
Şekil 10: Grafik Katmanı dönüşümünün üzerine klip uygulandı

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
Şekil 11: Alfa uygulanmış resim

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
Şekil 12: BlendMode.Clear and CompositingPolicy.Offscreen uygulama içinde daire şeklinde bir işaret gösteren bir resimde Modifier.drawWithContent

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
Şekil 13: BlendMode.Clear ve Compositingstratejisi ayarlanmamış dairesel bir gösterimin gösterildiği resimde, Modifier.drawWithContent

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.
Şekil 14: Compositingstratejisi ayarlanmamış ve BlendMode.Clear'ı şeffaf pencere arka planına sahip bir uygulamayla kullanma. Pembe duvar kağıdının, kırmızı durum dairesinin çevresinde nasıl gösterildiğine dikkat edin.

Ş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
Şekil 15: Compositingstrateji.Auto ve Compositingstratejisi. Offscreen: Ekran dışındaki klipler, otomatik oluşturulan bölge için devre dışıdır.
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
Şekil 16: ModlateAlpha, alfa grubunu her çizim komutuna uygular

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
Şekil 17: Metin Üzerinde Özel Ters Edilmiş Değiştirici

Ek kaynaklar

graphicsLayer ve özel çizimin kullanıldığı daha fazla örnek için şuraya göz atın: şu kaynakları inceleyin:

ziyaret edin. ziyaret edin.