Örgü gradyanları

Ağ geçişleri, 2D bir yama ızgarası kullanarak karmaşık, çok yönlü renk geçişleri oluşturur. Doğrusal veya dairesel renk geçişlerinin aksine, ağ renk geçişleri, renkleri 2D bir ızgara üzerinde sorunsuz bir şekilde birleştirir. Kullanıcı arayüzünüzde akıcı, organik veya çok noktalı arka planlar oluştururken birden fazla radialGradient veya linearGradient fırçayı üst üste koymak yerine ağ geçişleri kullanın.

Mevcut ağ geçiş noktalarının gösterildiği bir ağ geçişi örneği.
Şekil 1. Mevcut ağ geçiş noktalarının gösterildiği bir ağ geçişi örneği.

Temel kavramlar

Örgü geçişi oluşturmak için ızgara boyutlarını, köşeleri ve noktalar arasındaki renk geçişlerini tanımlayın:

  • Izgara boyutları: Ağ, dikey ve yatay eksenler boyunca parçalara bölünür. rows ve columns boyutundaki bir ızgara, (satır+1)×(sütun+1) köşe içerir. Örneğin, 1×1'lik bir ağ, bir yama oluşturan 4 köşeden oluşur.
  • Normalleştirilmiş koordinatlar: Tüm köşe konumları, çizim sınırlarının sol üst kısmını (0f, 0f) ve sağ alt kısmını (1f, 1f) değerinin temsil ettiği normalleştirilmiş bir koordinat sistemi kullanır.
  • Bezier kontrol noktaları (teğetler): Her köşe, en fazla dört isteğe bağlı bezier kontrol noktası içerir. Bu teğetler, komşu köşeler arasındaki kenar eğriliğini belirtir. Offset.Unspecified kullanırsanız Compose, yamalar arasında sorunsuz geçişler sağlamak için teğetleri tahmin eder. Her bir ızgara hücresi, kontrol noktalarıyla birlikte 4 köşeden oluşur ve bir Bezier parçası oluşturur.
  • Renk interpolasyonu: Çerçeve, ana köşeler arasındaki renkleri hesaplar. Daha yumuşak renk geçişleri için hasBicubicColor değerini true olarak ayarlayarak Catmull-Rom enterpolasyonunu, false olarak ayarlayarak bilineer enterpolasyonu kullanın.

MeshGradientPainter ile çizim yapma

Jetpack Compose'da, ağ geçişi oluşturmak için MeshGradientPainter kullanın. MeshGradientPainter, tuval üzerine çizim yapar.

Basit bir ağ geçişi oluşturma

Temel bir statik ağ gradyanı oluşturmak için boyutlarını belirterek ve yapılandırma bloğundaki setVertex işlevini kullanarak köşe noktalarınızı konumlandırıp renkler atayarak bir MeshGradientPainter başlatın.

val rows = 1
val columns = 1

val gradientPainter = remember {
    MeshGradientPainter(rows, columns) {
        // Parameters: row, column, position, color
        setVertex(0, 0, Offset(0f, 0f), Color.Red)     // Top-Left
        setVertex(0, 1, Offset(1f, 0f), Color.Blue)    // Top-Right
        setVertex(1, 0, Offset(0f, 1f), Color.Green)   // Bottom-Left
        setVertex(1, 1, Offset(1f, 1f), Color.Yellow)  // Bottom-Right
    }
}

Box(
    modifier = modifier
        .aspectRatio(16/9f)
        .fillMaxWidth()
        .paint(gradientPainter)
)

Her köşesinde 4 renk tanımlanmış temel ağ geçişi
Şekil 2. Dört renkten oluşan temel bir ağ geçişi. Her köşe, dört renkten birine ayarlanmıştır.

Belirli Bezier kontrol noktalarını kullanma

Varsayılan olarak, ağ oluşturucu, ızgara geçişlerini sorunsuz tutmak için karmaşık hesaplamaları gerçekleştirir. Ancak belirli renk bölümlerini seçerek itmek, çekmek veya keskin bir şekilde sıkıştırmak istiyorsanız herhangi bir tepe noktasındaki teğetleri açıkça özelleştirebilirsiniz.

Kontrol ofsetleri, ana tepe noktasının konumuna göre ölçülür.

val customTangentPainter = remember {
    MeshGradientPainter(rows = 1, columns = 1) {
        // Tweak the top-left vertex to curve outwards to the right and bottom
        setVertex(
            row = 0,
            column = 0,
            position = Offset(0f, 0f),
            color = Color.Magenta,
            rightControlPoint = Offset(0.4f, 0.1f),
            bottomControlPoint = Offset(0.1f, 0.4f)
        )

        // Other points can remain unspecified to use default inferred fallback tangents
        setVertex(0, 1, Offset(1f, 0f), Color.Cyan)
        setVertex(1, 0, Offset(0f, 1f), Color.Blue)
        setVertex(1, 1, Offset(1f, 1f), Color.Black)
    }
}
Box(
    modifier = modifier
        .aspectRatio(16/9f)
        .fillMaxWidth()
        .paint(customTangentPainter)
)

Sol üst noktası kavisli olan ağ geçişi.
Şekil 3. Sol üstteki tepe noktasını bir Bezier kontrol noktasıyla eğin.

