Video hosted by Apple at devstreaming-cdn.apple.com

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2011-125
$eventId
ID of event: wwdc2011
$eventContentId
ID of session without event part: 125
$eventShortId
Shortened ID of event: wwdc11
$year
Year of session: 2011
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2011] [Session 125] UITableView...

WWDC11 • Session 125

UITableView Changes, Tips and Tricks

App Frameworks • iOS • 47:28

iOS 5.0 introduces a number of new features in UITableView. Come learn what's new as well as some fun tricks to make your application stand out from the crowd.

Speakers: Jason Beaver, Luke Hiesterman

Unlisted on Apple Developer site

Downloads from Apple

HD Video (433.5 MB)

Transcript

This transcript was generated using Whisper, it may have transcription errors.

Good afternoon. My name's Jason Beaver, and I work on the iOS Frameworks team. And we're going to talk about what's new in UI Table View for iOS 5, as well as a couple of tips and tricks that hopefully can inspire you to add something interesting to your application that sort of sets it apart from the crowd.

So this won't be an intro session. We're not gonna cover the basics of a table view, how to get content into it and things like that. This talk is gonna be broken into two main areas. The first is what's new. There's a handful of topics here. First is automatic dimensions.

This will allow you to tell the table view to automatically compute some dimensions in cases where you need to provide custom dimensions in other cases. There's a new automatic animation style, which just tells the table view to figure out an appropriate animation that'll automatically look good. And there's a couple of new update methods to go along with the existing methods we have to insert, delete, and reload rows and sections. We've exposed the ability for you to attach menus to the cells in your table view, as well as multiple selection.

We have a great new mechanism that allows you to simplify the code you need to write when you're adding or providing cells to the table view, and even a new mechanism that allows you to eliminate all the code related to providing content to the table view if all you need to do is display some static content. And then as I mentioned, we're going to cover some tips and tricks. So let's start with what's new and automatic dimensions.

So hopefully you know, the TableView supports the ability to do custom section headers and footers. in addition to just specifying a title for a section header or footer. And if all of your doing is displaying section header, titles for your headers and footers, then the table can figure out the height of those things so that we preserve the appropriate spacing between the sections.

But if you are using custom headers and footers in your sections, you need to implement this delegate method, table view height for header and section, or the corresponding footer method, so you can tell the table view up front how big this thing needs to be. An unfortunate side effect of this is that that means that up until now, we're also going to ask you for the height of titles. And you had to guess an appropriate height to preserve the standard table view metrics.

So new in iOS 5.0 is a new constant, UI table view automatic dimension. For any of the methods where we're asking the delegate to provide some dimension to the table view, the height of a header for example, you can just return this and we'll use our own calculations to figure out what that is.

Alright, let's move on to automatic animation style. So if you have a group style table view, we have these nice rounded rectangles around each of the rows. And each of the individual cells draw pieces of those. So to preserve the illusion of that single rounded rectangle we have to be a little bit careful about the animation style that we use when we're inserting or deleting rows into a section. So for example here, we're inserting a row at the top of a section, and we need to be careful that we use the bottom animation style, so that that row will appear to slide out from beneath the rows that come after it in the table view. And similarly, if we're deleting a row at the top of a section, we have to use the bottom animation style, so that, again, it will slide out beneath the rows that come after it. Conversely, if we are inserting a row at the bottom of a section, we need to make sure we use the top animation style because we want that row to appear to come out from beneath the rows that proceeded in the table view.

And similarly, when we delete, we need to use the top animation style in that case. So we have to be a little bit careful. And if we get this wrong, we can actually make the table view look pretty bad. We break that visual illusion of the rounded rectangle that surrounds the section.

Here, for example, if we insert at the top of a table view and inadvertently use the top animation style, You'll see that that, we've told it that that row should appear prior to its spot in the table view. Well, that actually happens to be behind the header there, and you see part of it clipped, and that looks pretty bad. Here's what it looks like if we delete a row at the top, and you specify the top animation style.

And similarly, if we're inserting a row at the bottom of the table view and we inadvertently specify the bottom animation style, that row will again appear below where it's gonna go 'cause that's what we've told it to do. She'll be behind a header and look pretty bad. Here's what it looks like if you inadvertently delete from the bottom again, specify the bottom animation style. So you need to be a little bit careful, and this can get kind of complicated as you're doing lots of changes to your table view. So new in iOS 5 is a new row animation style called UI Table View Row Animation Automatic. So this tells the table view that depending on the style of the table view and where in the table view you're making these updates, we'll pick an appropriate animation style which will always look good. And I encourage you to just use this generally. Unless you have a really good reason to cause an animation to move in a certain direction, automatic is probably a better choice, and it'll look more consistent with other applications on the platform.

All right, let's move on to a couple of new update methods. So as we just talked about, and hopefully you know, we have ability to insert rows into table views as well as sections. We have ability to delete rows. And of course we can wrap these in an update block that allows you to insert and delete rows simultaneously.

And with this, we can actually do pretty sophisticated dynamic updates to a table view. I'm sure you've all played with the address book application when you go into editing mode, all sorts of new things appear as it indents. You can do pretty sophisticated things. But the one thing you couldn't do up to this point is move sections and rows from one location in the table view to another programmatically.

So new in iOS 5.0, we've had the ability to do this. This is what it looks like if we're moving a section from one location to another. Here we're going to exchange the first two sections. You see they just simply slide into the new location. And-- And the method to accomplish this is move section to section.

So this augments the existing update methods we have for sections and that is allows you to insert, delete and reload individual sections. But there's a couple of things I want to point out that are different. The existing methods take a set of sections, but the new method simply takes a single before and after section.

And the second is that the existing methods take a row animation parameter, that kind of what we just talked about, and notice that the new one doesn't. And this is because there really isn't an animation that makes sense. The row is automatically just going to slide from its old location to the new location, so any of the animation styles like fade or moving left or right don't really make sense.

And similarly we have a new method to move rows from one location to another. Here we're gonna exchange rows one and two. But of course you can move rows even between sections. And the method to accomplish this is move row at index path to index path. And this augments the existing methods to modify individual rows within a table view to insert, delete, and reload.

And similarly, the existing methods take arrays of index paths, while the new method takes a single source and destination index path. and the existing methods take a row animation property, and for the same reasons the new method doesn't. So with that, I'd like to bring Luke Hiesterman up on stage, and he will demo some of the stuff we've talked about up until now.

Thank you, Jason. It's great new stuff that we have in iOS 5 for TableView. I think some of our applications that you guys create for us are going to be able to be expanded in wonderful, new, delightful ways. So I'd like to show you an example of adding moves to your TableView now that we can do that. And to do so, I've pretty much downloaded an app from developer.apple.com, the sample code that we showed at last year's session, and I modified it ever so slightly. And I would like to re-show you that again today, but introduce this idea of doing moves.

So this application that some of you may have seen before allows us to click on sections and open them up in a way that demonstrates using the insert and deletion of rows. So you can see me doing that here. But now what I'm interested in doing is sorting these sections. These Shakespeare plays are sort of all in random order right now. But I thought it'd be interesting if I could move them into alphabetical order dynamically. And to do that I've added this little toggle sort button to the navigation bar, but it doesn't do anything right now because I haven't written that code yet. So I'd like to show you how I would actually write that code and make the table view do some moves.

So here's my method, toggle sort, I've started doing some things, and the code that is here already is the code that updates my model. My model is an array of plays, and in fact, the way that this application works is I decided to keep a couple of representations of the array of plays. One is just plays, and the other one is alphabetical plays, which is the new state that I'm gonna try to move to.

or from, depending on which way I'm toggling. So the update of my model simply takes the current array and the existing array so we know where we're coming from and where we're going to, and then switches a property on myself so I know whether I'm alphabetized, so I can return the right things from, you know, self, row, and index path, and number of rows in section, and those sorts of things. So now that I've updated my model, I want to go actually tell the table view about these moves so we can initiate the animation that we all want to see.

So we're gonna start with something that hopefully we're familiar with, a table view update block. That's begin updates ended by end updates. And in the middle, what we're going to attempt to do is take the old representation of our sections and map it to the new representation of our sections. And then for each of those mappings, we'll simply tell the table view to move from the old mapping to the new mapping.

So I have two arrays, the array that represents my current state, its current array, and a new array which represents the state that I want to go to. So I'm going to iterate through each of these arrays to find the mapping. So my first iteration is through the current array. I'll enumerate these objects using the block-based method. And for each one of these plays, I want to find its matching array in the new representation of the table. So I'm going to iterate through those objects in the new array. That's fine, don't worry about that.

Nothing to see. So we iterate through the instances of the new array, and what we're looking for is the instance that matches what we had in the current array. So we look for that with a simple test to see if the new play is equal to the current play, and if so, then I found my mapping for this particular instance of the current array. And I just want to tell the table view about that mapping now. I'll do that by using the moveSectionToSection API that we've just introduced. And it's as simple as giving it the index where that section is currently, and then the new mapping, the index in the new array, the new representation of the table that we want it to move to.

I'll give the block version of the break command here, which is stop enumerating new array equals yes. And then we're done. We found our mapping for that one, and since we're enumerating through the current array, we'll do that for each instance in the array. And this is within our update block, so each of these mappings that we've enumerated through each gets sent to the table view as a part of a single update block, and we're done. we can now take a look at this in action by coming to our play. And now if we try to toggle sorts, all of those sections move into their new place. We can, even if sections have rows showing in them, we can still sort them, new things happen.

Sorting of sections just works. We can do this, of course, with rows as well, even moving rows in between sections if we want. Whatever moves you want to do, the table view is ready and waiting to accommodate them. And in fact, you can incorporate insertions and deletions and reloads along with your moves all in the same update blocks if you wish. So that's using the new TableView Move API. And we've got a few more new things for you. And Jason will be happy to tell you about those. So, Jason.

Thanks, Luke. Ah, water. All right, so let's talk about menu support. I'm sure you've seen in some of our built-in applications the ability to attach a menu to an individual cell. We've exposed this now in iOS 5, so you can do this in your own applications. And here's basically the way this works. The user's finger comes down and touches a cell, and we highlight it just like we've always done. But if the user holds their finger on the cell for a fraction of a second, we're gonna send a new delegate method called table view should show menu for row at index path.

So if you return yes from this, then we're going to send another new method, table view can perform action for row and index path with sender. We're gonna call that multiple times. Once for each of the possible actions that might be in that menu. Of course this has a boolean return value as well, and so you can indicate for each one of those actions whether you wanna support that at that point in time. So after we've called this multiple times, we collect all the ones that you've returned yes for, and then we pop the menu up attached to the cell. So at this point, the user can take their finger off the screen and that'll stay.

They come up then and touch the menu item. We're gonna set the third and final new method to the delegate, table view perform action for row and index path. And at this point you're expected to do whatever the action says, copy, paste, et cetera. And once you return from this method, we're gonna go ahead and tear down the menu and deselect the row. All right, let's move on to multiple selection. So this is our built-in mail application, and we introduced the ability for this to have multiple selection a little while ago, but now we're exposing this so you can add multiple selection into your applications.

A long time coming, I know. So you control this with two new properties. They are allowsMultipleSelection and allowsMultipleSelectionDuringEditing. And this augments the existing properties to control selection called allowsSelection and allowsSelectionDuringEditing. So you can use really any combination you'd like here. For example, in mail, they turn on allowsSelection, which allows single selection when they're not in editing mode, and allows multiple selection during editing. So automatically, when they go into editing mode, they get the multi-select interface. There's also an additional property on the table view, index paths for selected row, which you might guess returns everything that's selected, and this augments the existing method to get a single index path for a single selected row.

We also added a new property to table view cell, and that is multiple selection background view. And this augments the existing property that allows you to specify the selected background view on the cell. And so let's cover briefly what the view hierarchy looks like in a cell. We've reused this graphic from a previous year, so hopefully you remember this. At the back of the view hierarchy is the cell itself. And if you have a background view, that's going to sit right in front of that. And you can obviously draw anything you want there. In fact, that's how we draw those rounded rectangles in group style table views.

If the cell happens to be selected, then we're going to add the selected background view on top of that background view. So this is typically just that blue gradient, or it's blue gradient with the sort of rounded corners in the group style case. And then on top of that is the content view and all of your views. So this is how we make that blue gradient appear behind everything.

Multiple selection is pretty much exactly the same thing. The only difference is that we use that multiple selection background view and then stick all the rest of your content on top. We do provide default multiple selection background views for both the editing case and the not in editing case. And so in the editing case, you can achieve the exact same look you get in mail. Okay, let's move on to automatic cell loading.

If you work with table views, I'm sure you're very familiar with code like this. This is the table view, cell for row, and index path method, and this is the way you tell the table view all of the content that should appear in your table view. And there's sort of several main areas of this.

The first is you need to figure out what the reuse identifier is for the row that the table view is asking you about. Now, in simple table views, this is probably just a constant. But in more complex table views where different cells in the table view have different structure to them, some may have a switch, some may have a slider, some may have an editable text field, you need to make sure you use different reuse identifiers for each style of cell so that you can get an appropriate one to reuse from the table view. So this is some method that you'd implement that figures that out based on what's in your model.

And then the next thing you're going to do is ask the table view to dequeue a reusable cell with that identifier. So, So if we have one, we will return that to you there, and then you can just populate it, which saves time. You don't have to create the cell. But there's always the possibility that that method returns nil, because we don't have one in the reuse queue right now.

And if that happens, you have to create a cell of that appropriate form. And in a complex case like this, it may be actually quite a lot of code that creates cells for all the different styles that you're going to display in your table view. What if we could just take all of that code and make it go away?

So new in iOS 5.0, we have a method called registerNibForCellReuseIdentifier. So there's a couple of constraints I want to mention on the nib that you register. The first is that the nib must contain a single top-level object, and that must be a table view cell or one of your subclasses. And the second is that the cells reuse identifier as specified in the nib, either must match the identifier passed into the registration method, or you can leave it nil, in which case we'll fill that in automatically for you.

So now when you call dequeue reusable cell with reuse identifier, you're guaranteed to get a cell back. Obviously we'll still prefer to return one from the reuse queue because that has the lowest cost and therefore the highest performance in your application. But if we don't find one, we'll automatically go load that nib, extract the cell and return it to you.

Okay, let's move on to static table views. So there's a lot of cases when you're adding table views to your application where it doesn't need to be dynamic. It's not based on some model that the user can change. You just need to display a static set of things. Here, for example, is our settings application. When you go into settings, you always see this basic set of things and it's always the same. With the exception of some of the components inside. I mean, your switches may have different states and text fields may have different values, but it's always the same cell with the same structure. Here's another example from settings where we're configuring sounds.

And again, it's always the same things. So we're not gonna go into the specifics of how you do this this afternoon, but this was covered in depth in the session yesterday, introducing interface builder storyboarding, as well as a bunch of great new features so you can actually flow out your entire application inside interface builder. So I highly encourage you to take a look at this if you haven't, and hopefully this can actually allow you to accomplish table views like this in your application without writing any code.

All right, there we go. All right, so let's move on to a few of the tips and tricks. So here's that application Luke was showing you just a minute ago. And what we'd like to do is add an ability to this application so that the user can rate these individual quotes from these plays.

Now there's a few different ways you could accomplish this. Using just the sort of built-in features in UIKit, you might imagine the user could select one of these plays and we could push an entire new view controller on the stack that maybe offers some rating choices. And the user could hit that and go back. User also could select one of these and we might pop up an alert sheet at the bottom, giving a set of buttons for the various choices the user might make.

But it's really nice a lot of times to be able to move some of that stuff directly in line and offer stuff more localized, so not as much stuff as moving around in your application. So what we'd like to do here is show how you might do this directly in line in the table view. You tap on a row, there's a set of controls right in line, you can interact with those, and then when you tap, they'll just go away.

So I want to bring Luke back up on stage, and he'll show you how we can accomplish this. Thank you, Jason. Hope you guys liked all that new stuff. Yeah. So I'm going to show you exactly what Jason said. We're going to add a little bit of what we might call a control row to our existing application. So I'm going to do that in the context of the two methods you see in front of you, didSelectRoadIndexPath and willSelectRoadIndexPath. Mostly it's all going to be in didSelectRoadIndexPath.

So my goal is I want to have one, at most one, of these control rows showing at any given time. That is, in the initial state of the table, it'll just look like this, where I've got these rows, and I don't have any control row anywhere. But if I click on one, I want to show that control row. But then if I go click on another row, I don't want two control rows. I only want this to be showing for one row at any time, so I will hide the one if I click on a different row and show it for the new row.

So that's the general idea that I'm gonna try to accomplish here. I will start out by first saying, okay, if I have one of these things visible when I select a row, I'm gonna go hide that thing. And part of that is going to be to unselect the row that I've tapped on if I've tapped on the same index path that I've selected before. I'm gonna be working in the context of a couple of Ivar's properties on my class that I've scrolled away. One is called this tapped index path, which represents the row that I tapped on. And then another one is control row index path, which is where I'm gonna put my control row. so you know what things are flying around the screen here.

So the next thing we're gonna do is get a modified version of the index path that the table view sent me. The reason I'm doing this is because, conceptually, when I tap on a row, I still have the same number of rows in my model, But I'm adding this control row so the table view thinks I have one more row than I really actually have. So instead of changing my actual model, I've decided to just say, well, I'm going to keep track of where this control row is, and when the table view sends me index paths, I'm going to map them to what they really are in my model. So I do that with this model index path for index path method that I wrote which just offsets things by one, if need be.

So, with that, I go to figure out what I need to delete, which, that's the control row index path, if I have one, so that will be set to something if I'm showing the control row. And whatever that is, I'm gonna scroll that away so I can delete it later. What I'm trying to do now is build what I'm gonna use to do a table view update block. So I need something to delete, possibly, something to insert, possibly, and I will be doing that at the end of the method.

So now I want to update my properties based on what happened here. So I have my tapped index path and my control row index path. And if I've tapped on the same row that I already had, the sort of the last row that I had tapped on, I'm going to nil them both out because if I tap on the same row twice, I'm just going to hide the control row. And so there will be no tapped index path, no control row index path. We're done with that. But if I'm tapping on some new row that is not currently showing a control row, then whatever I've tapped on, that is now my index path, my tapped index path. And the control row index path is going to be that row plus one. So you see I have here index path row plus one, and I'm creating that for my control row index path.

So now I have the thing I need to delete, which is whatever was the last thing that was selected, if anything. The row that I need to insert, which is the control row index path, that's where I'm bringing in the control. And I can go ahead and do an update block to make these things happen. So here's our familiar table view begin updates and updates. And I'll do an insertion if necessary.

If I have something there, I'll go ahead and... Or I'm sorry, a deletion first, if that makes sense. If I have something there, I'll go ahead and call tableview delete rows at index path, and send it my index path. I'm gonna go ahead and use the new tableview animation automatic style, because that's convenient and a nice default to use. Then I'll go ahead and do my insertion. If I have a control row index path, send that to insert rows index path. Again, I'll use the new automatic animation style.

I just have one more thing that I want to clean up. And that's I want to make it, I don't really want the user to tap to select the control row per se. We have some controls in there they can interact with, but I don't actually want them selecting it. So if they try to, when will_select_row_at_index_path comes in, I'm gonna see if they're actually trying to select, again, don't worry about that, I went to the wrong, okay.

If they try to tap on that row, I'm gonna detect that it's equal to the control row index path. And instead I'm gonna return the row above it, which is sort of the row that I'm really interacting with conceptually, the tapped index path. So with that I can go see what this looks like. As a nice little pitch, I will also say that I used register nib for cell identifier for this control row. And so that inserts when I tap on the row. Thank you.

and the little control row shows for me. I can go tap on another row, that one hides, new one shows, I can maybe rate this one as, hey, good thumbs up. Falstaff, he's talking about pepper, I'll rate that as not so good. And if I tap on the row itself again, that indicates that I'm done with this, and it goes and hides away. Gives you an idea of interesting new way that you can think about allowing your user to interact with your application, giving them inline controls to give feedback about the information in your table view. So thank you for letting me show using a control row in the table view. And I'll let Jason come back and talk to you about some more tips you can do with the table view. Thank you.

Alright, thanks Luke. So, we weren't actually doing anything really new there. This is something you actually can do in any version that's shipped so far. But it's not the typical way people use those. And the point of all of these tips and tricks is to get you to sort of think of new ways to use some of the built-in functions to provide new sorts of interfaces for your users. So the next thing I want to talk about is floating views.

What's a floating view? Well, a floating view is something that appears to stay fixed on the screen as the user manipulates the content. We have a couple of examples of these in TableView already. The index bar that appears over on the right side, showing A through Z in English, that stays fixed as the user emits their content is an example of one of these floating views. Also in applications that use plain style table views with headers, when the headers hit the top, they stick for a second until the next header comes in and sort of pushes them out of the way. It's another example of a floating view. So I wanna talk a little bit about how you can do this in your own applications and create a view that appears to just float in your table view.

So I want to talk a little bit first about the machinery of scrolling so that we all understand what's actually going on when we scroll a table view. So here we've got a blue box there that represents the table view in our iPhone frame, and let's just take away the iPhone frame so we can focus on the table view. So the table view is some fairly long view that goes far off the screen.

But there's some visible portion right now, and we're going to represent that by this dotted red line. So when a table view scrolls, all we're really doing is moving the content offset of the table view. So that's just the point within the content that should be shown visually.

So what happens if we have some sort of subview in our table view here? For example, we put a little box in our table view. When we scroll that, that box moves with it. Well, why does it move? Well, that box is specified, its coordinate system is specified in terms of its parent. It's some constant offset from the upper left corner of the parent. And that isn't moving. So it's always gonna be that constant offset. We've just changed sort of where inside the table view we're looking. And this is all that happens when we scroll.

Cells are at fixed locations within the table view, and as we move that content offset, they appear to move up and down. And then we take care automatically when those things go outside the visible region of popping them out, putting them in the reuse queue, things like that.

So hopefully by this point it's kind of clear what we need to do if we want to create a floating view. All we need to do is figure out whenever we scroll, grab our view and simply push it back to the same place on the screen. So we can figure out whenever we scroll with the scroll view delegate method, scroll view did scroll, and whenever that is called, the scroll view has moved some amount, and we can go do anything we'd like at this point. This is in fact the place where we go in and pop cells off if they've gone off screen and add new cells if they've come on screen. And you can do anything you'd like there. In fact, in this case, all we're doing is basically figuring out where we'd like that view to be and just moving it.

So we'll bring Luke up in a minute and we'll show some code that does that. Before we do that, I want to talk about one other tip and trick, and that's a dynamic background view. So in iOS 3.2, we added the ability to specify a background view on a table view.

The important thing to note is that this is actually a view. I mean, we generally use it for things like putting an image view back there. For example, on iPad, we have a nice gradient behind our table views. But because this is just a view, you can actually use it for just about anything you'd like. Here, for example, you can see this cloud subtly scrolling by behind our content.

So with that, I want to bring Luke back on stage, and he's going to run through how we accomplish these. Thanks again, Jason. - Okay, listen. So there's a lot of things you can do in response to scrolling in the table view. We're going to show the common case of just wanting to keep a view apparently static in terms of the table. So as Jason described it, a floating view that stays in the same place as we scroll the table.

But there's lots of different things that you might want to do in response to the table view scrolling. I talked to a gentleman yesterday who actually wanted to potentially move views outside of his table relative to the table view scrolling. And it's all pretty much the same idea. We're introducing here implementing the scroll view did scroll method. And that's going to be your key if you're using a table view controller to get in when the table view is scrolling. And then if you want to make adjustments to things to get different visual effects, that's where you do it. So I'm going to show you an app that you've seen in slides, but it's great to see just why this needs a little improvement.

So I put a little button over here, this is some more Shakespeare quotes, and I put a little button in the upper right that I intend to use to allow my user to download some new quotes in case the bard writes them. And the problem is I can scroll this table and that button goes away. So anytime I want to use that, I have to scroll to the top and click it up there. What I really want is just have this button stay in place, be a static floating view on top of the table and always be in that upper right. So we're going to do that by implementing scroll view did scroll. Now the key is to know where that view should stay relative to the apparent view of the table view. And we're gonna do that by creating a property that we can scroll away that is the initial origin of that view. So I'm gonna declare a property here. I'll call it CloudViewOrigin. And synthesize it so I can use it. All right, I've got my Cloud View origin property. And I'm just going to go implement scroll-view-did-scroll.

So in scroll view did scroll, what I'm observing is the changing bounds of the table view because as Jason illustrated, that's what happens when we scroll, the table view bounds change to a new value. So first thing I'm interested in is, okay, what are the new bounds of the table view?

All I'm going to do is adjust the frame of my little cloud view in response to what the actual bounds of the table view are now. So I'm just going to take the existing frame of the cloud view, grab it there. I'm going to set it back, but make a little adjustment here, particularly to its origin.y value. So I do self.cloudview.frame equals reflect, And that rect is the same as what it is now, the same size, width, and height, and origin.x. But for the origin.y, I'm taking the value that I scrolled away in my CloudView origin property and adding that to the table view's current bounds.origin.y. So now as we scroll and the table view's bounds origin changes, then we will use that value to update the frame.origin.y of our Cloud View.

So the only thing I'm missing now is I haven't actually initialized my Cloud View origin. I want to do that when I create the view. So I'll just come down here, and here in ViewDidLoad, this is where I create my Cloud View and add it to the table. While I'm doing that, I will initialize my self.cloudview origin to the Cloud View origin, and that should be everything I need. ScrollView did scroll, will now be able to do its thing.

Now hopefully when I scroll this, the view stays in place. This even works when we bounce right here, because in this case the table view origin bounds is going negative, and my adjustment to the offset still works, so in all cases, this will work for vertical scrolling. So, yay, I'm very happy about that.

The other trick I want to introduce here is thinking of the background view, as Jason said, as more than just a flat view. It is the background view property on UITableView is a generic UIView. So you can do anything that you can do with a view with it, which is all kinds of things.

You don't just need to provide some static idea of one single flat view with no subviews that don't change. as the background view. Obviously you want something tasteful, but there are things you can think about for making your application stand out by having a background view that maybe utilizes subviews and is dynamic in some way.

What I've set up here is a background view that actually isn't just a single view. My background view has a subview that is an image view, and that image view is actually twice the width of what you see on screen here. So half of it is living over here. And I'm going to use that to perform an animation on it and make it appear to move horizontally off screen. So, I can do that in... Gears, good place for that. And what I want to do is just initiate an animation here, as soon as the view appears, that changes the frame. Let me re-show you.

we're looking at, it changes the frame to move it over towards the left. We'll move it off screen to the left since half of my image view is over here to the right, not really on screen right now. As we move the whole view to the left, the stuff that's on the right off the screen now will come on screen and we'll get this animating effect.

And in fact, I made the image that it shows tessellated with itself, so I can just do this movement forever and we'll get a nice infinite scrolling appearance to it. So, the actual code for this is quite simple. It's just a UIView animation. Many of you have probably used UIView animations before. And that thing still hates me. So I'm going to initiate UIView, animate with duration, and I need a few options here, so I'll give it a duration of, say, 60, delay of zero, 'cause I don't need to wait. Couple of options I'm gonna use are UIView animation option repeat, that's there so that my animation, my dynamic idea that my table view has going just goes on forever, don't want it to ever stop. I'm gonna use a linear curve option, because by default, UI view animations use a ease in, ease out curve, but I want just sort of a constant velocity to my animation going on forever. So I'm gonna use the linear option. Now all I need to do is within the animation block, update the frame of my image view so that it appears to move across the screen as part of the animation.

So I get the current idea of the frame. I'm gonna adjust its origin so that it moves off-screen to the left. So I take the imageViews frame.origin.x and I'm gonna take half of its width and move it that much to the left, negative. And now that I have that, I'll just assign it back to the image view.

take my background image view, its frame, assign it to what I just calculated, and that sets up my animation, and that's all the code I need. So, You've seen this once before in slide form, but actually running in code, so much better. And there it is. My background view is so much more than a background view now. It's me floating through the sky enjoying my Shakespeare quotes.

So I really enjoyed showing you a few of these tricks today. I hope it gives you some food for thought as to things you can do to enhance your TableView application and continue to make the best apps in the mobile world. So thank you for letting me show that, and thank you for writing the apps.

Alright, thanks again Luke. So that's really cool, but we really don't want you guys to all go out and make cloud backgrounds in your apps. The point of all these tips and tricks was really to really let you see sort of under the covers a little bit and understand how things work inside the table view so that when you come up with your own ideas for something that will set your app apart, you understand the machinery of how everything works and you know where to hook in.

So we covered a bunch of different stuff. I want to just briefly recap. Bunch of new features in iOS 5 from automatic dimensions and animation style, a couple of new update methods to move sections and rows, menu support, multiple selection, new automatic cell loading feature and static table views, and then, of course, the tips and tricks that we just covered.

For more information, you can contact the Application Frameworks evangelist, that's Bill Dudney, and there's his email address. There's some great online documentation which discusses this, as well as the developer forums where you can all help each other out. There's a couple of related sessions. Unfortunately, these all happened yesterday. But simplifying touch, event handling, and gesture recognizers, and some advanced gesture recognition. And with that, thanks for coming.