utföra iOS-animationer på vyer med UIKit och UIView
- om författaren
- animera vid 60FPS
- Core Frameworks
- UIKit / UIView animationer
- animering (withDuration: animations: completion)
- animateWithDuration
- UIViewPropertyAnimator
- Vad är en frame?
- animateKeyframes
- CoreAnimation
- UIView + Core Animation
- UIKitDynamics
- UIKitDynamicAnimator
- UIKitDynamicBehavior
- Performance Tuning
- Core Animation Instrument
- ritning
- rasterisering
- Wrapping Up
om författaren
Saravanan är en iOS-ingenjör och författare på flexiple och Remote Tools. Han har arbetat med flera startups över olika domäner.Mer aboutSaravanan brasilian
- 14 min läs
- Animation,iOS,UI,mobil
- sparas för offline läsning
- Dela på Twitter, LinkedIn
jag har varit en iOS-utvecklare i över ett decennium nu och har sällan sett artiklar som konsoliderar alla möjliga sätt att utföra animationer i iOS. Den här artikeln syftar till att vara en primer på iOS-animationer med avsikt att uttömmande täcka de olika sätten att göra detsamma.
Med tanke på ämnets omfattning skulle vi täcka varje del kortfattat på en ganska hög nivå. Målet är att utbilda läsaren med en uppsättning val för att lägga till animationer i hans/ hennes iOS-app.
innan vi börjar med ämnen relaterade till iOS, låt oss ta en kort titt på animationshastigheten.
animera vid 60FPS
i allmänhet i Videor representeras varje bildruta av en bild och bildhastigheten bestämmer antalet bilder som vänds i sekvensen. Detta kallas ’ramar per sekund’ eller FPS.
FPS bestämmer antalet stillbilder som vänds inom en sekund, vilket bokstavligen betyder att ju mer antalet bilder/ ramar, mer information/ information visas i videon. Detta gäller även för animationer.
FPS används vanligtvis för att bestämma kvaliteten på animeringar. Det finns en populär åsikt att någon bra animering ska köras på 60fps eller högre — något mindre än 60fps skulle känna sig lite av.
vill du se skillnaden mellan 30FPS och 60FPS? Kolla här!
märkte du skillnaden? Mänskliga ögon kan definitivt känna jitteren vid lägre fps. Därför är det alltid en bra praxis att se till att alla animeringar du skapar följer grundregeln för att köra på 60 fps eller högre. Detta gör att det känns mer realistiskt och levande.
Efter att ha tittat på FPS, låt oss nu dyka in i de olika kärn iOS-ramarna som ger oss ett sätt att utföra animationer.
Core Frameworks
i det här avsnittet kommer vi att beröra ramarna i iOS SDK som kan användas för att skapa visningsanimationer. Vi kommer att göra en snabb promenad genom var och en av dem och förklara deras funktionsuppsättning med ett relevant exempel.
UIKit / UIView animationer
UIView är basklassen för alla vyer som visar innehåll i iOS-appar.
UIKit, ramverket som ger oss UIView, ger oss redan några grundläggande animeringsfunktioner som gör det bekvämt för utvecklare att uppnå mer genom att göra mindre.
API,UIView.animate
, är det enklaste sättet att animera vyer eftersom alla vyers egenskaper enkelt kan animeras genom att tillhandahålla egenskapsvärdena i den blockbaserade syntaxen.
i UIKit-animationer rekommenderas att endast ändra de animerbara egenskaperna hos UIVIew, annars kommer det att bli konsekvenser där animationerna kan få vyn att hamna i ett oväntat tillstånd.
animering (withDuration: animations: completion)
den här metoden tar in animeringstiden, en uppsättning visningsändringar som kan animeras som måste animeras. Kompletteringsblocket ger en återuppringning när vyn är klar med att utföra animeringen.
nästan alla typer av animationer som att flytta, skala, rotera, blekna, etc. på en vy kan uppnås med denna enda API.
Tänk nu på att du vill animera en knappstorleksändring eller om du vill att en viss vy ska zooma in på skärmen. Så här kan vi göra det med 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}
Här är vad vi gör här:
- vi kallar
UIView.animate
– metoden med ett varaktighetsvärde som skickas till det som representerar hur länge animationen, som beskrivs inuti blocket, ska köras. - vi ställer in den nya ramen på knappen som ska representera animationens slutliga tillstånd.
- vi ställer in knappen
center
med dess superviews centrum så att den förblir i mitten av skärmen.
ovanstående block av animeringskod bör utlösa animeringen av knappens ram som ändras från aktuell ram:
Width = 0, Height = 0
till den slutliga ramen:
Width = Height = newButtonWidth
och här är hur animationen skulle se ut:
animateWithDuration
den här metoden är som en förlängning av animate-metoden där du kan göra allt du kan utföra i det tidigare API med vissa fysikbeteenden som läggs till i visningsanimationerna.
om du till exempel vill uppnå fjäderdämpningseffekter i animationen som vi har gjort ovan, så är det så här koden skulle se ut:
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)
här är uppsättningen parametrar vi använder:
-
duration
representerar varaktigheten för animationen som bestämmer hur länge kodblocket ska köras. -
delay
representerar den initiala förseningen som vi vill ha innan animeringen börjar. -
SpringWithDamping
representerar värdet på den fjädrande effekten som vi vill att vyn ska fungera. Värdet måste vara mellan 0 och 1. Ju lägre värde desto högre fjäderoscillation. -
velocity
representerar den hastighet med vilken animeringen ska starta. -
options
typ av animeringskurva som du vill använda för din visningsanimering. - slutligen, kodblocket där vi ställer in ramen för knappen som måste animeras. Det är detsamma som den tidigare animationen.
och här är hur animationen skulle se ut med ovanstående animationskonfiguration:
UIViewPropertyAnimator
för lite mer kontroll över animationer, UIViewPropertyAnimator
kommer praktiskt där det ger oss ett sätt att pausa och återuppta animationer. Du kan ha Anpassad timing och få din animering att vara interaktiv och avbrytbar. Detta är till stor hjälp när du utför animationer som också kan interagera med användaråtgärder.
den klassiska ’Slide to Unlock’ – gesten och spelarvyn avvisa / expandera animering (i musikappen) är exempel på interaktiva och avbrytbara animationer. Du kan börja flytta en vy med fingret, sedan släppa den och vyn kommer att gå tillbaka till sin ursprungliga position. Alternativt kan du fånga vyn under animeringen och fortsätta dra den med fingret.
Följande är ett enkelt exempel på hur vi kan uppnå animationen med 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
Här är vad vi gör:
- vi kallar
UIViewProperty
API genom att skicka varaktigheten och animeringskurvan. - till skillnad från båda ovanstående UIView.animera API: er, animeringen startar inte om du inte anger det själv, dvs du har full kontroll över hela animeringsprocessen/ flödet.
låt oss nu säga att du vill ha ännu mer kontroll över animationerna. Du vill till exempel designa och styra varje bildruta i animeringen. Det finns ett annat API för det, animateKeyframes
. Men innan vi dyker in i det, låt oss snabbt titta på vad en ram är, i en animering.
Vad är en frame
?
en samling av vyens ramändringar/övergångar, från starttillstånd till slutläge, definieras som animation
och varje position i vyn under animeringen kallas som ett frame
.
animateKeyframes
detta API ger ett sätt att utforma animeringen på ett sådant sätt att du kan definiera flera animationer med olika tidpunkter och övergångar. Lägg upp detta, API integrerar helt enkelt alla animationer i en sömlös upplevelse.
låt oss säga att vi vill flytta vår knapp på skärmen på ett slumpmässigt sätt. Låt oss se hur vi kan använda keyframe animation API för att göra 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 }})
här är uppdelningen:
-
duration
Ring API genom att passera under animationens varaktighet. -
delay
Initial fördröjning varaktighet animeringen. -
options
den typ av animeringskurva som du vill använda för din visningsanimering. -
animations
Block som tar alla nyckelbildsanimationer designade av utvecklaren / användaren. -
addKeyFrame
Ring API för att designa varje animering. I vårt fall har vi definierat varje drag på knappen. Vi kan ha så många sådana animationer som vi behöver, läggs till i blocket. -
relativeStartTime
definierar starttiden för animationen i samlingen av animeringsblocket. -
relativeDuration
definierar den totala varaktigheten för denna specifika animering. -
center
i vårt fall ändrar vi helt enkelt knappens mittfunktion för att flytta knappen runt skärmen.
och så här ser de slutliga animationerna ut:
CoreAnimation
alla UIKit-baserade animeringar översätts internt till kärnanimationer. Således fungerar Core Animation framework som ett stödlager eller ryggrad för alla UIKit-animeringar. Därför är alla UIKit animation API: er ingenting annat än inkapslade lager av core animation API: er på ett lätt förbrukningsbart eller bekvämt sätt.
UIKit animation API: er ger inte mycket kontroll över animationer som har utförts över en vy eftersom de används mest för animerbara egenskaper i vyn. I sådana fall, där du tänker ha kontroll över varje bildruta i animationen, är det därför bättre att använda de underliggande API: erna för kärnanimering direkt. Alternativt kan både UIView-animationerna och kärnanimationerna användas tillsammans.
UIView + Core Animation
Låt oss se hur vi kan återskapa samma knappändringsanimering tillsammans med att ange tidskurvan med UIView och Core Animation API: er.
Vi kan använda CATransaction
tidsfunktioner, som låter dig ange och styra animeringskurvan.
Låt oss titta på ett exempel på en animering av knappstorlek med dess hörnradie som använderCATransaction
s timingfunktion och en kombination av UIView-animationer:
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
här är uppdelningen:
-
begin
representerar starten på animeringskodblocket. -
duration
Total animeringstid. -
curve
representerar tidskurvan som måste tillämpas på animeringen. -
UIView.animate
vår första animering för att ändra knappens ram. -
CABasicAnimation
vi skaparCABasicAnimation
objektet genom att hänvisa tillcornerRadius
på knappen som knappsöm eftersom det är vad vi vill animera. På samma sätt, om du vill ha granulär nivåkontroll över nyckelbildsanimationerna, kan du använda klassenCAKeyframeAnimation
. -
fromValue
representerar startvärdet för animationen, dvs det initialacornerRadius
värdet på knappen från vilken animationen måste börja. -
toValue
representerar animationens slutliga värde, dvs det slutligacornerRadius
värdet på knappen där animationen måste avslutas. -
cornerRadius
vi måste ställa in egenskapencornerRadius
för knappen med det slutliga värdet av animeringen annars kommer knappens hörnradius-värde automatiskt att återgå till sitt ursprungliga värde efter att animeringen är klar. -
addAnimation
vi bifogar animationsobjektet som innehåller konfigurationen av hela animeringsprocessen till skiktet genom att representera den knappsats för vilken animationen behöver utföras. -
commit
representerar slutet på animeringskodblocket och startar animeringen.
så här skulle den slutliga animationen se ut:
den här bloggen är en bra läsning för att hjälpa till att skapa mer avancerade animationer eftersom det snyggt går igenom de flesta API: erna för Kärnanimering med instruktioner som guidar dig genom varje steg på vägen.
UIKitDynamics
UIKit Dynamics är fysikmotorn för UIKit som gör att du kan lägga till några fysikbeteenden som kollision, gravitation, push, snap, etc, till UIKit-kontrollerna.
UIKitDynamicAnimator
detta är administratörsklassen i UIKit Dynamics framework som reglerar alla animeringar som utlöses av en viss UI-kontroll.
UIKitDynamicBehavior
det gör att du kan lägga till något fysikbeteende till en animatör som sedan gör det möjligt att utföra den vy som är kopplad till den.
olika typer av beteenden för Uikitdynamik inkluderar:
UIAttachmentBehavior
UICollisionBehavior
UIFieldBehavior
UIGravityBehavior
UIPushBehavior
UISnapBehavior
uikitdynamics arkitektur ser ut så här. Observera att Objekt 1 till 5 kan ersättas med en enda vy.
Låt oss tillämpa lite fysikbeteende på vår knapp. Vi kommer att se hur man applicerar gravitation på knappen så att den ger oss en känsla av att hantera ett verkligt objekt.
var dynamicAnimator : UIDynamicAnimator!var gravityBehavior : UIGravityBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: ) //2dynamicAnimator.addBehavior(gravityBehavior) //3
här är uppdelningen:
-
UIKitDynamicAnimator
vi har skapat ettUIKitDynamicAnimator
objekt som fungerar som en orkestrator för att utföra animationer. Vi har också passerat övervakningen av vår knapp som referensvy. -
UIGravityBehavior
vi har skapat ettUIGravityBehavior
objekt och skickar vår knapp till de arrayelement som detta beteende injiceras på. -
addBehavior
vi har lagt till gravitationsobjektet till animatören.
detta bör skapa en animering som visas nedan:
vi bör berätta för animatören att betrakta skärmens botten som marken. Det är här
UICollisionBehavior
kommer in i bilden.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 skapat ettUICollisionBehavior
objekt och passerade längs knappen så att beteendet läggs till elementet. -
translatesReferenceBoundsIntoBoundary
aktivera den här egenskapen berättar animatorn att ta referensvyns gräns som slutet, vilket är botten av skärmen i vårt fall. -
addBehavior
Vi har lagt till kollisionsbeteende till animatören här.nu ska vår knapp slå marken och stå still som visas nedan:
det är ganska snyggt, eller hur?låt oss nu försöka lägga till en studsande effekt så att vårt objekt känns mer verkligt. För att göra det kommer vi att använda klassen
UIDynamicItemBehavior
.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 skapat ettUIDynamicItemBehavior
objekt och passera längs knappen så att beteendet läggs till elementet. -
elasticity
värdet måste vara mellan 0-1, det representerar elasticiteten, dvs antalet gånger objektet måste studsa på och av marken när det träffas. Det är här magin händer-genom att justera den här egenskapen kan du skilja mellan olika typer av föremål som bollar, flaskor, hårda föremål och så vidare. -
addBehavior
Vi har lagt till kollisionsbeteende till animatören här.
nu ska vår knapp studsa när den träffar marken som visas nedan:
denna repo är ganska användbar och visar alla uikitdynamics beteenden i aktion. Det ger också källkod för att leka med varje beteende. Det borde enligt min mening fungera som en omfattande lista över sätt att utföra iOS-animationer på visningar!
i nästa avsnitt kommer vi att ta en kort titt på verktygen som hjälper oss att mäta animationernas prestanda. Jag skulle också rekommendera dig att titta på sätt att optimera din Xcode-byggnad eftersom det kommer att spara en stor del av din utvecklingstid.
Performance Tuning
i det här avsnittet kommer vi att titta på sätt att mäta och ställa in prestanda för iOS-animationer. Som iOS-utvecklare kanske du redan har använt Xcode-instrument som minnesläckor och allokeringar för att mäta prestanda för den övergripande appen. På samma sätt finns det instrument som kan användas för att mäta animationernas prestanda.
Core Animation
Instrument
prova instrumentetCore Animation
och du bör kunna se FPS som din appskärm levererar. Detta är ett utmärkt sätt att mäta prestanda/ hastighet för alla animeringar som gjorts i din iOS-app.
ritning
FPS sänks kraftigt i appen som visar tungt innehåll som bilder med effekter som skuggor. I sådana fall, istället för att tilldela bilden direkt till UIImageView
s bildegenskap, försök att rita bilden separat i ett sammanhang med hjälp av Core Graphics API: er. Detta minskar alltför bildvisningstiden genom att utföra bilddekompressionslogiken asynkront när den görs i en separat tråd istället för huvudtråden.
rasterisering
rasterisering är en process som används för att cacha komplex lagerinformation så att dessa vyer inte ritas om när de återges. Omritning av vyer är den främsta orsaken till minskningen av FPS och därför är det bäst att tillämpa rasterisering på vyer som kommer att återanvändas flera gånger.
Wrapping Up
avslutningsvis har jag också sammanfattat en lista över användbara resurser för iOS-animationer. Du kan hitta det här mycket praktiskt när du arbetar med iOS-animationer. Dessutom kan du också hitta den här uppsättningen designverktyg som är användbara som ett (design) steg innan du går in i animationer.