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

Compose'daki Brush simgesi ekranda bir öğenin nasıl çizildiğini açıklar: çizim alanında çizilen renkleri belirler (ör. bir daire, kare, yol). Ç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 Modifier.background(), TextStyle veya DrawScope boyama stilini içeriğe uygulamak için çağrılar çizer biraz farklıdır.

Örneğin, arka planda bir daire çizmek için yatay bir gradyan fırçası DrawScope:

val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue))
Canvas(
    modifier = Modifier.size(200.dp),
    onDraw = {
        drawCircle(brush)
    }
)
Yatay Gradyan ile çizilmiş daire
Şekil 1: Yatay Gradyan ile çizilmiş 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, görmek istediğiniz renklerin listesini belirtmenize oluşturmak istiyorum.

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 renk geçişinde nasıl görüneceğini özelleştirmek için Her biri için colorStops değer. colorStops, kesir olarak belirtilmelidir. 0 ile 1 arasında olmalıdır. 1'den büyük değerler bu renklerin oluşturulmamasına neden olur olarak ayarlayabilirsiniz.

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 içinde tanımlandığı şekilde sağlanan ofsette dağıtılır sarı ve maviden daha az sarı olduğunu unutmayın.

Farklı renk noktaları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. 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 alanın boyutu fırça boyutundan büyükse degradeyi karolar.

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

Farklı karo modlarının Yukarıda HorizontalGradient örnek:

Döşeme Modu Çıkış
TileMode.Repeated: Kenar, son renkten başa doğru tekrarlanır. Parça Modu Tekrarlandı
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şturulur. TileMode.Decal, içeriği orijinal sınırların dışında örneklemek için şeffaf siyahtan yararlanırken, TileMode.Clamp kenar renginden örnekler alır. 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ş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, kalıbı 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ümü
Şekil 3: Gölgelendirici boyutunun 4'e bölünmesi

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 dairesel renk geçişinin ortadaki değer, daha küçük boyutun (genişlik veya yükseklik):

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

Boyut değişikliği olmadan Dairesel Renk Geçişi ayarı
Şekil 4: Boyut değişiklikleri olmadan Dairesel Gradyan grubu

Yarıçap boyutunu maksimum boyuta ayarlamak için dairesel renk geçişi 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: Dairesel gradyan üzerinde daha büyük yarıçap (Alanın boyutuna bağlı olarak)

Gölgelendiricinin oluşturulmasına iletilen gerçek boyutun, çağrıldığı yerden belirlendiğini belirtmek gerekir. Brush varsayılan olarak şunları yapar: boyutu öncekinden farklıysa Shader öğesinin dahili olarak yeniden ayrılmasını Brush öğesinin oluşturulması veya gölgelendirici oluşturulurken kullanılan bir durum nesnesi değiştirildi.

Aşağıdaki kod, gölgelendiriciyi farklı boyutlarla üç farklı kez oluşturur boyutunu değiştirme:

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 bir 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 metni boyamak için ImageBitmap kullanılarak da oluşturulduğuna dikkat edin. piksel cinsinden belirtin.

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çayla kullanılmış.

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 ve alttan mesafeyi hesaplar çizim alanının solunda (vec2(0, 1)) ve iki renk arasında mix yapar mesafeye göre değişir. Bu şekilde bir gradyan efekti oluşturulur.

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 dokümanlarına göz atın.

Ek kaynaklar

Oluşturma'da Fırça'yı kullanmayla ilgili daha fazla örnek için aşağıdaki kaynaklara göz atın: