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: wwdc2012-205
$eventId
ID of event: wwdc2012
$eventContentId
ID of session without event part: 205
$eventShortId
Shortened ID of event: wwdc12
$year
Year of session: 2012
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2012] [Session 205] Introducing...

WWDC12 • Session 205

Introducing Collection Views

Essentials • iOS • 53:47

Creating dynamic and incredible interfaces is easy with collection views in iOS 6. Learn how to get started with collection views and see how to easily organize data in grid-like layouts using the built-in UICollectionViewFlowLayout class.

Speakers: Olivier Gutknecht, Luke Hiesterman

Unlisted on Apple Developer site

Downloads from Apple

HD Video (246.8 MB)

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Welcome to this WWDC session on Collection Views. My name is Olivier Gutknecht, and I am an iOS engineer in the UIKit team. And today, we have a great new addition to UIKit. Sometimes, developing applications on iOS is really about pushing the limits on UI design and maybe finding new ways to visualize information. And we think Collection View is going to be an amazing tool for that.

What we're going to talk about today. First, collection view. Surprise. And we'll see the basics of collection view. The view architecture, how can you actually provide data and interact with it. And then, we're going to talk about flow layout. And flow layout is a standard layout we ship on iOS 6 for collection view. And you'll see how you can tune and tweak flow layout for your application's needs. So, what can collection view do for you? and David Wright, Rose and Columns. Lines of items.

Something that wasn't that easy to do or elegant in UIKit. We're improving that. And actually, we already use Collection View on iOS 6. This brand new Clocks app on iPad. This top view is just a very simple collection view. We use also Collection View in Maps in this new info pane, this Photos tab. We use Collection View in some GameKit UIs.

and I are going to show you how to do that. And I think it's going to be a great tool for your applications, too. So, let's get started. But first, A small comparison. We already have tools to manage collection of data on our platforms. On OS X, we have NSCollectionView. NSCollectionView, UICollectionView, same name. It's not exactly the same model. In AppKit on OS X, NSCollectionView is really about managing a grid of NSView controllers. And the model we use for UICollectionView is actually closer to UITableView. we have the same common principles.

But let me stress that collection view is not a replacement for-- oh, yeah. UICollectionView is not replacing UI TableView. We have a lot of built-in behaviors in TableViews. That's really one of the major building blocks we use for iOS application on iPad and iPhone. And we're not changing that. We have things like headers, footers. We have edit mode. We have row animations. Many of these don't really make sense in a collection view world, because collection view is more abstract and generic than TableView.

What did we build Collection View? We wanted to give you an extremely flexible way to represent data content in your applications. And we wanted to do that while keeping our usual patterns. We use all of the place in UIKit. So CollectionView is data source-based. It's delegate-based. We use cells. And if you used TableView before, you should be at home with CollectionView. And we wanted to do that and keep high performance in CollectionView, even with very large datasets in your app.

Let's check a quick example. Let's say that my data set is actually my vacation pictures. A few pictures, some albums, I want to be an app for that. And what my designer gave me is this. Okay. How can I build that with Collection View?

[Transcript missing]

A cell is really a representation for one item in your data set.

So you might have one picture in that library, and you want one cell to represent that. And you, in that case, are probably just going to use some UIImageView, set the image, bam, that's done. The important thing here is cells are really data-driven. It's your data model that drives what is in Collection View for the cells part. It's based on the data source.

The second concept we use in Collection View is actually a new name for an old ID. It's what we call supplementary views. And what are supplementary views? Well, it's when you want to add some views here, these two album titles, that are really metadata about a section. It could be an album title. It could be the album index somewhere else. It could be a block of text, the story of that album. The important thing is it applies to an entire section.

And like cells, it's data-driven. And the reason why we don't call that eaters or footers, because that's really the same concept that we used before in TableView, it's, well, CollectionView is not exactly table-based, right? So is that small thing a footer? Yeah, maybe. But, again, it's more generic than that. So we decided on supplementary views to describe these additional things.

The third concept we use in Collection Views, and that's new, is what we call decoration views. And... Decoration views is not like cells and supplementary views. It's not something that is going to be data-driven. It's going to be in the visual side of the world. So it's more about the layout of the collection view when you want to add some embellishment to some part. And here, it's basically two kinds of views. We have this top part and the shelf element that we repeat three times.

