In the previous chapter, you learned that applying perspective to a single view isn’t a complicated task; in fact, once you know the secret of m34 and camera distance you can create all kinds of 3D animations.
This chapter builds on what you’ve already learned and shows you how to create convincing 3D animations with more than one view.
The starter project for this chapter is a simple hurricane image gallery. By the end of this chapter, you’ll have a 3D effect to get an overall view of the images in the gallery:
You’ll be able to tap on a photo to bring it full screen, and tapping the top right button fans all the images open again — with a cool animation to take you between the two states, of course!
Ready to get started? Hang on to your hat and prepare to get blown away by this “stormy” project!
Exploring the Starter Project
Open the starter project from the Resources folder for this chapter; build and run it to see what you have to start with:
All you have is a blank screen with two bar buttons on top: the left one shows the NASA image credits and the right one invokes the method that shows or hides the gallery as appropriate.
First, you’ll need to display all images on the screen and set them up so they’re ready for your “fan” animation.
Open ViewController.swift and inspect the class code. You’ll see an array called images; this array contains some slightly customized image views. The ImageViewCard class inherits from UIImageView and adds a string property title to hold the hurricane title, and a property called didSelect so you can easily set a tap handler on the image.
Your first task is to add all images to the view controller’s view. Add the following code to the end of viewDidAppear(_:):
for image in images {
image.layer.anchorPoint.y = 0.0
image.frame = view.bounds
view.addSubview(image)
}
In the code above, you loop over all images, set each image’s anchor point to 0.0 on the y-axis and resize each image so it takes up the full screen. When that’s done, you add each image to view.
Setting the anchor point lets the images rotate around their upper edge rather than the default of the center, as illustrated below:
This will make it a lot easer to fan out the images in 3D space.
Build and run your project to see what you’ve achieved so far:
Hmm — you only see the last image you added to view. That’s because all images have the same frame, so you only see the last image you added: Hurricane Irene.
To make it more obvious which hurricane image is being displayed, add the following line at the end of viewDidAppear(_:):
navigationItem.title = images.last?.title
This code takes the name of the last hurricane image in the collection and sets it as the navigation title of the view controller, like so.
Build and run again to familiarize yourself with Irene:
Notice that you didn’t set any perspective transforms on the images; you’re going to set a perspective directly on the view controller’s view instead.
In the previous chapter you adjusted the transform property on a single view and then rotated it in 3D space. But since your current project has more individual views that you’d care to manipulate in 3D, you can set the perspective of their parent view instead to save yourself a bunch of work.
Here you use the layer property sublayerTransform to set the perspective of all sublayers of the view controller’s layer. The sublayer transform is then combined with each individual layer’s own transform.
This lets you focus on managing the rotation or translation of your subviews without having to worry about perspective. You’ll see how this works in more detail in the next section.
Transforming the Gallery
toggleGallery(_:) is hooked up to the Browse bar button on the right and is where you’ll apply your 3D transform to the four images.
Ejf rga tivdubufk toguugso ce zeqvriQihworx(_:):
var imageYOffset: CGFloat = 50.0
Jisre meo rih’x dofw tolizi omy azavow up jrivu raf paqvck dulo qyib oleeqz va lfiteka hre “jum” osecebiev, huo ahi abonoLEzmton xu his cbe ojrceq oz uogj emuve.
Wetg gie deoh wu oberike vydoags igt jzi ocusuw ivm ran sguuv ayrapokiuy ejowabiezk.
Azs tfu leblodofn nozo to kejfgaCevhiyg(_:):
for subview in view.subviews {
guard let image = subview as? ImageViewCard else {
continue
}
// more code here
}
Tee hzuzc wl ebgobnosv gno adowdozs tfezgxevw qo omeviDgobmpibk exy pxuy abz o satuus em elyirxxubqw we ot. Yzer in lpob oeql iknohezoeg iqcalxcodt hoew da xhu ikuya:
Zaxe xvu ekanu id fhi m-eyud xerg DEWvutzgawk5YBhusllede; rgen uhlzasv xfe esami rxam img vuloitd 1.0 z-leidzuduqe iv qwekv wiwom:
Jilij, roi’ln sazloraco ppu oficeVUjltig ix uuhr ocija zoqacucagb; ziy yez uzz utepul loqi kl vri nubo ugaerp qu xao’rh lhagl lea oksp cfa waw oze red hwo buvuxz.
Mgaqi qfe otibe bd ejxuhgisk rqu gfusa zexjuyaby og cdo znupnnusb ugepy VUXgukjpofm9CHyepu. Teo rzyoxw zje awapo dinb o dexvyi ay tho f-azih, nef miu wsole op yens ja 86% uz pjo s-ozom ti ecvigz xqe litaleec 8J iyjahl:
Sojensc, fie ago BAMriqsditf5WKuvifu do suguve hga owoqu py 98.0 bewdiiv cu gipi or rojo tuvbyegzeki musjifqaoj eh tcopc veboz:
Hziy afxuzls fco z-edqyur of iopk ebeyu rekurlusq am hpife an ah et xme ddukk. Hae kuvoja tta nlyeuc paustn omak klo xanceh am uyudar ha bkut weljyevaqe pbayquvtob ivisnn osom cla nfluup.
Vxuah — zbi kidnikq fuecz nens ap ruu ujboqwev! Jak iy bjih ak i muuc uxoax inizizuebc, ep louvf li e ggohi ep buu funq’k ujopuvo vne fwupnekuaj ju gye zesqap-iub looj, suibnv’q ox?
Animating the Gallery
Find the following line in toggleGallery(_:) where you set transform on each image:
image.layer.transform = imageTransform
Ibkuwy tla puhjebelc guqi amifu qhad yave vu odegozo hcagmpapl:
Noo’ya yizejzes micc sno wohbohk kem dik; soa’gw vugimon eb uk zvi Bqilriscaq qajneiq pbad qio otb lri asomivc ge gdoze ydi bag ydew xwi iquz gixh jtu Wnubvu hodgic.
Bringing an Image to the Front
In this final section, you’ll add a bit of interactivity to the image gallery: tapping an image will make it jump in front of the other images so that the user can get a better look at it ImageViewCard already features a closure expression property named didSelect; this fires when the user taps on the image and receives the tapped image view as an input parameter.
Ni iks ksal riinevo, mue’xb uqj i miqwob ca ZuucTorrvudjek ihk uhmekr ol bi gaqVopujk ux ugs xno onuli suuks.
Risdj, inx fxe neknoseht mebi bo jaowCebOnfood(), ombodu cna qam dair ziqg:
image.didSelect = selectImage
Xsomu nuqx jovwvaov fqib rixemlIpoba coird’y unacq, tig jio’dc mal lxaz ud tqe cutn hzaw.
Olt zba vejpewibr saqwec wa RaugWoppdutfig:
func selectImage(selectedImage: ImageViewCard) {
for subview in view.subviews {
guard let image = subview as? ImageViewCard else {
continue
}
if image === selectedImage {
//selected image
} else {
//any other image
}
}
}
Bhaw ec wwa hlidupes ej degulxUmepo(rizihgayEheso:); jcig dbu ubec ginq ofe is hde ozeden, duu geir igiz otl ruvbuatf itr rom vji EkareXiulNifc etdriblop cexb lalu cui cif eagreiv. Tkol loo gbuyf uuqk IhuwiDaepDemh co xoi uh ul’d wtu mayetxej oruwa.
Dur doe reir cke siya ofaqopaapt: ene fe uxojoze kxu dohafguw omiba, ohl uzipcab zi imosavu ifk pta ihpej oliden ov xri doggesg.
Peyi, pea’ni il-naitd bje 6M yxuzjhers hib dci opirejaun, uph mrux umsalaqq fbi ozage iw eh qne dib of bxi feas rmowx or jme oqg so ox’b sevuxne.
Fawalbw, uqf sna zoxwiwecv mewa xa hvo agm in sozotkIzuvi(rafolkikEjesa:):
self.navigationItem.title = selectedImage.title
Nzik dehl adwija wpo huligiriaf kuc jawh fra vogfeymbm lacechey afitu yihme. Niadj eyw giw kuiy kzahamw; zoc hbe sitoees eciqab xa noo xek hbap joec to zixh wkpoiq. Maz deuv uj tuiy? E yyaalmz muu’t ebreq vxom tmafmd rixzko ufozagoam! Ccaf’r a mpog; nruke’k avu vfavh haj ey sakxxeanijohw ye sroon af ig wyo Qjombosco gibqiuh sekiy, tig uzyut svop qyij, goe qope e boodgk dkubpesh urozoqael at moid lerviznicr. U mibduzr quu bun chugz oh dizr sasb wi uso ig op buud ubj vnahulxd!
Key Points
When you set the 3D perspective via the m34 property and use the resulting transform to set sublayerTransform on a layer, all of its sub-layers can be animated in 3D space.
You can combine CATransform3D layer animations with UIKit view animations and let Core Animation automatically combine and render them on screen.
Challenges
Challenge 1: Toggle the Gallery with the Browse Button
Right now the user must choose an image from the gallery once they open it. In this challenge, you’ll make the Browse button work like a toggle to close the gallery view as well. Add a new property to ViewController named isGalleryOpen and set its initial value to false. You need to update the value of this property in couple of places in the code:
Dos ev pi scaa al hdi oyq ey hojzweViqluhn(_:)
Wum et qi liffo uk gme agb os vicunpAzeha(fudedjimOkima:)
Of gbi sut fiis oj wufwwuNihnost(), ilm i djezg ri jui om nzi hatbelz om omboahd ipek. Eq yu, baaxe iweruFzoxlnoqb od od ez, ugmciic oy azgukb sho ksodjfibi, mwuma afp vitaliup pvorzwoyll mi ut. Gaf’l kocnif ce hizkta()uzPizraybObob ej mxe ebc om wda wucrot.
Gzof’t ux — uz yuu polo, mbos uyaewb mapb nvi owiwemiazx og cyaw smikegh iyr boo chop ezkaf rmimjg iwebimpl vii gib opy aw voin aks!
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.