Published on

Custom Shape, Path va Animatable

Authors

SwiftUI da tayyor shakllar bor — Circle, Rectangle, Capsule. Lekin real ilovalarda maxsus shakllar kerak. Path va Shape bilan istalgan shakl yaratish mumkin.

Path asoslari

// ═══════════════════════════════════════
//  PATH — qo'lda shakl chizish
// ═══════════════════════════════════════
struct UchburchakPath: View {
    var body: some View {
        Path { path in
            // Boshlang'ich nuqta
            path.move(to: CGPoint(x: 100, y: 0))
            // Chiziqlar
            path.addLine(to: CGPoint(x: 200, y: 150))
            path.addLine(to: CGPoint(x: 0, y: 150))
            // Yopish
            path.closeSubpath()
        }
        .fill(.blue.gradient)
    }
}

Shape protokoli

// ═══════════════════════════════════════
//  CUSTOM SHAPE — o'z shaklingiz
// ═══════════════════════════════════════
struct Yulduz: Shape {
    let qirralariSoni: Int
    let ichkiRadius: CGFloat // Ichki radius nisbati (0...1)

    // path(in:) — shaklni chizish
    func path(in rect: CGRect) -> Path {
        let markaz = CGPoint(x: rect.midX, y: rect.midY)
        let tashqiRadius = min(rect.width, rect.height) / 2
        let ichki = tashqiRadius * ichkiRadius

        var path = Path()
        let nuqtalar = qirralariSoni * 2

        for i in 0..<nuqtalar {
            let burchak = Double(i) * .pi / Double(qirralariSoni) - .pi / 2
            let radius = i.isMultiple(of: 2) ? tashqiRadius : ichki
            let nuqta = CGPoint(
                x: markaz.x + CGFloat(cos(burchak)) * radius,
                y: markaz.y + CGFloat(sin(burchak)) * radius
            )

            if i == 0 {
                path.move(to: nuqta)
            } else {
                path.addLine(to: nuqta)
            }
        }
        path.closeSubpath()
        return path
    }
}

// Ishlatish
Yulduz(qirralariSoni: 5, ichkiRadius: 0.4)
    .fill(.yellow.gradient)
    .frame(width: 100, height: 100)

.trim() bilan animatsiya

// ═══════════════════════════════════════
//  TRIM — chizilish animatsiyasi
// ═══════════════════════════════════════
struct ChizilishAnimatsiyasi: View {
    @State private var foiz: CGFloat = 0

    var body: some View {
        ZStack {
            // Fon doira
            Circle()
                .stroke(.gray.opacity(0.2), lineWidth: 8)

            // Animatsiyali doira
            Circle()
                .trim(from: 0, to: foiz)
                .stroke(
                    .blue.gradient,
                    style: StrokeStyle(
                        lineWidth: 8,
                        lineCap: .round
                    )
                )
                .rotationEffect(.degrees(-90))

            // Foiz matni
            Text("\(Int(foiz * 100))%")
                .font(.title.bold())
        }
        .frame(width: 120, height: 120)
        .onAppear {
            withAnimation(.easeOut(duration: 1.5)) {
                foiz = 0.75
            }
        }
    }
}

Animatable Shape

// ═══════════════════════════════════════
//  ANIMATABLE — shape parametrini animatsiya qilish
// ═══════════════════════════════════════
struct TolqinShakl: Shape {
    var foiz: CGFloat      // Animatsiya qilinadigan qiymat

    // animatableData — SwiftUI bu qiymatni interpolyatsiya qiladi
    var animatableData: CGFloat {
        get { foiz }
        set { foiz = newValue }
    }

    func path(in rect: CGRect) -> Path {
        var path = Path()
        let kenglik = rect.width
        let balandlik = rect.height

        path.move(to: CGPoint(x: 0, y: balandlik * foiz))

        // To'lqin chizish
        for x in stride(from: 0, through: kenglik, by: 1) {
            let nisbiy = x / kenglik
            let y = balandlik * foiz + sin(nisbiy * .pi * 4) * 10
            path.addLine(to: CGPoint(x: x, y: y))
        }

        path.addLine(to: CGPoint(x: kenglik, y: balandlik))
        path.addLine(to: CGPoint(x: 0, y: balandlik))
        path.closeSubpath()

        return path
    }
}

struct TolqinKorinishi: View {
    @State private var foiz: CGFloat = 0.6

    var body: some View {
        TolqinShakl(foiz: foiz)
            .fill(.blue.gradient.opacity(0.5))
            .frame(height: 200)
            .onAppear {
                withAnimation(.easeInOut(duration: 2).repeatForever()) {
                    foiz = 0.3
                }
            }
    }
}

🎯 Topshiriq

5 qirrali yulduz Shape yarating, .trim() bilan chizilish animatsiyasi qo'shing. Keyin Animatable protokolini qo'llab, yulduz qirralarining ichki radiusini animatsiya qiling (yulduzdan doiraga o'tish effekti).

Buy mea coffee