And decoration views are really useful to have, for instance, A background scrolling with your content, which again was something that wasn't that easy to do before in TableViews. And with these three elements, I can actually implement that design. So, so View Architecture in Collection View. Sales, Supplementary Views on the data side, Decoration View on the visual/layout side.

How do you provide content to a collection view? Well, we have this Objective-C protocol called UICollectionViewDataSource. That is something that one of your class in your application must implement. And when we're about to display things on screen, we need to call that data source a few methods so we can know how many sections do we have, how many items in a given section, and how should we actually configure our cells or headers. Oh, well, supplementary views in the more generic sense. So let's see how that works.

The first thing is we call from the collection view one method on your data source number of sections in collection view. Actually, You don't have to implement that one. If you don't, we just assume that we have just one section. How many sections? Two. Next step. We're going to ask for each section How many items do you have in your data source for that section? Well, section 0, 4 items. Section 1, 5 items.

And then, when we're ready to display things on screen, we're going to call on your data source, and you must implement that one if you want to display something. Collection view, cell for item at index pass. And then you should actually fetch what you need in your data set and configure the cell we're going to give you.

It's important to note that in this case, we will only ask you about these cells for what is actually on screen. : We don't want to allocate cells for every single item in your data set. That would be quite a bad idea on a memory-limited device. We have another trick for performance.

Again, it's a technique we used before. It's cell and view reuse. What does that mean? In this case, when we scroll a collection view, that might cause a few cells or views to go off-screen, right? And in that case, we don't want to deallocate these cells. We're just going to move these into a reuse queue.

When the user is about to scroll again, we need new serves. So we are just going to grab what we have in the reuse queue. Prepare that by asking you with your data source method, and then we can actually screw it up. So with that, we minimize the number of allocation and deallocation we need to do. That works quite well for large datasets.

But... We actually improved that. We were using that technique in TableView before. And we tweaked that. How? When you set up a collection view, and that's usually in this viewDidLoad method in your UI view controller, we ask you to register the class you're going to use for a cell, for a reuse identifier. That is, the kind of data, the kind of cell you want.

And after that, in the dataSource method, We're going to call you with CollectionView, the index pass we want to display. And what you will need to do is to actually call on the CollectionView the QReusableCell with reuse identifier. And then you can actually configure that cell by setting the image, returning the cell.

What if we don't have any cell available in ReaSQ? Before, you had to check for that. Not anymore. Why? Because you did help us. by registering that class. So we know the class for that cell. So even if we don't have a cell available in the reuse queue, we can instantiate that for you. So that code just goes away. And we like that so much, we added the same technique to UITableView.

So, let's summarize. We always instantiate a cell or supplementary view for you. You just need to register the class for that cell or that supplemental review of kind, header, footer, anything. You can also set up that cell in Interface Builder and just register as an IP, something we had before in TableViews. And then, in DataSource, Just in the queue, we have two methods, one for sales and one for supplementary views.

Nice and easy. Then, how do we interact with content? It's time for yet another Objective-C protocol for you, UICollectionViewDelegate. And that delegate will control how cells are actually highlighted when you tap. Selected. And also, we have support for these nice menu actions when you long tap a cell.

And that's something we actually improved, too. So just to be clear on the vocabulary, That cell on the left is an highlighted cell. It's when I touch the screen, but before touch up, right? And on touch up, what happens is the cell might be selected, which is the case for these three other cells.

How did we improve that? First... On each cell, we have two properties, selected and highlighted. And we defined a very precise flow for highlighting and selection in Collection View. How does that work? First step is when the finger touches the screen, Here we call on your delegate if you actually implement that method. CollectionView should highlight item at index pass. And that's new.

In TableView, : You can control selection, but even if you don't want a cell to be selected, you would get that highlighting feedback, which is not that good from a user experience point of view. So in Collection View, We first ask, should we actually highlight the cell? And if you return no to that method, we don't highlight, but we completely bypass the selection process. stops here. If you return yes, then, well, we switch that highlighted property to yes, and we call on your delegate didHighlightItemAtIndexPass.

