Published on

SwiftUI-da Animation Curve va Animation Timing

Authors

Va biz qaytib keldik! Hammaga salom, men — Nick. Oldingi videoda biz animatsiyalarning asoslarini o'rgandik — animatsiyalar qanday ishlashini ko'rib chiqdik. Ushbu videoda esa animation curve (animatsiya egri chizig'i) haqida gaplashamiz — buni ba'zilar animation timing (animatsiya vaqtlash) deb ham atashadi. Mohiyatan, sizda qanday animatsiya bo'lishidan qat'i nazar, siz uning tezligini va animatsiya davomida qanday sur'at bilan harakat qilishini o'zgartirish orqali, animatsiyaning ko'rinishini sozlashingiz mumkin.

Ushbu videoda biz SwiftUI kodimizda standart holatda mavjud bo'lgan, va shunchaki bitta kichik modifikator orqali qo'shiladigan barcha animatsiya egri chiziqlarini ko'rib chiqamiz. Albatta, agar haqiqatan xohlasangiz, o'zingizning maxsus egri chiziqlaringizni ham yaratishingiz mumkin, ammo aytishim mumkin: holatlarning 99 foizida, standart egri chiziqlar siz qilmoqchi bo'lgan har qanday animatsiya uchun yetarli bo'ladi. Shuning uchun ushbu videoda biz buni juda sodda ushlab turamiz: ekranga bir nechta obyekt joylashtiramiz va ularning har birini turli egri chiziqlar bilan animatsiya qilamiz. Shu tarzda biz har bir egri chiziq orasidagi farqni yaqqol ko'rsatishimiz mumkin, chunki ba'zida bu farqlarni ko'rish biroz qiyin bo'ladi.

Shuni alohida ta'kidlab o'tmoqchiman: bu animatsiya egri chiziqlari universal — ular SwiftUI-ga xos emas, balki barcha turli dasturlash tillarida, barcha turli animatsiya dasturlarida ishlatiladi. Agar shu egri chiziqlarning ba'zilarini Google-da qidirsangiz, animatsiya egri chiziqlari qanday ishlashi va o'zingizning vaqtlashingizni qanday moslashtirish mumkinligi haqida juda ko'plab manbalarni topasiz. Ammo yana bir bor aytaman: SwiftUI bilan birga keladigan standart egri chiziqlar, ushbu kursda qiladigan deyarli har qanday narsa uchun yetarli va ortig'i bilan yetarli.

Hammaga xush kelibsiz qaytib! Bugun bizda yana bir juda qiziqarli kod yozish videosi bor — bugun animation timing haqida gaplashamiz.


Yangi SwiftUI fayl yaratish

Ushbu videoda qiladigan barcha kod uchun yangi fayl yaratamiz. Navigator-da o'ng tugmani bosib, yangi fayl yaratamiz — bu SwiftUI View bo'ladi, va unga AnimationTimingBootcamp deb nom beramiz. Create tugmasini bosamiz, ichiga kirgandan so'ng, canvas-da Resume tugmasini bosamiz, toki hammasi yaxshi va kod yozishga tayyor ekanligimizga ishonch hosil qilaylik.


Boshlang'ich animatsiya

Oldingi videodagi kabi, juda oddiy bir animatsiyadan boshlaymiz. VStack yaratamiz, uning yuqorisiga tugma qo'shamiz (bu yerda biz allaqachon bilganimiz string protokolidan foydalanamiz — bu joylarni tezroq o'tib ketamiz, chunki buni avval ham qilgan edik):

VStack {
    Button("Button") {
        // amal hozircha bo'sh
    }

    RoundedRectangle(cornerRadius: 20)
        .frame(width: isAnimating ? 350 : 50, height: 100)
}

Tugmaning matni — "Button", va aslida bu matn unchalik muhim emas. Hozircha amal (action) qismini bo'sh qoldiramiz.

Shu tugma ostiga, burchak radiusi 20 bo'lgan RoundedRectangle qo'shamiz, va unga frame beramiz — eni, aytaylik, 300, ammo men buni biroz kattaroq, 350 qilaman — bu yaxshiroq ko'rinadi. Balandligini esa 100 qilamiz.

Endi animatsiya uchun state o'zgaruvchisi qo'shamiz:

@State var isAnimating: Bool = false

Tugmani bosganimizda, isAnimatingni almashtirishni (toggle) xohlaymiz. Va biz nimani animatsiya qilmoqchimiz? — to'rtburchakning enini. Shuning uchun, isAnimatingga qarab: agar u true bo'lsa — 350, aks holda — 50:

Button("Button") {
    isAnimating.toggle()
}

Resume tugmasini bosamiz, jonli oldindan ko'rishda (live preview) Play tugmasini bosamiz, va bu ishlayotganiga ishonch hosil qilamiz.


Animatsiya qo'shish

Endi shu to'rtburchakka to'g'ridan-to'g'ri animatsiya qo'shamiz. .animation deb yozamiz, va oldingi videodagi kabi, .defaultni chaqirishimiz mumkin — bu standart animatsiya:

RoundedRectangle(cornerRadius: 20)
    .frame(width: isAnimating ? 350 : 50, height: 100)
    .animation(.default, value: isAnimating)

Bosganimizda, bizda standart animatsiya bor. Ammo ushbu videoda biz aynan animation timingni muhokama qilish uchun keldik, shuning uchun .default o'rniga, biz ko'rib chiqishimiz mumkin bo'lgan turli animatsiya egri chiziqlarini ko'ramiz. Nuqta qo'yib qarasak, bu yerda yana juda ko'p variantlar mavjud ekanligini ko'ramiz, va asosiylari — .linear, .easeIn, .easeInOut va .easeOut. Avval shularni ko'rib chiqamiz, so'ngra biroz murakkabroq narsalarga — masalan, interaktiv springlarga o'tamiz. Bularni tushuntirishning eng oson yo'li — shunchaki sizlarga ekranda ko'rsatib qo'yish.


To'rtta turli egri chiziqni solishtirish

Keling, bir nechta turli animatsiya qo'shamiz. Avval shu to'rtburchakka oddiy .default qoldiramiz, so'ngra to'rtta to'rtburchak qo'shamiz — shu to'rtburchakni nusxalab, uning ostiga uchta nusxasini joylashtiramiz, shunda bizda to'rtta to'rtburchak bo'ladi, va ularning barchasi hozircha standart vaqtlashga ega:

RoundedRectangle(cornerRadius: 20)
    .frame(width: isAnimating ? 350 : 50, height: 100)
    .animation(.linear, value: isAnimating)

RoundedRectangle(cornerRadius: 20)
    .frame(width: isAnimating ? 350 : 50, height: 100)
    .animation(.easeIn, value: isAnimating)

RoundedRectangle(cornerRadius: 20)
    .frame(width: isAnimating ? 350 : 50, height: 100)
    .animation(.easeInOut, value: isAnimating)

RoundedRectangle(cornerRadius: 20)
    .frame(width: isAnimating ? 350 : 50, height: 100)
    .animation(.easeOut, value: isAnimating)

Agar barchasi bir xil vaqtlashga ega bo'lsa, tugmani bosganimizda ularning barchasi aynan bir xil tezlikda animatsiya bo'ladi. Ammo endi vaqtlashlarni o'zgartiramiz: birinchisiga — .linear, ikkinchisiga — .easeIn, uchinchisiga — .easeInOut, to'rtinchisiga — .easeOut.

Bularning barchasi — turli xil animatsiya egri chiziqlari, va bu, mohiyatan, shuni anglatadi: animatsiya boshlangan paytdan tugagan paytgacha, animatsiya turli tezliklarda harakat qilishi mumkin.

  • linear — boshidan oxirigacha bir xil tezlikda harakatlanadi.
  • easeIn — animatsiyaga "yumshoq kiradi": avval sekin, so'ngra oxirida tezlashadi.
  • easeInOut — sekin, keyin tez, keyin yana sekin.
  • easeOut — avval tez, so'ngra sekinlashadi.

Ammo bularning barchasi aynan bir xil vaqtda tugaydi.

Tugmani bosib, tezda ko'rib chiqaylik — barchasi animatsiya qilinayotganini, va barchasi aynan bir xil vaqtda chiziqning oxiriga yetib borayotganini ko'ramiz. Ammo shu animatsiyalarning ba'zilarida nozik farqlarni ko'ramiz. Va animatsiya qilishda mahoratingiz oshgani sayin, qaysi animatsiyalar qaysi holatlar uchun yaxshiroq ko'rinishini sezib boradigan bo'lasiz — masalan, ekranga kirib keladigan biror narsa uchun easeInni xohlashingiz mumkin (shunda u ekranga kirib keladi), ekrandan chiqib ketayotgan biror narsa uchun esa easeOutni xohlashingiz mumkin.


Duration (davomiylik) qo'shish

Ammo buni tezroq bo'rttirib ko'rsatish uchun, ba'zilarining davomiyligini (duration) o'zgartiramiz. .linearni chaqirganimizda, biz unga duration ham qo'shishimiz mumkin. Shuning uchun, yana .linear deb yozaylik — bu yerda ikki xil tugatish (completion) variant bor, va biz duration parametri bilan kelganini tanlaymiz. Bu yerga, boshidan oxirigacha qancha soniya ketishini xohlasak, shu raqamni yozamiz.

Men barchasida bir xil davomiylikni ishlatishni xohlayman, shuning uchun yuqorida timing nomli o'zgaruvchi yaratamiz:

let timing: Double = 10

Double turidan foydalanamiz, chunki bizga kasrli son kerak — Double, mohiyatan, kasr qismi bo'lgan oddiy son, xolos. Men 10 soniya qilaman — odatda ilovadagi vaqtlashlarning ko'pi bir soniya yoki kamroq bo'ladi, ammo biz buni hozircha shunchaki bo'rttirib ko'rsatish uchun shunday qilamiz.

Endi shu timing o'zgaruvchisini durationga qo'shamiz, va xuddi shunday barchasiga qo'llaymiz:

.animation(.linear(duration: timing), value: isAnimating)
.animation(.easeIn(duration: timing), value: isAnimating)
.animation(.easeInOut(duration: timing), value: isAnimating)
.animation(.easeOut(duration: timing), value: isAnimating)

Animatsiyalarni qayta ishga tushirib, yaqinroq kuzatish

Keling, bu animatsiyalarni yana ishga tushirib, yanada yaqinroq kuzatamiz.

Linear

Birinchisi — linear — boshidan oxirigacha bir xil tezlikda harakatlanadi, ya'ni 10 soniya davomida butun vaqt mobaynida bir xil sur'atda. Bu — bizning birinchi to'rtburchagimiz. Bosamiz, va u butun 10 soniya davomida aynan bir xil tezlikda harakatlanayotganini ko'ramiz.

10 soniyada barcha vaqtlashlar bir-biriga yetib oladi. Jonli oldindan ko'rishni o'chirib, qayta yoqamiz (Play tugmasini bosamiz), toki yana boshlang'ich holatga qaytaylik.

Ease In

Endi **easeIn**ni ko'raylik. Linear bilan solishtirganda, easeIn juda sekin boshlanadi, so'ngra yetib oladi va linear bilan bir xil vaqtda tugaydi. Tugmani bosamiz, va easeIn sekin boshlanayotganini, linear-dan ancha orqada qolib ketayotganini ko'ramiz — ammo 10 soniyada ular tenglashadi va bir vaqtda yetib boradi.

Stop tugmasini bosamiz.

Ease In Out va Ease Out — birga

Bu safar **easeInOut**ni ko'ramiz — bu sekin boshlanadi, keyin biroz tezlashadi, keyin yana sekinlashib tugaydi. Shu bilan birga **easeOut**ni ham kuzatamiz — bu eng tez boshlanadi, shuning uchun u darrov oldinga chiqib ketadi, so'ngra sekinlashadi, toki barchasi bir xil vaqtda tugasin.

Tugmani bosamiz: bu to'rtburchak hammasidan oldinda, bu esa tez, keyin sekin, keyin tez harakatlanmoqda — va ularning barchasi aynan 10 soniyada tugaydi.

Animatsiya egri chizig'i — animatsiya davomida tezlikni o'zgartiradi. Duration esa — boshidan oxirigacha qancha vaqt ketishini, ya'ni umumiy vaqtlashni belgilaydi.

Men har birining tafsilotiga juda chuqur kirmayman — bu turli animatsiyalar uchun minglab qo'llanish holati mavjud. O'zingiz bir view yasab, ilovangizda bularni sinab ko'rishni tavsiya qilaman, toki qaysi animatsiya qaysi holat uchun eng yaxshi ko'rinishini topib olasiz. Bu, albatta, har xil bo'ladi — men o'z ilovalarimda har xil turini ishlataman, va sizlarga ham bularning farqlari haqida hech bo'lmaganda asosiy tushunchaga ega bo'lishni va ular bilan qulay bo'lib qolishni tavsiya qilaman.


Spring animatsiyasi

Yakunlashdan oldin, sizlarga spring (yoy) animatsiyalarini ko'rsatmoqchiman, chunki ular juda-juda qiziqarli. Avval to'rtta to'rtburchakni izohga olib qo'yamiz, shu jumladan linearni ham, va shu burchaklari yumaloq to'rtburchak (rounded rectangle)ga yana bir animatsiya qo'shamiz:

RoundedRectangle(cornerRadius: 20)
    .frame(width: isAnimating ? 350 : 50, height: 100)
    .animation(.spring(), value: isAnimating)

Bu safar **.spring**ni chaqiramiz — bu, ehtimol, mening barcha animatsiyalar orasida eng sevimlisi, chunki u haqiqatan ham yoy (spring)ga o'xshab ko'rinadi, va u juda tabiiy ko'rinadi. Resume tugmasini bosamiz — bizga bu yerda timingning o'zi kerak emas, chunki biz endi 10 soniyani ishlatmayapmiz — bu shunchaki spring uchun standart vaqtlash, va bizda juda tabiiy ko'rinadigan, ajoyib animatsiya bor. Aytishim mumkin, bu — agar siz biror view-ni ko'rsatayotgan bo'lsangiz, yoki biror narsa ekranga otilib chiqayotgan bo'lsa, ishlatiladigan eng keng tarqalgan animatsiyalardan biri — spring shunday holatlar uchun juda-juda foydali.


Spring-ni moslashtirish

Va nihoyat, sizlarga spring-ni qanday moslashtirish mumkinligini ko'rsatmoqchiman, chunki ba'zida sizga qadamingizda biroz ko'proq sakrash (bounce), yoyingizda biroz ko'proq "yoy"lik kerak bo'ladi.

.animation, so'ngra nuqta qo'yib, spring deb yoza boshlaymiz, va bizda response, dampingFraction va blendDuration parametrlari bilan keladigan variant mavjud. Boshqa animatsiya turlari ham bor, ammo men ularning barchasiga kirmayman — hozircha shu birini ishlatamiz:

RoundedRectangle(cornerRadius: 20)
    .frame(width: isAnimating ? 350 : 50, height: 100)
    .animation(
        .spring(
            response: 1.0,
            dampingFraction: 1.0,
            blendDuration: 1.0
        ),
        value: isAnimating
    )