Gelişmiş ızgaralar oluşturma

Bu örnekte, 3'e 3'lük bir ızgara gösterilmektedir. Bu, belirtilmesi gereken 16 nokta olduğu ve orta noktaların farklı ofsetlerle ayarlandığı anlamına gelir:

val points = remember {
    listOf(
        Offset(0.0f, 0.0f), Offset(0.3f, 0.0f), Offset(0.7f, 0.0f), Offset(1.0f, 0.0f),
        Offset(0.0f, 0.3f), Offset(0.2f, 0.4f), Offset(0.7f, 0.2f), Offset(1.0f, 0.3f),
        Offset(0.0f, 0.7f), Offset(0.3f, 0.8f), Offset(0.7f, 0.6f), Offset(1.0f, 0.7f),
        Offset(0.0f, 1.0f), Offset(0.3f, 1.0f), Offset(0.7f, 1.0f), Offset(1.0f, 1.0f)
    )
}

val gradientPainter = remember {
    MeshGradientPainter(rows = 3, columns = 3) {
        // Row 0
        setVertex(0, 0, points[0], yellow)
        setVertex(0, 1, points[1], orange)
        setVertex(0, 2, points[2], yellow)
        setVertex(0, 3, points[3], purple)

        // Row 1
        setVertex(1, 0, points[4], pink)
        setVertex(1, 1, points[5], yellow)
        setVertex(1, 2, points[6], pink)
        setVertex(1, 3, points[7], purple)

        // Row 2
        setVertex(2, 0, points[8], indigo)
        setVertex(2, 1, points[9], pink)
        setVertex(2, 2, points[10], purple)
        setVertex(2, 3, points[11], indigo)

        // Row 3
        setVertex(3, 0, points[12], purple)
        setVertex(3, 1, points[13], indigo)
        setVertex(3, 2, points[14], pink)
        setVertex(3, 3, points[15], yellow)
    }
}

Box(
    modifier = modifier.padding(32.dp)
        .aspectRatio(16 / 9f)
        .fillMaxWidth()
        .paint(gradientPainter)
        // ...
)

Bezier kontrol noktaları ve dalga renkleri içeren ağ geçişi ve üzerinde gösterilen ağ noktaları.
Şekil 4. Bezier kontrol noktaları ve dalga renkleri içeren ağ geçişi ve üzerinde gösterilen ağ noktaları.

Örgü geçişini canlandırma

MeshGradientPainter işlevinin block lambda parametresi bir DrawScope içinde yürütüldüğünden, değişebilir durumu okuyabilir ve gözlemleyebilir. Gölgelendiricileri veya bitmap'leri yeniden tahsis etmeden konumları ya da renkleri zaman içinde canlandırabilirsiniz.

val infiniteTransition = rememberInfiniteTransition(label = "meshMovement")
val animatedOffset by infiniteTransition.animateFloat(
    initialValue = -0.1f,
    targetValue = 0.1f,
    animationSpec = infiniteRepeatable(
        animation = tween(2500, easing = LinearEasing),
        repeatMode = RepeatMode.Reverse
    ),
    label = "offset"
)

val coral = Color(255, 90, 90)
val peach = Color(255, 139, 90)
val amber = Color(255, 169, 90)
val sunshine = Color(255, 212, 90)
val indigo = Color(0xFF5856D6)
val pink = Color(0xFFFF2D55)


val gradientPainter = remember {
    MeshGradientPainter(rows = 3, columns = 3) {
        // Row 0
        setVertex(0, 0, Offset(0.0f, 0.0f), indigo)
        setVertex(0, 1, Offset(0.3f, 0.0f), peach)
        setVertex(0, 2, Offset(0.7f, 0.0f), amber)
        setVertex(0, 3, Offset(1.0f, 0.0f), sunshine)
        // Row 1
        setVertex(1, 0, Offset(0.0f, 0.3f), pink)
        setVertex(1, 1, Offset(0.2f, 0.4f) + Offset(animatedOffset, animatedOffset), coral)
        setVertex(1, 2, Offset(0.7f, 0.2f) + Offset(animatedOffset, animatedOffset), peach)
        setVertex(1, 3, Offset(1.0f, 0.3f), indigo)

        // Row 2
        setVertex(2, 0, Offset(0.0f, 0.7f), coral)
        setVertex(2, 1, Offset(0.3f, 0.8f) + Offset(animatedOffset, 0f), pink)
        setVertex(2, 2, Offset(0.7f, 0.6f) + Offset(animatedOffset, 0f), sunshine)
        setVertex(2, 3, Offset(1.0f, 0.7f), amber)

        // Row 3
        setVertex(3, 0, Offset(0.0f, 1.0f), sunshine)
        setVertex(3, 1, Offset(0.3f, 1.0f), amber)
        setVertex(3, 2, Offset(0.7f, 1.0f), pink)
        setVertex(3, 3, Offset(1.0f, 1.0f), indigo)
    }
}


Box(
    modifier = modifier.padding(32.dp)
        .safeContentPadding()
        .aspectRatio(16 / 9f)
        .fillMaxWidth()
        .paint(gradientPainter)
)

Şekil 5. Animasyonu gösteren noktalar içeren animasyonlu ağ geçişi.