The next step is : When we switch up, should we actually select that cell? So, again, if you choose to implement that method, CollectionView should select item at index pass. And if you return yes, okay, we do a bunch of things. We switch selected to true. We switch back, highlight it to false. And at the same time, we call CollectionViewDidAnalyteItemAtIndexPass and CollectionViewDidSelectItemAtIndexPass. So you can hook whatever you want on the actual end of the selection process.

What's next? Unselect. So that's when you tap again a cell. And in that case, we call should deselect item at index pass. Returning yes means that you deny unselect. So the cell would stay selected. If you return yes, then... We call didSelect, didDeselect, item at index pass, and we switch back the selected property to false.

So that's a very precise flow for selection and highlight in Collection View. And, of course, you can also set up on Collection View if you want selection or multiple selection or no selection at all. And we do the right thing. Then... Bringing actual content on screen. We have two interesting things here. Cells and layout. First, cells.

There is one thing you need to know. The collection view is not in the content business. It's your content. We do not define any style in collection view. So you don't have, like, table view things like, give me that cell with one image, one label, two labels. No styles at all. But... We do help you by tracking selection and highlight, as we saw. And we do actually a bit more than that.

When we call setHighlighted or setSelected on a cell, what we actually do is we walk the entire view sub-tree for that cell. And if any view here actually implements setSelected or setHighlighted, we're going to call that. What does that mean? It means that if in a collection view cell you actually use any standard UIKit control, you will get selection and highlight for free because we're going to call that on the UIKit controls.

The next thing we do-- and you can do that for your own custom view, of course. The next thing we do is We give you two additional properties on CELS. You can configure a background view and a selected background view. And if you do that, we're going to switch when we track selection, background view and selected background view. So it's really easy to implement these styles.

So we know what the UICollectionViewCell view hierarchy looks like now. We have UICollectionViewCell, and we're probably going to supply that. The first view is the background view, if you did provide one such view to CollectionViewCell. The next view is the selected background view, if you did configure that.

And on top of that, we have a content view that we set up for you. And you should really add your own content to that content view and not to the main CollectionViewCell view, because that would mean that your views would be behind background or selected background view, which wouldn't be a good idea.

Okay. Now... That's what we know about CollectionView. It's actually a ScrollView subclass. It cooperates with UICollectionViewDelegate and UICollectionViewDataSource, which are in your application. And it manages a bunch of cells. We have something else. UICollectionViewLayout. And UICollectionView actually doesn't know anything about how to set up cells on screen.

It cooperates with a UICollectionViewLayout instance to do that. And might be just a subclass of that, like the flow layout we ship in iOS 6. But you can actually subclass UICollectionViewLayout. What does that mean? It means that you can bring your own layout to the party. A layout's responsibility is to compute, generate layout information for each cell, supplementary views, or decoration views we would have in a collection view. And these layout attributes, this layout information is a few things you might want to set. Eventually on a cell, like position for a cell, The actual size for each cell. But you can also set opacity.

Even z-index, if you have overlapping cells, with the index you can control which cell is going to be above or below the other. And you can even set up a simple transform on a cell so you can scale a cell relative to others. And because UICollectionViewLayout attribute is actually a class, you can supply that and add other information that we're going to give to your view, your cell class. Thank you.

So, what does that mean? Well, that's a layout that UICollectionViewFlowLayout might generate perfectly fine layout, two sections, two supplementary views for header-like things, and a bunch of cells. But that is a perfectly fine layout. It's just not generated by flow layout, but we have two sections. Two subliminal reviews, bunch of cells, and that's something that one of your class, subclassing your UICollectionView layout might actually generate. So, now, let's talk about flow layout.

FlowLayout is an interesting class. Something we wanted to share to give you some basic behavior for Collection View. And what can we do with CollectionViewFlowLayout? We can go from really simple things, some things that you asked us to do before,

[Transcript missing]

having it different sizes. Eaters and footers with, again, different sizes. And CollectionViewLayout, CollectionViewFlowLayout make that really easy to do. So what I want to do now is to give you a very short demo of CollectionViewFlowLayout.

This is an extremely simple collection view with a flow layout. And here, my cells are just a small label with just one letter. And that section is just showing these cells. : Working nicely. And if we have another section, like when I want to display Helvetica, notice that my cells are now-- with different size. And that's built in UICollectionViewFlowLayout.

