Articles

utföra iOS-animationer på vyer med UIKit och UIView

  • 14 min läs
  • Animation,iOS,UI,mobil
  • sparas för offline läsning
  • Dela på Twitter, LinkedIn

denna artikel syftar till att vara en primer på iOS animationer uttömmande täcker olika sätt att göra det. Vi börjar med att förstå grunderna i animationer, flytta till Kärnramarna och bygga ett enda exempel med de olika metoderna som erbjuds och slutligen titta på sätt att ställa in Prestanda.

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:

  1. vi kallarUIView.animate – metoden med ett varaktighetsvärde som skickas till det som representerar hur länge animationen, som beskrivs inuti blocket, ska köras.
  2. vi ställer in den nya ramen på knappen som ska representera animationens slutliga tillstånd.
  3. 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:

  1. duration
    representerar varaktigheten för animationen som bestämmer hur länge kodblocket ska köras.
  2. delay
    representerar den initiala förseningen som vi vill ha innan animeringen börjar.
  3. 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.
  4. velocity
    representerar den hastighet med vilken animeringen ska starta.
  5. options
    typ av animeringskurva som du vill använda för din visningsanimering.
  6. 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:

  1. vi kallarUIViewProperty API genom att skicka varaktigheten och animeringskurvan.
  2. 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:

  1. duration
    Ring API genom att passera under animationens varaktighet.
  2. delay
    Initial fördröjning varaktighet animeringen.
  3. options
    den typ av animeringskurva som du vill använda för din visningsanimering.
  4. animations
    Block som tar alla nyckelbildsanimationer designade av utvecklaren / användaren.
  5. 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.
  6. relativeStartTime
    definierar starttiden för animationen i samlingen av animeringsblocket.
  7. relativeDuration
    definierar den totala varaktigheten för denna specifika animering.
  8. 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 CATransactiontidsfunktioner, 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änderCATransactions 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:

  1. begin
    representerar starten på animeringskodblocket.
  2. duration
    Total animeringstid.
  3. curve
    representerar tidskurvan som måste tillämpas på animeringen.
  4. UIView.animate
    vår första animering för att ändra knappens ram.
  5. 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 klassen CAKeyframeAnimation.
  6. fromValue
    representerar startvärdet för animationen, dvs det initialacornerRadius värdet på knappen från vilken animationen måste börja.
  7. toValue
    representerar animationens slutliga värde, dvs det slutligacornerRadius värdet på knappen där animationen måste avslutas.
  8. 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.
  9. 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.
  10. 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:

  1. 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.
  2. UIGravityBehavior
    vi har skapat ett UIGravityBehavior objekt och skickar vår knapp till de arrayelement som detta beteende injiceras på.
  3. addBehavior
    vi har lagt till gravitationsobjektet till animatören.
    detta bör skapa en animering som visas nedan:
    Lägg märke till hur knappen faller från mitten (dess ursprungliga position) på skärmen till botten och bortom.

    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
  4. UICollisionBehavior
    vi har skapat ett UICollisionBehavior objekt och passerade längs knappen så att beteendet läggs till elementet.
  5. 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.
  6. 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
  7. UIDynamicItemBehavior
    vi har skapat ett UIDynamicItemBehavior objekt och passera längs knappen så att beteendet läggs till elementet.
  8. 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.
  9. 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 UIImageViews 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.