Fırça: Renk geçişleri ve gölgelendiriciler

Oluşturma'daki Brush, bir nesnenin ekranda nasıl çizildiğini tanımlar: Çizim alanında çizilen renkleri (ör. daire, kare, yol) belirler. Çizim için yararlı birkaç yerleşik Fırça vardır. LinearGradient, RadialGradient veya bir plain gibi SolidColor fırçası.

Fırçalar Modifier.background(), TextStyle veya DrawScope boyama stilini içeriğe uygulamak için çağrılar çizer biraz farklıdır.

Örneğin, DrawScope'te daire çizmek için yatay degrade fırçası uygulanabilir:

val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue))
Canvas(
    modifier = Modifier.size(200.dp),
    onDraw = {
        drawCircle(brush)
    }
)
Yatay degrade ile çizilmiş daire
Şekil 1: Yatay Renk Geçişi ile Çizilen Daire

Gradyan fırçaları

Farklı tasarımlar elde etmek için kullanabileceğiniz birçok yerleşik gradyan fırçası hoş geldiniz. Bu fırçalar, gradyan oluşturmak istediğiniz renklerin listesini belirtmenize olanak tanır.

Kullanılabilen gradyan fırçalarının listesi ve karşılık gelen çıkışları:

Gradyan Fırça Türü Çıkış
Brush.horizontalGradient(colorList) Yatay gradyan
Brush.linearGradient(colorList) Doğrusal Gradyan
Brush.verticalGradient(colorList) Dikey Gradyan
Brush.sweepGradient(colorList)
Not: Renkler arasında yumuşak bir geçiş elde etmek için son rengi başlangıç rengine ayarlayın.
Kaydırma gradyanı
Brush.radialGradient(colorList) Radyal Gradyan

colorStops ile renklerin dağılımını değiştirin

Renklerin degradede nasıl görüneceğini özelleştirmek için her birinin colorStops değerini değiştirebilirsiniz. colorStops, 0 ile 1 arasında bir kesirli sayı olarak belirtilmelidir. 1'den büyük değerler, bu renklerin degradenin bir parçası olarak oluşturulmamasına neden olur.

Renk duraklarını, bir rengin daha az veya daha fazla olması gibi farklı miktarlara sahip olacak şekilde yapılandırabilirsiniz:

val colorStops = arrayOf(
    0.0f to Color.Yellow,
    0.2f to Color.Red,
    1f to Color.Blue
)
Box(
    modifier = Modifier
        .requiredSize(200.dp)
        .background(Brush.horizontalGradient(colorStops = colorStops))
)

Renkler, colorStop çiftinde tanımlandığı gibi sağlanan ofsette dağıtılır ve kırmızı ve maviden daha az sarı olur.

Farklı renk duraklarıyla yapılandırılmış fırça
Şekil 2: Farklı renk noktalarıyla yapılandırılmış fırça

Deseni TileMode ile tekrarla

Her degrade fırçanın üzerine TileMode ayarlama seçeneği vardır. Yapamazsınız renk geçişi için bir başlangıç ve bitiş ayarlamadıysanız TileMode varsayılan olarak tüm alanı dolduracaktır. TileMode, yalnızca renk geçişini döşer alanın boyutu Fırça boyutundan büyükse.

endX değeri yüksek olduğundan, aşağıdaki kod gradyan kalıbını 4 kez tekrarlayacaktır: 50.dp olarak ve boyut 200.dp olarak ayarlandı:

val listColors = listOf(Color.Yellow, Color.Red, Color.Blue)
val tileSize = with(LocalDensity.current) {
    50.dp.toPx()
}
Box(
    modifier = Modifier
        .requiredSize(200.dp)
        .background(
            Brush.horizontalGradient(
                listColors,
                endX = tileSize,
                tileMode = TileMode.Repeated
            )
        )
)

Aşağıda, farklı karo modlarının yukarıdaki HorizontalGradient örneğinde ne yaptığını gösteren bir tablo verilmiştir:

TileMode Çıkış
TileMode.Repeated: Kenar, son renkten ilk renge doğru tekrarlanır. TileMode Tekrarlanan
TileMode.Mirror: Kenar, son renkten başa doğru yansıtılır. Fayans Modu Aynası
TileMode.Clamp: Kenar, son renge sabitlenmiş. Ardından bölgenin geri kalanına en yakın renge boyanır. Karo Modu Sıkıştırma
TileMode.Decal: Yalnızca sınırların boyutuna kadar oluşturun. TileMode.Decal, orijinal sınırların dışındaki içeriği örneklemek için şeffaf siyahtan yararlanırken TileMode.Clamp kenar rengini örnekler. Karo Modu Çıkartması