Another thing we built in is when you actually rotate a device with a flow layout, We nicely crossfade cells if we need to. We actually detect-- we actually detect if it's going to look good or not when we make cells. If it doesn't, we crossfade. For free. We don't have anything to do here. The next demo I want to do is a small gallery app. And I think that's something that you also requested before. Horizontal starting.

So it's much better than just table view in a horizontal mode. That's a collection view, and here I have a custom header on the side. A few items in that section. I go to another section with different insets. : I'm going to start with the collection view. And here I just customize the internal item space between my cells. And again, we support rotation out of the box.

That was FlowLayout. Well, the demo of FlowLayout. And so FlowLayout is... A line-oriented layout is just not grids. You can configure that as a grid. You don't have to. And because that's really useful, in FlowLayout, we do include support for headers and footers. And to talk about FlowLayout, I'd like to introduce you to Luke Hiesterman. Thank you, Olivier.

So as Olivier said, you can bring all kinds of arbitrary layouts to Collection View, but we've built in a tremendous layout that we think is really awesome that we're shipping with iOS 6 that you guys can use to produce some really great UIs already today. So I'm going to talk to you about UICollectionViewFlowLayout, which is our built-in layout, which you just saw on screen in Olivier's demo, and all of the different bells and whistles we have for you to tweak within that layout to be able to do interesting things right out of the box. So to start off, let's define what flow layout means. Maybe this is a sort of interesting term for some of us. Well, we think of it as really a line-oriented layout.

We said right up front you're going to be able to do grids, and absolutely. Grids are the degenerate case of a line-oriented layout. If every item is the same size, we end up laying them out in something that looks like a grid. But this could be a grouping of lines of things that are not of like size.

If you have different sizes, we will lay them out sort of on a line until we hit the end of the screen. We break to another line, and we start laying things out again. It's sort of like a text system in that sense. And we include support for headers and footers, which you've seen.

So we have a bunch of ways to customize the flow layout, and these include everything you see here. You can change the item size, number one. You can change the spacing between the lines. You can change the spacing between the cells. You can change the scroll direction. So, you know, we're all familiar with horizontal or rather vertical scrolling that we've done in TableView.

And one of the big requests people have had is, hey, I want something like a TableView to scroll horizontally. Well, we haven't given you a horizontally scrolling TableView. We've given you something better. We've given you something that can scroll horizontally and display content in whatever way makes sense.

The little painting demo that Olivier showed you, acted similarly to what a horizontal table view would be in the sense that we only had one cell per row there, per column, but we accomplished that by using insets around the section, which is one of the other bells and whistles that we'll talk about here.

And you can also specify the sizes that you want to use for your headers and footers. So this is all within the built-in flow layout that we're talking about right now. So the item size for any particular thing can be configured globally based on a property on the actual flow layout. And you can just say, "Hey, I want to make my item size 100 by 100," or whatever it is.

[Transcript missing]

We also provide line spacing. This is different from the inter-item spacing in that if you have, say, a vertically scrolling grid, then the space between the items is that horizontal space that we just saw on the previous slide. But line spacing, also provided as a minimum, gives us the ability to provide the definition of how much space is between the individual lines. And that's pretty straightforward as to what that means if all your items are of the same height in a vertically scrolling layout.

But if you have something that looks like this, then maybe it's a little less obvious right out of the box what that actually means. Well, since it's a minimum, what we mean, what we guarantee is the distance from the bottom of the furthest down item is-- and to the top of the furthest up item on the following line, that is at least the minimum value that you have specified. So that's what minimum line spacing gets you.

So spacing is something, both of these properties can be configured globally. We have properties directly on the layout. You can say my minimum spacing for the line, my minimum spacing for the item is this much, and you're done. For a lot of us, this is going to be the way to go.

We set it up when we configure the layout, and we're done. But just like with item sizing, we have delegate methods so that we can specify this dynamically. Some sections may have different spacing between their items and between their lines than other sections. You saw this work in Olivier's demo before, where different sections had different spaces between the items.

So between these three properties that you've talked about or that we've talked about, you may have started to pick up a pattern that we're introducing here in FlowLayout, which is everything can be configured globally if you want to use that thing for your FlowLayout everywhere and set it up up front, or we can do it on a per-delegate basis. This is true basically for all properties on the FlowLayout.

