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ı olan birkaç yerleşik fırça (ör. LinearGradient, RadialGradient veya düz SolidColor fırça) vardır.

Fırçalar, çizim stilini çizilen içeriğe uygulamak için Modifier.background(), TextStyle veya DrawScope çizim çağrılarıyla kullanılabilir.

Örneğin, DrawScope uygulamasında daire çizmek için yatay bir gradyan 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ı degrade efektleri elde etmek için kullanılabilecek birçok yerleşik degrade fırçası vardır. 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.
Süpürme 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 kesir olarak belirtilmelidir. 1'den büyük değerler, bu renklerin degradenin bir parçası olarak oluşturulmamasına neden olur.

Renk duraklarını, daha az veya daha fazla renk gibi farklı miktarlarda 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 duraklarıyla yapılandırılmış fırça

TileMode ile bir kalıbı tekrarlama

Her gradyan fırçasının üzerinde bir TileMode ayarlama seçeneği vardır. Eğim için bir başlangıç ve bitiş noktası ayarlamadıysanız TileMode simgesini fark etmeyebilirsiniz. Varsayılan olarak tüm alanı doldurur. TileMode, yalnızca alanın boyutu fırça boyutundan büyükse degradeyi karolar.

Aşağıdaki kodda, endX 50.dp olarak ve boyut 200.dp olarak ayarlandığından degrade deseni 4 kez tekrarlanır:

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 ilk renge doğru yansıtılır. Fayans Modu Aynası
TileMode.Clamp: Kenar, son renge sabitlenir. Ardından, bölgenin geri kalanı için en yakın rengi boyar. Fayans modu kelepçesi
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önlü gradyanlar için benzer şekilde çalışır. Tek fark, tekrarın gerçekleştiği yöndür.

Fırça boyutunu değiştirme

Fırçanızın çizileceği alanın boyutunu biliyorsanız yukarıdaki TileMode bölümünde gördüğümüz şekilde endX blokunu ayarlayabilirsiniz. Bir DrawScope içindeyseniz alanın boyutunu öğrenmek için size mülkünü kullanabilirsiniz.

Çizim alanınızın boyutunu bilmiyorsanız (örneğin, Brush, Metin'e atanmışsa) Shader öğesini genişletebilir ve createShader işlevinde çizim alanının boyutundan yararlanabilirsiniz.

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 boyutunun 4'e bölünmesi

Ayrıca, dairesel renk geçişleri gibi diğer renk geçişlerinin fırça boyutunu da değiştirebilirsiniz. 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ılmadan ayarlanan dairesel gradyan
Ş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 boyutuna bağlı olarak dairesel gradyanda daha büyük yarıçap
Şekil 5: Alanın boyutuna bağlı olarak dairesel gradyan üzerinde daha büyük yarıçap

Gölgelendiricinin oluşturulmasına iletilen gerçek boyutun, çağrıldığı yerden belirlendiğini belirtmekte fayda var. 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, çizim alanının boyutu değiştikçe gölgelendiriciyi üç farklı boyutta üç kez oluşturur:

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 metin için pikselleri boyamak için ImageBitmap kullanılarak da oluşturulduğuna dikkat edin.

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

AGSL RuntimeShader fırçası

AGSL, GLSL gölgelendirici özelliklerinin bir alt kümesini sunar. Gölgelendiriciler AGSL ile yazılabilir ve Compose'da fırçayla kullanılabilir.

Bir gölgelendirici fırçası oluşturmak için önce gölgelendiriciyi 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ından (vec2(0, 1)) mesafeyi hesaplar ve mesafeye bağlı olarak iki renk arasında bir mix yapar. Bu şekilde bir gradyan efekti oluşturulur.

Ardından, Gölgelendirici Fırçasını oluşturun ve resolution için üniformaları (çizim alanının boyutu) ve özel renk geçişinizde giriş olarak kullanmak istediğiniz color ile color2'yi ayarlayın:

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

Tümüyle matematik tabanlı hesaplamalar olduğundan gölgelendiricilerle yalnızca gradyanlardan çok daha fazlasını yapabileceğinizi unutmayın. AGSL hakkında daha fazla bilgi için AGSL dokümanlarına göz atın.

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: