udførelse af iOS-animationer på Visninger med UIKit og Uivevisning
- om forfatteren
- animering ved 60 FPS
- Kernerammer
- UIKit/Uivevisning animationer
- animation (medvarighed: animationer: færdiggørelse)
- animatemedvarighed
- Uiveejendomanimator
- Hvad er en frame?
- animateKeyframes
- CoreAnimation
- Uivvisning + Kerneanimation
- UIKitDynamics
- UIKitDynamicAnimator
- UIKitDynamicBehavior
- Performance Tuning
- Core Animation Instrument
- tegning
- rasterisering
- indpakning
om forfatteren
Saravanan er en iOS ingeniør og forfatter på fleksiple og Remote Tools. Han har arbejdet med flere startups på tværs af forskellige domæner.Læs mere om Saravanan
- 14 min læs
- Animation,iOS,UI,mobil
- gemt til offline læsning
- Del på kvidre, LinkedIn
jeg har været en iOS-udvikler i over et årti nu og har sjældent set artikler, der konsoliderer alle mulige måder at udføre animationer i iOS. Denne artikel sigter mod at være en primer på iOS-animationer med det formål at udtømmende dække de forskellige måder at gøre det samme på.
i betragtning af emnets omfang dækker vi hver del kortfattet på et ret højt niveau. Målet er at uddanne læseren med et sæt valg for at tilføje animationer til hans/ hendes iOS-app.
før vi starter med emner relateret til iOS, lad os tage et kort kig på animationshastigheden.
animering ved 60 FPS
generelt i videoer er hver ramme repræsenteret af et billede, og billedhastigheden bestemmer antallet af billeder, der vendes i sekvensen. Dette kaldes ‘frames per second’ eller FPS.
FPS bestemmer antallet af stillbilleder, der vendes inden for et sekund, hvilket bogstaveligt betyder, at jo mere antallet af billeder/ rammer, flere detaljer/ information vises i videoen. Dette gælder også for animationer.
FPS bruges typisk til at bestemme kvaliteten af animationer. Der er en populær opfattelse, at enhver god animation skal køre på 60fps eller højere — noget mindre end 60fps ville føle sig lidt væk.
vil du se forskellen mellem 30FPS og 60FPS? Tjek det her!
har du bemærket forskellen? Menneskelige øjne kan helt sikkert mærke jitteren ved lavere fps. Derfor er det altid en god praksis at sikre, at enhver animation, du opretter, overholder grundreglen om at køre ved 60 fps eller højere. Dette får det til at føle sig mere realistisk og levende.
efter at have set på FPS, lad os nu dykke ned i de forskellige centrale iOS-rammer, der giver os en måde at udføre animationer på.
Kernerammer
i dette afsnit berører vi rammerne i iOS SDK, som kan bruges til at oprette visningsanimationer. Vi vil gøre en hurtig tur gennem hver af dem og forklare deres funktionssæt med et relevant eksempel.
UIKit/Uivevisning animationer
Uivevisning er basisklassen for enhver visning, der viser indhold i iOS-apps.
UIKit, den ramme, der giver os Uivevisning, giver os allerede nogle grundlæggende animationsfunktioner, der gør det praktisk for udviklere at opnå mere ved at gøre mindre.
API ‘ en,UIView.animate
, er den nemmeste måde at animere visninger på, da enhver visnings egenskaber let kan animeres ved at give egenskabsværdierne i den blokbaserede syntaks.
i UIKit-animationer anbefales det kun at ændre de animerbare egenskaber ved Uivevisning ellers vil der være konsekvenser, hvor animationerne kan få visningen til at ende i en uventet tilstand.
animation (medvarighed: animationer: færdiggørelse)
denne metode tager animationens varighed, et sæt visnings animerbare egenskabsændringer, der skal animeres. Færdiggørelsesblokken giver et tilbagekald, når visningen er færdig med at udføre animationen.
næsten enhver form for animation som at flytte, skalere, rotere, falme osv. på en visning kan opnås med denne enkelt API.
overvej nu, at du vil animere en knapstørrelsesændring, eller du vil have en bestemt visning til at forstørre ind på skærmen. Sådan kan vi gøre det ved hjælp af UIView.animate
API:
let newButtonWidth: CGFloat = 60UIView.animate(withDuration: 2.0) { //1 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) //2 self.button.center = self.view.center //3}
Her er hvad vi laver her:
- vi kalder
UIView.animate
metode med en varighedsværdi, der er overført til den, der repræsenterer, hvor længe animationen, der er beskrevet inde i blokken, skal køre. - vi indstiller den nye ramme på knappen, der skal repræsentere animationens endelige tilstand.
- vi indstiller knappen
center
med dets overvågnings center, så det forbliver i midten af skærmen.
ovenstående blok af animationskode skal udløse animationen af knappens ramme, der skifter fra nuværende ramme:
Width = 0, Height = 0
til den endelige ramme:
Width = Height = newButtonWidth
og her er hvordan animationen ville se ud:
animatemedvarighed
denne metode er som en udvidelse af animate-metoden, hvor du kan gøre alt, hvad du kan udføre i den tidligere API med nogle fysiske adfærd tilføjet til visningsanimationerne.
for eksempel, hvis du vil opnå fjederdæmpningseffekter i animationen, som vi har gjort ovenfor, så er det sådan, koden vil se ud:
let newButtonWidth: CGFloat = 60UIView.animate(withDuration: 1.0, //1 delay: 0.0, //2 usingSpringWithDamping: 0.3, //3 initialSpringVelocity: 1, //4 options: UIView.AnimationOptions.curveEaseInOut, //5 animations: ({ //6 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center}), completion: nil)
Her er det sæt parametre, Vi bruger:
duration
repræsenterer varigheden af animationen, der bestemmer, hvor længe kodeblokken skal køre.- repræsenterer den oprindelige forsinkelse, som vi vil have før starten af animationen.
SpringWithDamping
repræsenterer værdien af den fjedrende effekt, som vi ønsker, at visningen skal opføre sig. Værdien skal være mellem 0 og 1. Jo lavere værdien er, desto højere er fjederoscillationen.velocity
repræsenterer den hastighed, hvormed animationen skal starte.-
options
type animationskurve, som du vil anvende til din visningsanimation. - endelig blokken af kode, hvor vi indstiller rammen på den knap, der skal animeres. Det er det samme som den foregående animation.
og her er hvad animationen ville se ud med ovenstående animation konfiguration:
Uiveejendomanimator
for lidt mere kontrol over animationer, UIViewPropertyAnimator
kommer handy hvor det giver os en måde at pause og genoptage animationer på. Du kan have tilpasset timing og få din animation til at være interaktiv og afbrydelig. Dette er meget nyttigt, når du udfører animationer, der også kan interagere med brugerhandlinger.
den klassiske ‘Slide to Unlock’ – gestus og afspillervisningen Afvis / Udvid animation (i musikappen) er eksempler på interaktive og afbrydelige animationer. Du kan begynde at flytte en visning med din finger, slip den derefter, og visningen går tilbage til sin oprindelige position. Alternativt kan du fange visningen under animationen og fortsætte med at trække den med fingeren.
Følgende er et simpelt eksempel på, hvordan vi kunne opnå animationen ved hjælp af UIViewPropertyAnimator
:
let newButtonWidth: CGFloat = 60let animator = UIViewPropertyAnimator(duration:0.3, curve: .linear) { //1 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center}animator.startAnimation() //2
Her er hvad vi laver:
- vi kalder
UIViewProperty
API ved at passere varigheden og animationskurven. - i modsætning til begge ovenstående Uivevisning.animere API ‘ er, animationen starter ikke, medmindre du angiver det selv, dvs.du har fuld kontrol over hele animationsprocessen/ strømmen.
lad os nu sige, at du vil have endnu mere kontrol over animationerne. For eksempel, du ønsker at designe og styre hver eneste ramme i animationen. Der er en anden API til det, animateKeyframes
. Men før vi dykker ind i det, lad os hurtigt se på, hvad en ramme er, i en animation.
Hvad er en frame
?
en samling af visningens rammeændringer/ overgange, fra starttilstand til sluttilstand, er defineret som animation
og hver position af visningen under animationen kaldes som en frame
.
animateKeyframes
denne API giver en måde at designe animationen på en sådan måde, at du kan definere flere animationer med forskellige tidspunkter og overgange. Post dette, API integrerer simpelthen alle animationerne i en problemfri oplevelse.
lad os sige, at vi vil flytte vores knap på skærmen på en tilfældig måde. Lad os se, hvordan vi kan bruge keyframe animation API til at gøre det.
UIView.animateKeyframes(withDuration: 5, //1 delay: 0, //2 options: .calculationModeLinear, //3 animations: { //4 UIView.addKeyframe( //5 withRelativeStartTime: 0.25, //6 relativeDuration: 0.25) { //7 self.button.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.maxY) //8 } UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.25) { self.button.center = CGPoint(x: self.view.bounds.width, y: start.y) } UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) { self.button.center = start }})
Her er opdelingen:
-
duration
Ring API ‘ en ved at passere i animationens varighed. - Initial forsinkelse varighed af animationen.
-
options
den type animationskurve, du vil anvende til din visningsanimation. animations
blok, der tager alle keyframe animationer designet af udvikleren / brugeren.addKeyFrame
ring til API ‘ en for at designe hver eneste animation. I vores tilfælde har vi defineret hvert træk på knappen. Vi kan have så mange sådanne animationer, som vi har brug for, tilføjet til blokken.-
relativeStartTime
definerer starttidspunktet for animationen i samlingen af animationsblokken. -
relativeDuration
definerer den samlede varighed af denne specifikke animation. -
center
i vores tilfælde ændrer vi simpelthen midteregenskaben på knappen for at flytte knappen rundt på skærmen.
og Sådan ser de endelige animationer ud:
CoreAnimation
enhver UIKit-baseret animation oversættes internt til kerneanimationer. Således fungerer Kerneanimationsrammen som et baglag eller rygrad for enhver UIKit-animation. Derfor er alle UIKit animation API ‘er intet andet end indkapslede lag af core animation API’ er på en let forbrugsstof eller praktisk måde.
UIKit animation API ‘ er giver ikke meget kontrol over animationer, der er blevet udført over en visning, da de bruges mest til animatable egenskaber af visningen. Derfor i sådanne tilfælde, hvor du har til hensigt at have kontrol over hver ramme af animationen, er det bedre at bruge de underliggende core animation API ‘ er direkte. Alternativt kan både uivevisningsanimationer og kerneanimationer også bruges sammen.
Uivvisning + Kerneanimation
lad os se, hvordan vi kan genskabe den samme knapændringsanimation sammen med at specificere timingkurven ved hjælp af Uivvisning og Core Animation API ‘ er.
Vi kan bruge CATransaction
‘s timingfunktioner, som lader dig angive og styre animationskurven.
lad os se på et eksempel på en knapstørrelsesændringsanimation med dens hjørneradius ved hjælp af CATransaction
‘s timingfunktion og en kombination af uivevisningsanimationer:
let oldValue = button.frame.width/2let newButtonWidth: CGFloat = 60/* Do Animations */CATransaction.begin() //1CATransaction.setAnimationDuration(2.0) //2CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)) //3// View animations //4UIView.animate(withDuration: 1.0) { self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center}// Layer animationslet cornerAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.cornerRadius)) //5cornerAnimation.fromValue = oldValue //6cornerAnimation.toValue = newButtonWidth/2 //7button.layer.cornerRadius = newButtonWidth/2 //8button.layer.add(cornerAnimation, forKey: #keyPath(CALayer.cornerRadius)) //9CATransaction.commit() //10
Her er opdelingen:
begin
repræsenterer starten af animationskodeblokken.-
duration
samlet animationsvarighed. -
curve
repræsenterer den timingkurve, der skal anvendes til animationen. -
UIView.animate
vores første animation til at ændre rammen på knappen. -
CABasicAnimation
Vi opretterCABasicAnimation
objektet ved at henvisecornerRadius
af knappen som tastatur, da det er det, vi vil animere. Tilsvarende, hvis du vil have granulær niveaukontrol over keyframe-animationerne, kan du brugeCAKeyframeAnimation
klasse. -
fromValue
repræsenterer startværdien af animationen, dvs.den oprindeligecornerRadius
værdien af knappen, hvorfra animationen skal starte. -
toValue
repræsenterer den endelige værdi af animationen, dvs.den endeligecornerRadius
værdien af knappen, hvor animationen skal slutte. cornerRadius
vi skal indstillecornerRadius
egenskaben for knappen med den endelige værdi af animationen ellers bliver knappens hjørneradius-værdi automatisk vendt tilbage til dens oprindelige værdi, når animationen er afsluttet.addAnimation
vi vedhæfter animationsobjektet, der indeholder konfigurationen af hele animationsprocessen til laget ved at repræsentere den Tastatursti, som animationen skal udføres for.-
commit
repræsenterer slutningen af animationskodeblokken og starter animationen.
Sådan ser den endelige animation ud:
denne blog er en god læsning for at hjælpe med at skabe mere avancerede animationer, da den pænt fører dig gennem de fleste af de centrale animationsrammer API ‘ er med instruktioner, der guider dig til at gennem hvert skridt på vejen.
UIKitDynamics
UIKit Dynamics er fysikmotoren til UIKit, som giver dig mulighed for at tilføje enhver fysikadfærd som kollision, tyngdekraft, push, snap osv.
UIKitDynamicAnimator
Dette er admin klassen af UIKit Dynamics rammer, der regulerer alle animationer udløst af en given UI kontrol.
UIKitDynamicBehavior
det giver dig mulighed for at tilføje enhver fysik adfærd til en animator, som derefter gør det muligt at udføre på visningen knyttet til det.
forskellige former for adfærd for UIKitDynamics omfatter:
UIAttachmentBehavior
UICollisionBehavior
UIFieldBehavior
UIGravityBehavior
UIPushBehavior
UISnapBehavior
arkitekturen i uikitdynamics ser sådan ud. Bemærk, at elementer 1 til 5 kan erstattes med en enkelt visning.
lad os anvende nogle fysiske adfærd på vores knap. Vi vil se, hvordan man anvender tyngdekraften på knappen, så den giver os en følelse af at håndtere et rigtigt objekt.
var dynamicAnimator : UIDynamicAnimator!var gravityBehavior : UIGravityBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: ) //2dynamicAnimator.addBehavior(gravityBehavior) //3
Her er opdelingen:
UIKitDynamicAnimator
vi har oprettet etUIKitDynamicAnimator
objekt, der fungerer som en orkestrator til udførelse af animationer. Vi har også bestået overvågningen af vores knap som Referencevisning.-
UIGravityBehavior
vi har oprettet etUIGravityBehavior
objekt og send vores knap ind i arrayelementerne, som denne adfærd injiceres på. addBehavior
vi har tilføjet tyngdekraftobjektet til animatoren.
dette bør skabe en animation som vist nedenfor:
vi skal fortælle animatoren at betragte bunden af skærmen som jorden. Det er her
UICollisionBehavior
kommer ind i billedet.var dynamicAnimator : UIDynamicAnimator!var gravityBehavior : UIGravityBehavior!var collisionBehavior : UICollisionBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: ) //2dynamicAnimator.addBehavior(gravityBehavior) //3collisionBehavior = UICollisionBehavior(items: ) //4collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5dynamicAnimator.addBehavior(collisionBehavior) //6
UICollisionBehavior
vi har oprettet enUICollisionBehavior
objekt og passeret langs knappen, så adfærden tilføjes til elementet.translatesReferenceBoundsIntoBoundary
aktivering af denne egenskab fortæller animatoren at tage referencevisningsgrænsen som slutningen, som er bunden af skærmen i vores tilfælde.-
addBehavior
vi har tilføjet kollisionsadfærd til animatoren her.
nu skal vores knap ramme jorden og stå stille som vist nedenfor:
Det er ret pænt, er det ikke?
Lad os nu prøve at tilføje en hoppende effekt, så vores objekt føles mere reelt. For at gøre det bruger viUIDynamicItemBehavior
klasse.var dynamicAnimator : UIDynamicAnimator!var gravityBehavior : UIGravityBehavior!var collisionBehavior : UICollisionBehavior!var bouncingBehavior : UIDynamicItemBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: ) //2dynamicAnimator.addBehavior(gravityBehavior) //3collisionBehavior = UICollisionBehavior(items: ) //4collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5dynamicAnimator.addBehavior(collisionBehavior) //6//Adding the bounce effectbouncingBehavior = UIDynamicItemBehavior(items: ) //7bouncingBehavior.elasticity = 0.75 //8dynamicAnimator.addBehavior(bouncingBehavior) //9
UIDynamicItemBehavior
vi har oprettet enUIDynamicItemBehavior
objekt og passere langs knappen, så adfærden tilføjes til elementet.elasticity
værdien skal være mellem 0-1, den repræsenterer elasticiteten, dvs.antallet af gange objektet skal hoppe på og fra jorden, når det rammes. Det er her magien sker – ved at tilpasse denne egenskab kan du skelne mellem forskellige slags genstande som bolde, flasker, hårde genstande og så videre.-
addBehavior
vi har tilføjet kollisionsadfærd til animatoren her.
nu skal vores knap hoppe, når den rammer jorden som vist nedenfor:
denne repo er ganske nyttig og viser alle uikitdynamics adfærd i aktion. Det giver også kildekode til at lege med hver adfærd. Det skal efter min mening tjene som en omfattende liste over måder at udføre iOS-animationer på visninger!
i det næste afsnit vil vi tage et kort kig på de værktøjer, der hjælper os med at måle animationernes ydeevne. Jeg vil også anbefale dig at se på måder at optimere din Kodeopbygning på, da det sparer en enorm mængde af din udviklingstid.
Performance Tuning
i dette afsnit vil vi se på måder at måle og indstille ydeevnen på iOS-animationer. Som iOS-udvikler har du muligvis allerede brugt Kodeinstrumenter som hukommelseslækager og tildelinger til måling af ydeevnen for den samlede app. Tilsvarende er der instrumenter, der kan bruges til at måle udførelsen af animationer.
Core Animation
Instrument
prøvCore Animation
instrumentet, og du skal kunne se den FPS, som din appskærm leverer. Dette er en fantastisk måde at måle ydeevnen/ hastigheden på enhver animation, der gengives i din iOS-app.
tegning
FPS sænkes kraftigt i appen, der viser tungt indhold som billeder med effekter som skygger. I sådanne tilfælde, i stedet for at tildele billedet direkte til UIImageView
‘s billedegenskab, prøv at tegne billedet separat i en sammenhæng ved hjælp af Core Graphics API’ er. Dette reducerer alt for billedvisningstiden ved at udføre billeddekompressionslogikken asynkront, når den udføres i en separat tråd i stedet for hovedtråden.
rasterisering
rasterisering er en proces, der bruges til at cache komplekse lagoplysninger, så disse visninger ikke tegnes igen, når de gengives. Gentegning af synspunkter er hovedårsagen til reduktionen i FPS, og det er derfor bedst at anvende rasterisering på visninger, der skal genbruges flere gange.
indpakning
for at konkludere har jeg også opsummeret en liste over nyttige ressourcer til iOS-animationer. Du kan finde dette meget praktisk, når du arbejder på iOS-animationer. Derudover kan du også finde dette sæt designværktøjer nyttige som et (design) trin, før du går ned i animationer.