And the thing that makes this convenient for you is the delegate that the FlowLayout uses is actually the delegate of the CollectionView. So that same delegate that gets the item did select and should highlight all of those highlight selection calls, that same delegate is going to get calls from the FlowLayout asking for things like, things like item sizing and such.

So to accomplish that, the flow layout actually defines an additional protocol which extends UICollectionViewDelegate-- and we call that UICollectionViewDelegate-- flow layout

[Transcript missing]

You're specifying a width and a height, but we're only going to actually use one of those dimensions. And which dimension we use depends on the scroll direction.

So this is a header that we're going to put into a vertically scrolling collection view using UICollectionViewFlowLayout. And you specify some height for that collection view. You actually give us a size, because we're going to ask size for header and section. But the dimension that we care about is the height. and we're going to take that height and stretch the view out to fit the bounds of the collection view.

So... and I will be working on the collection view. We will stretch the height of that header view to fit the collection view bounds that way. So the dimension that we care about depends on the dimension that you're scrolling in. Just as we change the dimension on which we lay out lines, we change the dimension in which we stretch your headers and footers.

So to summarize what we have done with headers and footers, these are defined as supplementary views in the CollectionViewSpeak. The flow layout actually defines two types of supplementary views that are used, section header and section footer, namely. And you'll notice that we've actually kept the term flow layout out of those definitions. And that's because if you go write your own layout, you may find that your layout works in section headers and section footers as well. And you can just reuse these supplementary types in your own layout.

So in order to get them on screen, it's really just the same dance that you're used to doing with cells. You'll register a class or a nib, and then when in your data source you'll implement the appropriate method, we will ask you for a view for the appropriate kind, and you can dequeue a view of the type that you have registered and return it to us. It's really the same thing that you've done with cells, so that should be pretty simple code for you to write. Let's talk about section insets. This is another little tweak that you can do on your content.

And so if you imagine having a bunch of content that looks like this, you got it laid out, it's sort of within, it's got a header on top and a footer on bottom and a bunch of stuff in between, section insets is a property on that content that allows you to specify a box surrounding the content, and then the insets, top, bottom, left, and right, allow you to shrink that box. So that bounding box can change your section header and footer stay put, but your content gets laid out in a smaller area. And that's what section inset will do for you.

We used that in Olivier's demo before in order to ensure that we only had one column for each of the artistic drawings, and that got us a nice little line, horizontally scrolling line layout. So those also can be configured globally or via the delegate. Very simple. It will be a pattern that you'll be used to.

When you walk out of here, I want you to think about the Flow Layout as your new best friend. The Flow Layout is the thing that you want to go home and play with tonight when you roll out Collection View and you want to see what it's capable of, what kind of powers that it can bring into your life for creating new, beautiful UI. It's really, really powerful.

We have a lot of little bells and whistles that you can tweak in there to produce really great new user interfaces that maybe would have taken a lot, a lot of code to write in iOS 5, but in iOS 6, you'll find yourself building them in an evening. So we have a lot of built-in behaviors that let you do that. The amount of time that you'll save, just, you're going to go buy yourself some ice cream. You'll be so happy about it. Yeah.

And all of this that we've shown is almost the tip of the iceberg. We've designed Collection View so that layouts themselves are subclassable. And this includes UICollectionViewFlowLayout. By subclassing the flow out, you can provide all kinds of little tweaks specific to whatever your imagination has come up with.

So this is going to be a really fantastic starting point for all of you to make applications that are going to just blow us all away and even I can't dream of today. So with that, I'd like to invite Olivier back on stage to show us a beautiful demo of the capabilities of Collection View and wrap -- put this whole thing back together for us. Doctor? First, a quick recap.

So what do we know about Collection View? It's a data-driven view, data source-based. We do selection and ROI tracking built-in for you, and we help you build your cells to support that. It's based on cell decoration views, elementary views, and collection view actually doesn't know anything about layout. That's the job of the layout class.

We have more in Collection View. We have fine-grained, block-based updates when you change your data source. We have a very fine and precise flow of the layout, and the Collection View is going to manage insertion and deletion of items. We have some built-in hooks for animation and relay out. And you saw the one with this rotation crossfade with FlowLayout. CollectionView is actually a ScrollView subclass, but it's quite well integrated. The layout can know that we're scrolling and compute some final position for a cell, for instance.