response, damping va blendDurationning har birini alohida qatorga yozamiz, o'qilishi osonroq bo'lishi uchun. Men animatsiya bo'yicha ekspert emasman, va blendDuration aslida nima qilishini to'liq bilmayman, shuning uchun buni hozircha 1.0 holida qoldiraman. Keling, response va **dampingFraction**ni ko'rib chiqamiz.

response

response — bu, mohiyatan, biz boshida ko'rgan duration bilan bir xil. Agar responseni, masalan, 3.0 qilsak, bu spring uch soniya davomida sodir bo'ladi.

dampingFraction

dampingFraction — spring qanchalik sakrab qaytishini boshqaradi. Agar buni 1.0 qilsak, u, menimcha, umuman sakrab qaytmaydi. Sinab ko'raylik:

.spring(
    response: 3.0,
    dampingFraction: 1.0,
    blendDuration: 1.0
)

Uch soniya davomida animatsiya bo'ladi, va hech qanday sakrab qaytish bo'lmaydi.

Ammo agar dampingFractionni 0.5 qilsak, xuddi shu narsa sodir bo'ladi, faqat endi bizda katta sakrab qaytish bo'ladi. To'xtatamiz, qayta ishga tushiramiz:

.spring(
    response: 3.0,
    dampingFraction: 0.5,
    blendDuration: 1.0
)

Endi bizda sakrab qaytish borligini ko'ramiz, chunki biz dampingFractionni o'zgartirdik.

Response va dampingFraction-ni birga o'zgartirish

Endi responseni bir soniyaga o'zgartiramiz, dampingFractionni esa, aytaylik, 0.2ga tushiramiz:

.spring(
    response: 1.0,
    dampingFraction: 0.2,
    blendDuration: 1.0
)

Endi bizda juda qiziq, g'alati animatsiya bor. To'xtatamiz, qayta ishga tushiramiz, va tugmani bossak, animatsiya tugaganda juda katta "yoy"lik borligini ko'ramiz. Bu, albatta, qiziqarli, ammo agar oldingi, kichikroq qiymatga qaytsak, bu deyarli haddan tashqari ko'p sakrab qaytadi, shuning uchun men buni haqiqiy ilovada ishlatmasdim.

Hozircha siz, hech bo'lmaganda, spring-laringizni qanday moslashtirish mumkinligini bilasiz. Men aytardim: dampingFraction uchun, odatda, 0.60.7 atrofida bir qiymat eng yaxshisi bo'ladi, va men animatsiyalarning qisqaroq bo'lishini yoqtiraman, shuning uchun response uchun, aytaylik, 0.5 atrofida bir qiymat:

.spring(
    response: 0.5,
    dampingFraction: 0.7,
    blendDuration: 1.0
)

Bu — juda tabiiy va chiroyli ko'rinadigan spring.


Xulosa

Yana bir bor aytaman: bu vaqtlashlarning barchasini o'zingizning bo'sh vaqtingizda sinab ko'ring. Ammo endi siz animatsiyalarni turli animation curvelar va turli animation timinglar bilan qanday moslashtirish mumkinligini bilasiz.

Internetda juda ko'plab manbalar mavjud — agar shunchaki "Swift animation curves" deb Google-da qidirsangiz, haqiqiy grafiklarni topishingiz va o'zingizning egri chiziqlaringizni yaratishga chuqur kirib borishingiz mumkin. Ammo agar o'zingizning egri chiziqlaringizni yaratishni xohlamasangiz, easeIn, easeInOut, easeOut — bular juda qulay, juda foydali, va men ularni o'zim doim ishlataman — menimcha, sizlar ham ishlatadigan bo'lasiz.

Har doimgidek, tomosha qilganingiz uchun rahmat. Men — Nick, bu Swiftful Thinking, va keyingi videoda ko'rishamiz!

Buy mea coffee