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
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
[Transcript missing]
So this won't be an intro session. We're not going to cover the basics of a table view, how to get content into it and things like that. This talk is going to 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 TableView 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 will 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 as 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, TableViewHeightForHeaderInSection, or the corresponding footer method, so you can tell the TableView 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 TableViewAutomaticDimension. 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.
All right, 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 preceded 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 TableView and we inadvertently specify the bottom animation style, that row will again appear below where it's going to go because 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.0 is a new row animation style called UI TableViewRowAnimationAutomatic. 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 TableViews 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.
[Transcript missing]
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 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.
The second is that the existing methods take a row animation parameter that we just talked about and notice that the new one doesn't. 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 going to 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'll demo some of the stuff we've talked about up till now.
Luke Beaver, Luke Thank you, Jason. It's great new stuff that we have in iOS 5.0 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, a 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 would 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, ToggleSort. 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 decide 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 going to 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 and sections. 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 going to start with something that hopefully we're familiar with, a TableView update block. Let'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, it's a 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 TableView 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 TableView 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 box 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.
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.0 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 going to send a new delegate method called TableViewShouldShowMenu for RowItIndexPath.
So if you return yes from this, then we're going to send another new method, TableView can perform action for row and index path with sender. We're going to 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 want to 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 and then and touch the menu item. We're gonna set the third and final new method to the delegate. TableView 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 going to 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 allows multiple selection and allows multiple selection during editing. And this augments the existing properties to control selection called allows selection and allows selection during editing. So you can use really any combination you'd like here. For example, in mail, they turn on allow selection, 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 TableView, 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 TableView's cell, and that is multiple selection background view. This augments the existing property that allows you to specify the selected background view on the cell. 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, you know, blue gradient with the sort of rounded corners in a 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 TableViews, I'm sure you're very familiar with code like this. This is the TableView cell for row and index path method and this is the way you tell the TableView all of the content that should appear in your TableView. 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 TableView is asking you about. Now in simple TableViews, this is probably just a constant, but in more complex TableViews where different cells in the TableView have different structure to them, you know, 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 TableView. 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 TableView to dequeue a reusable cell with that identifier. 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 need to make, 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 TableView. 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 TableView 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 going to 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 is 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 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.
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 going to 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 going to 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 going to 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 going to put my control row so you know what things are flying around the screen here.
So the next thing we're going to do is get a modified, version of the index path that the TableView sent me. The reason I'm doing this is because conceptually, when I tap on a row, I still have this, the same number of rows in my model, I'm adding this control row so the TableView 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 TableView 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 going to scroll that away so I can delete it later. What I'm trying to do now is build what I'm going to use to do a TableView 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, 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 TableViewBeginUpdates and updates. And I'll do an insertion if necessary.
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 going to 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 willSelectRowAtIndexPath comes in, I'm going to see if they're actually trying to select, and don't worry about that, and I are going to go, I went to the wrong, okay.
[Transcript missing]
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.
All right, thanks, Luke. So we weren't actually doing anything really new there. This is something you actually you can do in any version that's shipped so far.
[Transcript missing]
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,
[Transcript missing]
So I want to 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 TableView.
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, you know, far off the screen.
But there's some visible portion right now and we're going to represent that by this sort of 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 going to 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. 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 the, 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 TableView scrolling. I talked to a gentleman yesterday who actually wanted to potentially move views outside of his table relative to the TableView scrolling. And it's all pretty much the same idea. We're introducing here implementing the ScrollViewDidScroll method. And that's going to be your key if you're using a TableView controller to get in when the TableView 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, but 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 to 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 going to do that by creating a property that we can scroll away that is the initial origin of that view. So I'm going to declare a property here, I'll call it cloud view origin. And synthesize it All right, I've got my Cloud View Origin property. And I'm just going to go implement scrollView.scroll.
So in ScrollViewDidScroll, 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 gonna 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 gonna take the existing frame of the cloud view, grab it there, I'm gonna set it back but make a little adjustment here, particularly to its origin.y value.
So I do self.cloudview.frame equals erect. And that erect 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 cloud view 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, 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 CloudView 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 CloudView and add it to the table. While I'm doing that, I will initialize my self.cloudview origin to the CloudView origin. And that should be everything I need. ScrollView did scroll. We'll now be able to do its thing. Now hopefully when I scroll this, the view stays in place.
Yay! This even works when we bounce right here because in this case the TableView 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 UI view.
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.
So... 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.
and I will be doing a little bit of a demo of what 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 0 because I don't need to wait. A couple of options I'm going to 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 going to use a linear curve option because by default, UIView 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 going to 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 going to adjust its origin so that it moves off-screen to the left. So I take the imageViews frame.origin.x and I'm going to 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 imageView.
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. 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.
Hi, 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. A bunch of new features in iOS 5.0 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. With that, thanks for coming.