and I are going to show you how to do that with some layouts. That's quite a big deal in Collection View. But I don't want to talk about that. Let me show you. What we want to do now is to give you a little taste of what Collection View can do, actually.

OK, so what do we have here? It's a very simple flow layout. : Every cell having the same size. I just added a few section insets to show you that we have different sections. I can actually select on that. I even added some more keyframe animation. And... What happens when you actually insert or remove items? Well, when we insert, it's quite easy. We just move new cells to the right place. And when we remove, if we remove within a section, what do we do? Actually, we just animate. We don't have anything to do. You get that behavior for free.

I might have forgotten something about Collection View. For a given Collection View with a collection Configure with a layout. You can call a method on CollectionView which is setCollectionViewLayout. So you can switch to a new layout. What do we do in that case? Well, we animate. And that is one line of code.

[Transcript missing]

That grid layout, that stacked layout, they are quite generic layout, right? Could apply to pictures, to CD albums, anything. One thing you can do if you write your own layout could be to actually peek into your data set and build your layout based on some information about the actual item you want to display. Like, for instance, for pictures, I don't know. GPS coordinates. And that's just a custom layout with one small decoration view, one big decoration view. And we just animate.

When we switch layout like that, we actually call a method on each cells that are going to appear in the next layout. Why that? You might start with a cell with a very small size and get into the layout where the cell size is huge because the cell doesn't decide. It's a layout job, right? So in a huge cell size, well, you could add additional information, a label for the picture, the date, anything else. Or what you could do, too, is just tweak the visual appearance for that cell so it matches best the new layout.

Here, I'm just changing the corner radius when switching to that new layout. So that's another custom layout. quite a simple one. And when I implemented that layout, I needed to-- For my implementation, I need two properties. One is that reference point for that cluster of cells. And the other one is the cell distance.

: One thing I could do is to actually add a gesture recognizer on my collection view and just change the distance and that reference point on my layout is just a parameter, right? Just call the setter. So let's pinch. And move. And I'm just changing two things. Set distance. Set point. That's all. And what happens is the layout invalidates the collection view, compute the new state for the cell, set everything to the right place. Again, it's just a few lines of code.

But what if I just call setDistance, setReferencePoint? What's going to happen? Well, in that case, we change the parameters of that layout, so the layout is going to jump in the next state, which visually is maybe not what I want. So what we can do is use this fine-grained, blog-based update mechanism. So we can ask the CollectionView to actually animate when changing a parameter in code. for a layout. No ends.

So, you can do some really crazy layout. Please talk to your designer before. Things like circle layouts, wave layouts, grid-back layouts-- maybe not grid-back layouts. And that one is actually quite interesting. Remember in my first layout, the grid one, I was adding and removing items from my data source, and cells would just appear and disappear, or even animate. What happens in that case? Well, we try to do the right thing, which is we're going to actually add the cell at the right position or just fade out a cell when we remove an item.

Everything should just work out of the box. One thing you can do when you implement a custom layout, you can define the initial position for a cell when it's appearing. You can define the final state for a cell when it's disappearing. And what is that initial and final state? Well, again, it's that UICollectionViewLayout attribute that define cell position.

Cell size, cell opacity, a simple transform, and you can do things like that. And that was adding a cell, but you can get creative for deletion. Okay, so that was quite a simple layout. Because that transform actually, it's a CA transform 3D. So, what could you do with that? Something like that.

And it's actually quite an interesting layout, too. Because in that case, when I swipe, I actually need to compute again the cell state. And CollectionView is just tracking that and asking the layout at the right time. And you might notice, too, if I just scroll, that the cell perfectly snapped in place. And that was the scroll view/layout integration I was talking about. And, of course, selections still work.

My last layout is my final layout. That was not a Keynote animation. That was just a 10-lines layout. One thing about this demo, every single layout, every single custom layout we add here is about one page of code. It's that easy to create new custom layouts with Collection View.

Collection view is all about your content, your sales, your layouts. Simple things are quite simple because we ship flow layout for you, and we can't wait to see what you're going to do with that. So, for more information, Please check the UIKit API documentation or mail Jake Behrens or Evangelist. And we have this iOS 6 developer forums online. We're going to have some sample code posted really soon now. So again, thank you. Hope you enjoyed that. Have a great week.