TileMode, diğer yön gradyanlarında da benzer şekilde çalışır. tekrarın gerçekleştiği yöndür.

Fırça Boyutunu Değiştir

Fırçanızın çizileceği alanın boyutunu biliyorsanız endX öğesini, yukarıdaki TileMode bölümünde gördüğümüz gibi ayarlayın. Bir DrawScope ise alanın boyutunu öğrenmek için size özelliğini kullanabilirsiniz.

Çizim alanınızın boyutunu bilmiyorsanız (örneğin Brush, Metin'e atandı) Shader ve şu boyutta bir boyut kullanabilirsiniz: createShader işlevindeki çizim alanı.

Bu örnekte, deseni 4 kez tekrarlamak için boyutu 4'e bölün:

val listColors = listOf(Color.Yellow, Color.Red, Color.Blue)
val customBrush = remember {
    object : ShaderBrush() {
        override fun createShader(size: Size): Shader {
            return LinearGradientShader(
                colors = listColors,
                from = Offset.Zero,
                to = Offset(size.width / 4f, 0f),
                tileMode = TileMode.Mirror
            )
        }
    }
}
Box(
    modifier = Modifier
        .requiredSize(200.dp)
        .background(customBrush)
)

Gölgelendirici boyutunun 4'e bölünmesi
Şekil 3: Gölgelendirici boyutu 4'e bölünmüş

Ayrıca, dairesel renk gibi başka bir renk geçişinin fırça boyutunu da değiştirebilirsiniz. renk geçişlerini kullanabilirsiniz. Boyut ve merkez belirtmezseniz gradyan, DrawScope öğesinin tüm sınırlarını kaplar ve radyal gradyanın merkezi varsayılan olarak DrawScope sınırlarının ortasına yerleştirilir. Bu durumda, radyal gradyanın merkezi daha küçük boyutun (genişlik veya yükseklik) merkezi olarak görünür:

Box(
    modifier = Modifier
        .fillMaxSize()
        .background(
            Brush.radialGradient(
                listOf(Color(0xFF2be4dc), Color(0xFF243484))
            )
        )
)

Boyut değişikliği yapılmayan dairesel gradyan ayarı
Şekil 4: Boyut değişiklikleri olmadan Dairesel Gradyan grubu

Dairesel gradyan, yarıçap boyutunu maksimum boyuta ayarlayacak şekilde değiştirildiğinde daha iyi bir dairesel gradyan efekti oluşturduğunu görebilirsiniz:

val largeRadialGradient = object : ShaderBrush() {
    override fun createShader(size: Size): Shader {
        val biggerDimension = maxOf(size.height, size.width)
        return RadialGradientShader(
            colors = listOf(Color(0xFF2be4dc), Color(0xFF243484)),
            center = size.center,
            radius = biggerDimension / 2f,
            colorStops = listOf(0f, 0.95f)
        )
    }
}

Box(
    modifier = Modifier
        .fillMaxSize()
        .background(largeRadialGradient)
)

Alanın boyutuna bağlı olarak dairesel gradyanda daha büyük yarıçap
Şekil 5: Alanın boyutuna bağlı olarak radyal gradyanda daha büyük yarıçap

Gölgelendiricinin oluşturulmasına iletilen gerçek boyutun, çağrıldığı yerden belirlendiğini belirtmek gerekir. Varsayılan olarak Brush, boyut Brush'ün son oluşturulmasından farklıysa veya gölgelendiricinin oluşturulmasında kullanılan bir durum nesnesi değiştiyse Shader'ünü dahili olarak yeniden ayarlar.

Aşağıdaki kod, gölgelendiriciyi farklı boyutlarla üç farklı kez oluşturur bir boyut ekleyin:

val colorStops = arrayOf(
    0.0f to Color.Yellow,
    0.2f to Color.Red,
    1f to Color.Blue
)
val brush = Brush.horizontalGradient(colorStops = colorStops)
Box(
    modifier = Modifier
        .requiredSize(200.dp)
        .drawBehind {
            drawRect(brush = brush) // will allocate a shader to occupy the 200 x 200 dp drawing area
            inset(10f) {
      /* Will allocate a shader to occupy the 180 x 180 dp drawing area as the
       inset scope reduces the drawing  area by 10 pixels on the left, top, right,
      bottom sides */
                drawRect(brush = brush)
                inset(5f) {
        /* will allocate a shader to occupy the 170 x 170 dp drawing area as the
         inset scope reduces the  drawing area by 5 pixels on the left, top,
         right, bottom sides */
                    drawRect(brush = brush)
                }
            }
        }
)

Bir resmi fırça olarak kullanma

ImageBitmap'i Brush olarak kullanmak için resmi ImageBitmap olarak yükleyin ve ImageShader fırçası oluşturun:

val imageBrush =
    ShaderBrush(ImageShader(ImageBitmap.imageResource(id = R.drawable.dog)))

// Use ImageShader Brush with background
Box(
    modifier = Modifier
        .requiredSize(200.dp)
        .background(imageBrush)
)

// Use ImageShader Brush with TextStyle
Text(
    text = "Hello Android!",
    style = TextStyle(
        brush = imageBrush,
        fontWeight = FontWeight.ExtraBold,
        fontSize = 36.sp
    )
)

// Use ImageShader Brush with DrawScope#drawCircle()
Canvas(onDraw = {
    drawCircle(imageBrush)
}, modifier = Modifier.size(200.dp))

Fırça, birkaç farklı çizim türüne uygulanır: arka plan, metin ve kanvas. Bu işlem şu sonucu verir:

Farklı şekillerde kullanılan ImageShader Fırçası
Şekil 6: Arka plan, metin ve daire çizmek için ImageShader fırçasını kullanma

Metnin artık pikselleri boyamak için ImageBitmap kullanılarak da oluşturulduğunu unutmayın.

Gelişmiş örnek: Özel fırça

AGSL RuntimeShader fırçası

AGSL, GLSL Gölgelendirici özelliklerinin bir alt kümesini sunar. Gölgelendirici AGSL ile yazılmış ve Compose'da Fırça ile kullanılmış.

Gölgelendirici fırçası oluşturmak için önce Gölgelendirici'yi AGSL gölgelendirici dizesi olarak tanımlayın:

@Language("AGSL")
val CUSTOM_SHADER = """
    uniform float2 resolution;
    layout(color) uniform half4 color;
    layout(color) uniform half4 color2;

    half4 main(in float2 fragCoord) {
        float2 uv = fragCoord/resolution.xy;

        float mixValue = distance(uv, vec2(0, 1));
        return mix(color, color2, mixValue);
    }
""".trimIndent()

Yukarıdaki gölgelendirici iki giriş rengi alır, çizim alanının sol alt kısmına (vec2(0, 1)) olan mesafeyi hesaplar ve mesafeye göre iki renk arasında mix yapar. Bu işlem, renk geçişi efekti oluşturur.

Ardından, Gölgelendirici Fırçası'nı oluşturun ve resolution için üniformaları ayarlayın - boyut ve giriş olarak kullanmak istediğiniz color ve color2 için özel renk geçişiniz:

val Coral = Color(0xFFF3A397)
val LightYellow = Color(0xFFF8EE94)

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Composable
@Preview
fun ShaderBrushExample() {
    Box(
        modifier = Modifier
            .drawWithCache {
                val shader = RuntimeShader(CUSTOM_SHADER)
                val shaderBrush = ShaderBrush(shader)
                shader.setFloatUniform("resolution", size.width, size.height)
                onDrawBehind {
                    shader.setColorUniform(
                        "color",
                        android.graphics.Color.valueOf(
                            LightYellow.red, LightYellow.green,
                            LightYellow
                                .blue,
                            LightYellow.alpha
                        )
                    )
                    shader.setColorUniform(
                        "color2",
                        android.graphics.Color.valueOf(
                            Coral.red,
                            Coral.green,
                            Coral.blue,
                            Coral.alpha
                        )
                    )
                    drawRect(shaderBrush)
                }
            }
            .fillMaxWidth()
            .height(200.dp)
    )
}

Bu komutu çalıştırdığınızda ekranda aşağıdakilerin oluşturulduğunu görebilirsiniz:

Compose'da çalışan özel AGSL gölgelendirici
Şekil 7: Compose'da çalışan özel AGSL Gölgelendirici

Gölgelendiricilerle, renk geçişlerinden çok daha fazlasını yapabileceğinizi belirtmekte fayda var. çünkü hepsi matematik tabanlı hesaplamalarda. AGSL hakkında daha fazla bilgi için AGSL belgeleri.

Ek kaynaklar

Oluşturma özelliğinde Fırça kullanımıyla ilgili daha fazla örnek için aşağıdaki kaynaklara göz atın: