Published on

SwiftUI'da shaxsiy shakllarni animatsiya qilish (AnimatableData)

Authors

Oddiy o'zgaruvchilar bilan muammo

Avvalgi darslarda biz o'zimizning shaxsiy (Custom) shakllarimizni yasashni o'rgandik. Aytaylik, biz faqatgina bitta burchagi yoy (rounded) bo'ladigan Maxsus To'rtburchak chizdik. Uni chizishda bizga burchak qanchalik bukilishini bildirish uchun parametr kerak bo'ladi (var cornerRadius: CGFloat).

Agar biz bu parametrni vaqt o'tishi bilan o'zgartirsak (masalan tugma bosilganda 0 dan 60 ga o'zgartirsak) qiziq xolat yuz beradi: shakl o'zgaradi, lekin Silliq Animatsiya bilan emas! U birdaniga "sakrab" o'zgaradi. withAnimation ga o'rab qo'ygan bo'lsak ham animatsiya ishlamaydi! Nima uchun?

Sababi oddiy: SwiftUI dagi tayyor Rectangle ichida barcha narsa Apple tomonidan animatsiya qilishga sozlangan. Lekin biz yaratgan Custom Shape da path() funksiyasi qaysi raqam aynan animatsiya bilan o'zgarishi kerakligini bilmaydi.

AnimatableData nima?

Ushbu muammoni hal qilishning yagona yo'li — SwiftUI ga qaysi malumot "jonli" (animatable) ekanligini ochiq aytishdir. Buning uchun animatableData nomli maxsus parametrni yozishimiz shart.

1-Misol: Faqat bir burchagi aylanadigan to'rtburchak

import SwiftUI

struct RectangleWithSingleCornerAnimation: Shape {
    var cornerRadius: CGFloat

    // SIRLI KALIT SHU YERDA:
    var animatableData: CGFloat {
        get { cornerRadius }
        set { cornerRadius = newValue }
    }

    func path(in rect: CGRect) -> Path {
        var path = Path()

        // Tepadan o'ngga
        path.move(to: .zero)
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))

        // O'ng tepadan O'ng pastga (burchakkacha etib bormaymiz, burilish uchun joy qoldiramiz)
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - cornerRadius))

        // Burchakda yoy chizamiz (Burilish)
        path.addArc(
            center: CGPoint(x: rect.maxX - cornerRadius, y: rect.maxY - cornerRadius),
            radius: cornerRadius,
            startAngle: Angle(degrees: 0),
            endAngle: Angle(degrees: 90),
            clockwise: false
        )

        // Pastdan chapga
        path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))

        // Va yana boshlagan nuqtaga
        path.addLine(to: .zero)

        return path
    }
}

Endi, biz qachonki cornerRadius ni o'zgartirsak, SwiftUI uning get va set metodlariga o'tib, eski va yangi raqamlar orasidagi 1,2,3,4 kabi oraliq raqamlarni birma-bir o'zgartirib ajoyib silliq animatsiyani vujudga keltiradi!

2-Misol: animatsiyali Pac-Man

Bu narsa faqat radiuslarga emas, balki graduslarga (degrees) ham ishlaydi. Keling og'zini ochib-yopadigan Pac-Man yasaymiz.

struct Pacman: Shape {
    var offsetAmount: Double // Og'izning qanchalik ochilishi (gradusda)

    // BUNI YOZMASAK OG'IZ OCHILIB YOPILISHI SAKRAB ISHLAYDI!
    var animatableData: Double {
        get { offsetAmount }
        set { offsetAmount = newValue }
    }

    func path(in rect: CGRect) -> Path {
        var path = Path()

        // O'rtadan boshlaymiz
        path.move(to: CGPoint(x: rect.midX, y: rect.midY))

        // Yoy qo'shamiz (OffsetAmount qancha katta bo'lsa, og'iz shuncha ko'p ochiladi)
        path.addArc(
            center: CGPoint(x: rect.midX, y: rect.midY),
            radius: rect.height / 2,
            startAngle: Angle(degrees: offsetAmount),
            endAngle: Angle(degrees: 360 - offsetAmount),
            clockwise: false
        )

        return path
    }
}

Bu shaklni oynaga qo'shganimizda uni withAnimation bilan ochib yopish qanchalik qulay va tayyorligini ko'rasiz:

struct AnimatableDataBootcamp: View {
    @State private var animate: Bool = false

    var body: some View {
        ZStack {
            Pacman(offsetAmount: animate ? 20 : 0)
                .fill(Color.yellow)
                .frame(width: 200, height: 200)
                .onAppear {
                    // Tinimsiz takrorlanuvchi animatsiya ulaymiz
                    withAnimation(Animation.easeInOut.repeatForever()) {
                        animate.toggle()
                    }
                }
        }
    }
}

Xulosa shuki: Agar Custom Shape yozsangiz va u nimagadir animatsiya bilan silliq o'zgarmayotgan bo'lsa, siz albatta animatableData yozishni esdan chiqargansiz!

Buy mea coffee