Örgü gradyanları

Örgü renk geçişleri, yamalardan oluşan bir 2D ızgara kullanarak karmaşık ve çok yönlü renk geçişleri oluşturur. Doğrusal veya radyal renk geçişlerinin aksine, örgü renk geçişleri renkleri bir ızgara üzerinde sorunsuz bir şekilde enterpolasyon yapar. Kullanıcı arayüzünüzde akıcı ve doğal estetik öğeler oluşturmak için örgü renk geçişlerini kullanın.

Mevcut örgü gradyan noktalarının gösterildiği bir örgü gradyan örneği.
Şekil 1. Mevcut örgü gradyan noktalarının gösterildiği bir örgü gradyanı örneği.

Temel kavramlar

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

  • Izgara boyutları: Ağ, dikey ve yatay eksenler boyunca yamalara bölünür. rows ve columns içeren bir ızgara (satır+1)×(sütun+1) köşe içerir. Örneğin, 1x1 örgü, bir yama oluşturan 4 köşeden oluşur.
  • Normalleştirilmiş koordinatlar: Tüm köşe konumları, (0f, 0f)'nin sol üstü ve (1f, 1f)'ün çizim sınırlarının sağ altını 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 çıkarır. 4 köşe ve kontrol noktalarıyla oluşturulan her ızgara hücresi, bir bezier yaması oluşturur.
  • Renk enterpolasyonu: Çerçeve, ana köşeler arasındaki renkleri hesaplar. Daha yumuşak renk geçişleri için Catmull-Rom enterpolasyonu için hasBicubicColor değerini true, çift doğrusal enterpolasyon için false olarak ayarlayın.

MeshGradientPainter ile çizim yapma

Jetpack Compose'da, ağ renk geçişi oluşturmak için MeshGradientPainter kullanın. MeshGradientPainter tuval üzerinde çizim yapıyor.

Basit bir örgü gradyanı oluşturma

Temel bir statik ağ gradyanı oluşturmak için boyutlarını belirterek bir MeshGradientPainter başlatın ve köşe noktalarınızı konumlandırıp onlara renk atamak için yapılandırma bloğunun içindeki setVertex işlevini kullanı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öşede 4 renk tanımlanmış temel örgü renk geçişi
Şekil 2. Dört renkle oluşturulmuş temel bir ağ renk geçişi. Her köşe, dört renkten biriyle ayarlanmıştır.

Belirli Bezier kontrol noktalarını kullanma

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

Kontrol ofsetleri, ana köşe 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 örgü gradyan.
Şekil 3. Sol üstteki tepe noktasını Bezier kontrol noktasıyla eğin.

Gelişmiş kılavuzlar oluşturma

Bu örnekte 3x3 bir ızgara gösterilmektedir. Bu, ortadaki noktalar farklı uzaklıklarla ayarlanmış şekilde 16 noktanın belirtilmesi gerektiği 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 örgü renk geçişi ve üzerinde örgü noktaları gösteriliyor.
Şekil 4. Bezier kontrol noktaları ve dalga renkleri içeren ağ renk geçişi ve üzerinde ağ noktaları gösteriliyor.

Örgü gradyanını canlandırma

MeshGradientPainter öğesinin block lambda parametresi DrawScope içinde yürütüldüğünden, değiştirilebilir durumu okuyabilir ve gözlemleyebilir. Gölgelendiricileri veya bit eşlemleri yeniden ayırmadan 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östermek için noktalar içeren animasyonlu ağ gradyanı.