You will learn to develop sophisticated user interfaces for iOS, with a focus on user interface design best practices, UI animations, and responsive design. You will learn about the key UI widgets, mapping interfaces and view restoration.

审阅

MR

Very descriptive, that's good for learning. Besides, peer assignment works are very effective. Anyone interested in iOS development must try this course.

DJ

Aug 13, 2017

Filled StarFilled StarFilled StarFilled StarFilled Star

Very Good content, clear and challenging. But the most important part is that the material is very applicable to real app development

从本节课中

View Controllers and Map Interfaces

This week, we will look at view controllers and map interfaces. We will cover user interface construction plus complete a peer review assignment called The Basic Map View. Who doesn't want to be able to put locations on a map!

教学方

Don Patterson

Sam Kaufman

脚本

[MUSIC] Now, it's time to dive into some of the details of the code associated with setting up, some of these content views and some of these controllers. So, let's first look at scroll views. Scroll views is a very common view container, that's used in iOS designs, and there's a little bit of nuance to them, and we want to talk about them, so you can get them right. Now, you may want to follow along and see if you can duplicate some of the things that I am executing here. Because you're gonna learn a lot better, if you try and follow along at home. So, what's the big picture? Well the big picture, is that the scroll view container, is a container that expands the size of the screen. But, it expands it virtually. So the scroll view itself, has a frame that acts normally. And so, that kind of is represented by this black rectangle here. That's a thing that you would drag and drop onto your device. Within that frame though, there is a larger virtual frame and that's represented by the grey dotted line. This enables that large content, within the grey dotted line to be shown on a small screen represented by the black frame of the ScrollView and, you move around that larger content, by moving that black window around over the content virtually through scrolling, and paging, and through zooming. So, that's the big idea, ScrollView enables you to have larger virtual canvases. Maybe, you want to have a big picture, that you can scroll and zoom in and out of. Maybe you would like a long set of contact information and you'd like to be able to scroll up and down through that information. You can put several things within the scroll view. It doesn't just have to be one item that you're viewing, but lots of things if you want, that you enable your user to move around in. All right. So, the challenge in scroll view is that, there is a different constraint layout system that's running within the virtual space. So that gray dotted line, that gray dotted rectangle has its own constraint engine that's determining how large it is. And the trick is, is that you don't specify that size of it explicitly. What you do is you specify the components that go in it and you give them enough constraints, that the constraint engine determines, that it must have a certain size. And then, that becomes the size of the object that gets moved around underneath the scroll view container. When you do this, then, you have to decide how you're gonna do it. What we're gonna do is, we're gonna show an example of having a ScrollView, and internally we're gonna put an ImageView, and that ImageView is gonna be larger than the device's screen. And we're going to put constraints on that image, such that the virtual screen in completely specified. First of all, we're going to place the scroll view on top of the device, and we're going to put constraints on the scroll view. So, it's fixed to the device size. And internally, we're going to say that image view is going to extend all the way to the bounds of the virtual space, which are undefined. And that the height and width of the image view is going to be constrained, to the height and width of the image. And that will be enough that the auto-layout can figure out both, where the black square should be within the view and how large the dotted grey line should be. So, let's give that a shot. Alright, I'm going to switch to Xcode, and in Xcode I've setup a single view application here. And we're gonna go to our storyboard and here, we see that we don't have anything in our view controller scene. So the first thing that I wanna do, is I'm gonna select our view and I'm gonna give it a background color, so that we can see what's happening with our scroll view. I'll make it a dark gray. And then the next thing that I'm gonna do, is I'm gonna add a scroll view. This is the equivalent to our diagram, the thing that had the black line around it. I'm gonna drop that scroll view in here and I'm going to go ahead and position it. So, I kinda like the way it's laid out. But, I'm not gonna send it all the way to the edges of the outer shell, because I want you to be able to see the ScrollView in action. All right. So, let me go ahead and constrain that ScrollView. We're gonna make it 000020. Add those constraints. And then, I also want to get the ScrollView itself some background color, just so, that we can see where this ScrollView is where the outer container is and then where the content is, as well. So give it a white background and anything else we want to add there? No, I don't think anything else we want to do now. So let's just run it and show you what we've got now. This should give us a device with a white square in it, If all goes well, that's what we get. Great. Now that is the scroll view, but we don't have any content in it, so if we touch in, touch it and move it around, we don't actually have any content scroll in, so there's nothing to show. So, back to our project. Now what I'm gonna do is, I'm going to go into our assets folder. And the assets folder's, the place where you keep images and media that you want to have in your project. We don't have any here right now, but I'm gonna drop some images in that we're gonna need for the rest of our project. I've set them up here, conveniently. I'm gonna add them to our project. All right, now let me go back to our main storyboard. And I'm gonna add an image, that's too large to be viewed within our device. [INAUDIBLE] There's gonna be a big panoramic view of a beach in Haiti. So I'm gonna click on our media, a library, it's something that we haven't seen before, and I'm gonna drag and drop this image into our ScrollVview container. And if you do this from the media gallery, what is helpful is that, it drops that image into an ImageView container from the get-go. So, you don't have to do the work of setting up an ImageView and then, adding an image to it. It saves you just a short step. You can see, it's a big image. I'm going to drop it into the ScrollView. Let it settle. Then if you come over here, you can see that the ImageView becomes a child of the ScrollView. And I can verify that, that's an ImageView by coming over here and seeing ImageView. It has the name of my image though. And it's too large. But it's within the ScrollView, so that if we go ahead and we run it, we should now be able to scroll around this very large photo. Oh, that's right. We haven't given enough specifications to that dotted gray line area, to specify well how big is the space that we're zooming around. We haven't really specified that at all. So, let me select our ImageView. Just do it over here, because this is extending outside the ScrollView expanse, so it's hard to see it. I'm gonna set up some constraints. I'm gonna say that, I want this interior image, this beach scene, to go all the way to the edges of this virtual boundary even though it hasn't been specified. Now I want the width of the image, and the height of the image, to be the same as the number of pixels in the image itself. So between that, that's gonna be enough information to constrain that inner boundary to being 4,678 pixels wide, by 1024 high. And now, if I go ahead and I run it, that inner space has been constrained and as I drag it around, you can see that I can scroll through this entire picture. And notice as I do this, there are scroll bars down on the bottom and scroll bars on the side. That indicate where in the content I am. And then when I get to the end, you can see that it bounces off the end to indicate that I've hit the end of the content. Alright, really nice, that's the first thing we want to demonstrate. Okay, so that's what we did. We created a scroll view container, we dropped an image in it, we set the bounds on the image so that the dotted gray lines were specified so that the auto layout knew how big a space there was to scroll over. Now, the next thing that I'd like to do is I'd like to set up multiple images. When you do multiple images, multiple UIView elements and anything, multiple things that are gonna go in within your scroll view. Everything suddenly gets hard. Because it becomes hard to correctly set out all the constraints and all the elements that you might want and have them be fully constrained. And not have the objects flipping all over the place. So best known practice is rather than just dropping all your elements into the scroll view. You first drop a UI view into your scroll view, you set the width and the height of that UI view specifically and then you drop your content into the UI view and set up the constraints within that. So that you have this outer frame whose width and height is specified into what you drop your content. And then sometimes we have a hard time seeing everything so I'm gonna show you how to change the simulated size of your view controller so you have a little bit more canvas to work on. So let's set up multiple images, go back to our project. Okay, that was good. What I wanna do now though is I wanna get rid of that image that we just dropped, and into our scroll view, I wanna add a UI view, not from our media library but from our object library. I'm gonna drop it into our scroll view, great. I see over here in my hierarchy that it dropped into the correct place, it's a child of the scroll view. And then I'm gonna set the bounds of this scroll view, that dotted gray line, to what I want it to be. All right, let's see, for starters I know that the images that I'm, what I'm gonna do is I'm gonna do a a two by two grid of square images and each one of those square images is 1024 on the side. So for this view element, I want that to be constrained to having a width and a height of 2048 by 2048. I'm going to have it extend all the way to the edges of the virtual boundary. And that should be enough to specify how big that virtual boundary is. It's gotta be exactly as big as this UI container. Cuz the UI container goes all the way to the edges, and we've given it a very specific width and height. So let's add those, great. And what's our warning here? Our warning says that our frame for view will be different at run time, right. And so that's a reminder that if we come up here to our editor and we resolve auto, select our view controller, then go to our editor, resolve auto layout issues, and update all our frames, it'll resize the elements according to what are constraint engine currently says. Okay, now going back to our media library. Why is everything gone from our media library, oh, because we have a selector here, great. Don't want to filter those. So if we go back to our media library and we select the four, let's select them one at a time. Let's drop this first image into our UI view. It's an image of the side of a house with a whale cut out of the wood. We can see that we dropped that correctly into our view, but this image is so much larger, and we're gonna set up four of them, that it's hard to be able to position them on a canvas. So I'm gonna go to my view controller and I'm gonna come over here. And rather than having a simulated size at fixed, I'm gonna specify how big this virtual device is that I'm working with. This isn't gonna affect the ultimate layout, it just gives me more canvas to work with. So I'm gonna set it to be 3000 by 3000. [SOUND] And then it'll, and then if I come over here and zoom out, you can see I've made my virtual device unreasonably large. Larger than it, it doesn't matter how big I set it, this just gives me some canvas to work with. So now I have this whale and I'm gonna click on the whale image and I'm gonna give it some constraints. I want it to be in the upper left of the container in which it is embedded. And so I'm gonna say, okay, it's gonna be 00 from the container. And I want it's width and it's height to be constrained. I'm gonna add those four constraints, I'm gonna zoom out. And then I'm just going to update my drawing here, so I can see the current state of affairs. That helps me not get too confused. All right, now I'm gonna select my second image that I want to drop and I'm gonna put it in the upper right. [NOISE] Op it didn't draw. Let's try that again. Okay it's not dropping onto the canvas because I'm zoomed out too far on the canvas. Let's see if I can put it directly into my view hierarchy. Nope it's not letting me do that. Okay, so in order to do this I'm gonna have to zoom in a little bit. I don't like this behavior in x code, because I think it's confusing if your virtual device here behaves differently depending on how far you scroll down. Now you can see the green plus. I'm going to link it clearly to the right of the whale, and now I'm gonna give it similar constraints. I'm gonna say it's gonna be in the upper right, so it's zero from the top and zero from the right. And I want its width and height constrained. I'm going to add those constraints, select my view controller, resolve my auto-layout issues and you can see that we have dropped those elements nicely where we want them to be. All right now let's add that lower left image. The lower left image is going to be this picture of a light bulb, just going to move it down a bit there, all right? Now let's set the constraints on this to be zero from the left, zero from the bottom, a widths and a height of 1,024. Add those four constraints, select my view controller, resolve my auto-layout issues, and you can see that things are laying out nicely. And then let's take our last image here, let's take our image of a face, now we're zoomed out too far. Zoom in a little bit, okay, this is gonna be on the bottom right, so I'm gonna add constraints such that is is zero from the right and zero from the bottom. And I'm going to give it hard width and height of 1024. Select my view controller. Go to resolve auto-layout issues to update frames. And now what we've done is we've specified a Scroll View. The first child and the only child of the Scroll View, the immediate child of the Scroll View is the view. This view has hard width of 2048 by 2048, and it has borders of 0 on the interior views. So that makes a grey dotted line within our virtual space that gives us a canvas on which to work. Within that canvas, I then dropped these four images so that they would fill up the resulting container. Now, if I go and I run this application. You can see that I can scroll over my entire two by two image that has multiple images in it and you get nice behavior here that's kind of what I was looking for. All right, that's a good outcome. All right, multiple images. Best known practices, have this interior container of the UIView. And then if you need to work with a bigger canvas, you can set the view control to simulated size in order to position things. All right, the next think I'd like to show you is constrained scrolling. And this is, for example, if you don't want to enable your scroll to go up and down, it might be nice to just be able to scroll left and right. And the way that you would do this is you would specify a constraint on one of the child elements to be the same as the parent elements. So, time you might use this is if you had sort of a profile page with an image and maybe demographic information, or an address, and you'd like to be able to scroll up and down through all that info. But you don't want to scroll left and right. So you make sure that that interior UIView matches the exterior scroll view. So let's see if we can go and we can set up our interior UIView. Actually, let's go back to our Haiti image, and we will take a look at our Haiti image and attempt to lock it down so it just scrolls one way. All right, so let's go back here, and I'm just gonna go ahead and commit this in case we want to get back to it. Save this position in source code. All right, I'm gonna delete my four images here. I'm gonna delete my interior view controller cuz I just want to add one image now and I want to go back and I want to add my Haiti image. Okay, and we need to specify constraints on it so that that interior gray dotted box is specified. I know that I want it to extend to the four sides of the virtual space. That's gonna say that the bounds of this image are the bounds of the dotted grey line. Now I want the width to be as wide as the image needs to be. Let's see. Which is gonna be 4,068. No actually, I just want to set the aspect ratio correctly. Because I'm gonna set the height of this image equal to the height of my scroll view so that it matches exactly and we only scroll back and forth. So let me add those five. And then I'm gonna control drag my image to my scroll view and I want the heights to be equal. Now if all goes well, this will mean that my image height will be the same height as my scroll view and the aspect ratio will be constrained. So that now I can scroll left to right and the image has been resized to be exactly as tall as my scroll view, so I can't go up and down even if I click. But I can go back and forth nicely. Now you notice that at the end, there's this bounce behavior. That's something that can be changed. If you don't want the bounce behavior, you can select the scroll view over here. You can go over to the properties and you can turn off the bounces. The bounces are actually kind of nice. If you don't have the bounces, then when you scroll to the edge, you get. You don't see any of the white but you end up getting kind of a hard stop which is a little disconcerting. So you see it's hard stopped. It doesn't bounce, all right? I like the bouncing so we're gonna get that back. The next thing that you might want to do is you might want to support zooming. Now, zooming isn't quite as easy as just specifying a checkbox saying you wanna zoom, you don't wanna zoom. There's three things that you have to do. The first thing you have to do is you have to specify your zoom levels. And this is saying how far in do you want to allow the user to zoom? And how far out do you wanna allow the user to zoom? Okay, that seems straight forward, usually it's set up one to one, if it's one down and one up you can't zoom at all. Then you have to identify which object you want to have the scroll. When a user touches the scroll view and zooms, you have to inform iOS what object within the scroll of view should be zooming, getting bigger and smaller, and you do that with the delegate. And so your zoom view is this UIView element within your view controller. And so when you touch it, it receives these pinches and you have to indicate within iOS where the code is that's going to answer those pinches. And then you have to write the code that answers the pinches which simply returns which elements could be zoomed. It's a little bit of a circular element here that probably could be done automatically for you but isn't. So let's go back to our image and let's add zooming to our beach image. All right, so, how do we want to do this? Well, for starters, I'm gonna take my image and I just want to get rid of it. And I want to start with some fresh constraints. I'm gonna drop it into my scroll view container, and I want it to extend to the edges of the virtual boundary. And I want the full width and the full height. Now if all goes well, when I run this, we should be back to the behavior where we're just scrolling around our image. Let's just make sure that's working. Yep, we can go up and down, and left and right, good! Now what I wanna do is I wanna add the behavior of zooming. So I need to go to my scroll view and I need to say, okay, well here's my scrollview, how much is my user allowed to zoom? Well let's allow the user to go down to 0.25, and let's let them go up as high as ten times the image size. All right, that's the first thing, to specify that it's more than just a one to one. The second thing is to say, okay, when a user touches on the scroll, where can iOS find the code that's gonna answer that touch event? And to do that, you have to specify a delegate. You say, where does the code exist? Well we haven't written the code yet but we're gonna put the code in the view controller. We're gonna point the scroll view to the view controller to find that code. So I'm gonna Ctrl+Drag from scroll view to view controller and I'm gonna specify that the view controller is the delegate. Now in the view controller, I have to write the delegate. So let's bring up our assistant. Let's give ourselves a little space. And what we have to do here is we have to implement a method through an interface. Let's specify the interface that we want to use. And I have some code here standing by to help me out. I thought I did. Yeah, there we go. All right, so the interfaces that I wanna implement is called UIScrollViewDelegate. And that means that down here in my view controller, I need to implement that function. I'm gonna implement that function that UIScrollViewDelegate requires, which is called ViewForZoomingInScrollView. So I'm gonna respond to what is the thing that gets zoomed in and out. I'm gonna return something that is a child of a UIView and I'm gonna receive the scroll view but I'm not gonna use that. Well, I haven't indicated what I want to zoom. Well, I know what I want to zoom is this image. So I'm gonna need to add a connection to it. I'm gonna need to be able to wire that in. So I'm gonna Ctrl+Drag, I'm gonna Ctrl+Drag the image over to my code so I have access to it, and I will say this is my image view. So now I can program against it. And when the scroll view receives a pinch, it has pointed to the view controller as the place where the pinch is handled. Here's my view controller code. This is the delegate that handles pinches. And I have to return what it is that I want to be zoomed, and that's going to be the image field. I'm going to have to return that, sorry. All right. So, now having done those three things, when I run it. I can option-drag and simulate a two-finger pinch. And you can see that I can zoom in and I can also zoom out quite a ways. And I can still scroll, I still get my bouncy behavior and then I can zoom back in in order to see details on my image. All right, so that's pretty good. We implemented zooming. We implemented pinching. The last thing that's helpful in the scroll view that you might want to implement is paging. Now paging is actually very easy to turn on. It's just a matter of doing a check box on the side. So for example, in this case, we specify our scroll view and we can come over here and we can turn on paging as simply as clicking paging enabled. And if we do that. Let's turn off our zoom by just specifying 1:1 so that you can't practically zoom. I've turned on paging and so now what happens when I swipe left and swipe right is that the content moves in discrete widths according to my scroll view here. So you can see that it's hard to see on an image, but it doesn't stop halfway. So look up here at the branches. As I scroll left, it stops right where that branch picked up. And if I scroll back, it stops at exactly the same spot. Or again, you can look and see the end of this branch. And as I scroll left, it goes right to the end, and I can't stop it in-between. The paging behavior insists that it snaps to these pages. That's nice if you're going through some paginated content. So, this zooming up and down does the same thing if your content is large enough. My content isn't large enough to have two widths. So, that's how you turn on paging, but if you actually want to constrain your inner content to be that size, that's a little tougher. And we can try to do that. Let's try and do that right now. All right, so let's go back to our view and let's go ahead and get rid of our assistant editor here. And let's get rid of our image. And what we'll do is we'll try and put those four images that we saw before, side by side so that as you scroll through them you see one at a time. And it's a little tricky. So let me get rid of my image view and I'm gonna use that UI, that inner UI view trick that we did before. So let's go to our library, let's get a UI view, let's drop it in our scroll view, and let's specify that it is going to go to the full width of our scroll view. And in terms of width and height, that's a little trickier. Let's just add those four constraints there. Let's run it and see what we get without specifying a width and height. All right, so it's filling it up. We don't have anything in that interior view yet, but we're gonna wanna do that shortly so let's see. I'm gonna specify within this, even within the view I'm gonna specify four additional views. So view one, view two, view three, view four. And so that I can see them, let's give them different background colors for the time being. Yellow. Pink. Green. And blue. And, I'm going to put them side by side. Now, I need to give them some constraints. Now the constraints that I wanna give them is that I want them first of all, I want all four of them to be the same width and height. I'm not gonna specify what they are but I want them all to have equal widths and equal heights. That's gonna be my first constraint. The next constraint is I want them each to have a width that's equal to the scroll view width so as you go through one at a time it pages exactly one of these views each. So I'm gonna do that by selecting the four views and control drag and drop into the scroll view and saying that they're gonna have equal widths. All right and now for height I'm actually gonna make sure that they have the same height as the scroll view as well. Equal heights. Now if all goes well hm no. I also want to let's see I wanna make sure that they are all aligned vertically in the container. And then I want to go through and I want to specify to make sure that they are all reaching the boundaries of the view. So, the blue one is on the left so it's going to be zero, zero, zero. So the top left and bottom, add those constraints. The green one, the same. It's gonna be zero from the top, left, and the bottom. Three constraints. The orange one, three constraints from the top, the left, and the bottom. And in the yellow one, we're gonna give four constraints. From the top, the left, the right, and the bottom. All right. We go back to our scroll view. We make sure that paging is enabled, and now we're going to run this and see what we get. All right, there's our blue. If we go left, we can see that we cleanly go to the green, we cleanly go the orange, and we cleanly go to the yellow, and it balances on the side. So it's only allowed to stop on the boundaries of those colors because I've set their constraints equal to the scroll view and turned the paging on. Now that's efficient. If I wanted to add the images, it would be enough to just make an image a child of each of these views and make sure that the constraints within that view, the blue view, the green view, the orange view, and the yellow view have been set. All right. Great. So in summary, scroll views create a canvas that's larger than the device's screen. The internal screen, the virtual screen, that dotted gray box, has its own constraint system that can be difficult to manage. Best known practice is to put an internal UI view inside it to help you control those constraints. These scroll views are very, very common for moving through content in which you need to scroll because there is too much to fit on one screen. All right, good luck on trying this on your own. That's all I've got for this lecture. [MUSIC]