Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> TROY STEPHENS:
Thank you for coming.
Welcome to Session 225, What's
New in NSCollectionView.
My name's Troy Stephens,
I'm a Software Engineer
on the AppKit team and
I'm delighted to get
to answer this question for
you today, what's new indeed.
Let's find out.
NSCollectionView has been around
for a while on OS X since 10.5,
and it provides a handy way
to display a grid of items
in the user interface,
for example here,
in the Screen Saver Pref
panel, we have a grid
of items representing
the different screen
savers available.
CollectionView is good at
this, displaying a grid
of identically sized items,
you give CollectionView an
item prototype, which consists
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you give CollectionView an
item prototype, which consists
of basically, a view
subtree of your own design,
and an associated
ViewController that manages it.
CollectionViewclones that item
prototype, to populate itself
with items that represent
your model objects.
CollectionView supports
selection, drag and drop,
animated re-layout, all around,
it is a very handy
class to have around.
Now enter UICollectionView
on iOS,
a cousin to NSCollectionView
that is also very versatile.
We see it here in
the World Clocks part
of the iPad Clocks app.
UI CollectionView,
like its name implies,
is useful for displaying
collections of items,
where each item, once
again, is represented
by a view subtree that's
completely of your own design,
usually, these are loaded from
a nib, withUICollectionView.
And UICollectionView
supports mixing item types,
you can have different nibs,
prototypes for different items,
you're not stuck with just one.
UICollectionView supports
optional header views,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
UICollectionView supports
optional header views,
and footer views surrounding
your items, and bracketing them.
This is especially useful
when used in conjunction
with the ability to group your
items into sections if you wish.
Each section can have a
header, and a footer view.
Layout is very flexible
and customizable,
there is a default flow
layout that handles about 90%
of your needs and is
very customizable,
you can tune its parameters to
usually get something close,
at least, to what you want.
UICollectionView is
also open to arbitrary,
developer-definable layouts.
Any kind of layout algorithm
that you can implement,
UICollectionView can use,
to apply to the items
that it shows.
Importantly, UICollectionView
is scalable.
It has smart behaviors in
it, so that it can scale
to potentially large numbers
of items, and it is smart
about just instantiating the
items for model objects in view,
and recycling or reusing items
that have scrolled out of view
to represent other model objects
that have been scrolled
into view.
That's very handy.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Like everything else on iOS,
UICollectionView was designed
from the beginning to
always operate layer-backed,
which gives it the ability
to present very fluid,
high-frame-rate animation,
as the items
in the Collection View move
around, and come and go,
it can give you have a
very nice, animated effect.
With all of these
great features,
and an API that developers have
already become familiar with,
and wide adoption and
use through iOS apps,
we thought that UICollectionView
would therefore form an
excellent basis for the new
and greatly-improved
NSCollectionView
that we're introducing
in El Capitan.
This new NSCollectionView
inherits all
of the scalability
behaviors of UICollectionView.
It knows how to instantiate
items only as needed,
just keeps a few of them
around, a little more
than what's visible and is able
to reuse or recycle items rather
than reinstantiate them.
That saves some overhead, you
can group items in sections,
you can give those sections
header, and footer views,
if you want, put
anything you want in them.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Layout is completely
customizable,
so NSCollectionView is no longer
hard-wired to think I'm a grid.
You can plug any kind of
layout you want into it.
We can handle items that are of
variable sizes, the items can be
of all different types,
you can mix and match,
and Flow Layout especially
is capable
of handling that
very gracefully.
Appearance, as before, it
is completely customizable,
you can define your
Item View subtrees
to look however you want.
The CollectionView is your blank
canvas, to use however you want.
You have control
over animations.
When animations are performed,
and with what durations.
We'll see how to do that.
Of course, not content to
just port UICollectionViews
capabilities to OS X, we wanted
to make the new NSCollectionView
feel really right
at home on the desktop.
One of the important
technologies we deal
with on the desktop
is drag and drop
which NSCollectionView
has supported all along,
but as part of bringing
UICollectionView Layout API
to the desktop, we have
augmented the API with a couple
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to the desktop, we have
augmented the API with a couple
of new methods we'll
talk about at the end,
that basically enable
any layout,
including your own custom
layouts, to perform hit-testing
to identify drop
target candidates.
We'll look at how
to do that later.
Any custom layout of your own
design can support Drag-and-Drop
like a first class layout.
Rubber Band Drag Select, you
use that to drag across items,
and select groups
of items in bulk,
that's fully supported
as before.
We have modified the selection
and highlight notification
methods, the delegate methods,
that handle those occurrences,
to be able to handle selection
and highlighting of items in
bulk because that's something
that tends to happen a lot
more on the desktop, you know,
you tend to do a Select All
operation or a Deselect All,
or a big Range Select.
We wanted to be able to
handle those very efficiently.
There is slight adjustments
to the APIs.
As before, however, items
are still represented using
ViewControllers on the desktop.
We think this provides a
great opportunity for you
to compartmentalize
your code neatly,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to compartmentalize
your code neatly,
and have your controller code
separate from your view code.
Better code organization.
One last nice little touch
we added, is the ability
for CollectionView
to automatically find the
appropriate nibs to use
for items, if you just
follow naming conventions,
if you name the nib
identical to the identifier
of the item type
you're requesting
from the CollectionView,
you don't even have
to register your item nibs with
the CollectionView anymore.
It saves you a little
work, a little bit of code.
So our goals for
today, I wanted this
to be a really hands-on session,
I want you to walk away ready
to use the new CollectionView.
We'll look at how to wire up one
of these new NSCollectionViews,
where we're using the new
API on 10.11, along the way,
we'll learn what's different
on OS X versus on iOS,
and we'll have a
little something
for everybody here I think.
Whether you're a
veteran iOS developer,
maybe bringing companion
apps over to OS X,
you have used UI CollectionView,
you're familiar with the API,
you want to port that knowledge
over, maybe some code over,
we'll have information
useful to you.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
we'll have information
useful to you.
Maybe you're an OS
X developer working
with NSCollectionView
already, and you want
to learn the new API
paradigms and how to do that.
We'll have enough
of an introduction
into the UICollectionView
APIs to get you started.
But even if you've not worked
with either before we're going
to have enough introduction,
and enough nuts and bolts
and a code sample, to go
along with today's session
that you can study, to learn how
to get up and running quickly
with the new CollectionView.
We'll start with a quick
overview of the concepts,
the basic concepts that we need
to understand about the new API
and then we'll dive into nuts
and bolts of how the API works,
which methods are important,
what to use, and we'll wrap
up with a quick conclusion.
First with that overview.
In the old model of using
CollectionView, NSCollectionView
on OS X 10.10 and earlier,
you would wire your
CollectionView's content
property to an array
or array controller
that references your model
objects, that's how you wire
up your model, and you
provide an item prototype,
that's an NSCollectionView item,
a subclass of ViewControllers,
you have basically
got a ViewController,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you have basically
got a ViewController,
and an associated view subtree,
and this is what's going
to get cloned to populate
your CollectionView.
Lastly, yourCollectionView
might have a delegate,
if you want to support
Drag-and-Drop,
that's your delegate's
responsibility,
so you would wire up
a delegate for that.
With the new API, a few of
these things have changed.
Instead of providing a content
array, what you are going
to do now on El Capitan,
is wire up a data source.
The data source protocol for
CollectionView is very simple,
as in iOS there are only
two required methods,
it's very quick and easy
as you will see to wire
up your model to CollectionView.
You still have a
delegate, as before,
but now the delegate has the
opportunity to participate
in selection and
highlighting of items.
We'll talk about
that in detail later.
Instead of an item prototype
you now typically provide a nib
file, that hasyour
example item in it,
and it's associatedview subtree.
You're not limited to just one
of these, as I said, you can mix
and match different
types of items,
you can have multiple nib files,
one for for each type of item
and the view trees can be
completely different for these.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and the view trees can be
completely different for these.
Last but not least,
very importantly,
we have taken the layout
functionality and factored it
out of CollectionView so
it is no longer hard wired.
We now have a very
modular model, like on iOS,
so you can take your
existing CollectionView,
unplug the layout that's
currently connected to it,
plug in a different layout, and
suddenly your items are laid
out with different sizes using
a completely different layout
algorithm, and these layouts
are completely interchangeable,
nd you can even make the
change to a different layout
in an animated-transition
kind of way.
very easily, as ourcode
sample does.
For customizing layout, your
layout can also delegate
to your CollectionViews
delegate.
You can implement certain
optional methods to allow you
to make per-item
layout adjustments.
You don't even necessarily
have to subclass,
if you want a custom layout.
We'll take a quick look
at the layout classes.
These arevery similar but
not identical, on iOS.
As on iOS,
NSCollectionViewLayout,
his is the base class that
defines the common behavior,
the API interface
for all layouts.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
NSCollectionViewGridLayout
is new and unique to OS X
and its job is basically
encapsulate NSCollectionView's
existing, sort of stretchy
grid layout algoritm,
in case you want to use
it with the new APIs.
It gives you a stretchy
grid, where it tries
to make all items the same
size, but they're limited to min
and max sizes, and it tries
to basically fill its visible
area as much as possible.
Sometimes useful,
but this is sort
of a legacy layout right now.
It doesn't yet support sections
or header or footer views
and FlowLayout is
generally much more flexible.
We usually recommend that
you you start with that.
NSCollectionViewFlowLayout
is basically identical
to UICollectionViewFlowLayout
on iOS, it's a very powerful,
general layout algorithm,
and the algorithm is much
like flowing text fragments
or CSS boxes in flow,
if you've dealt with
either of those problems.
Basically, you can have
variable item sizes,
and the layout algorithm
canhandle that nicely.
It willrack up items
into rows or columns,
depending which orientation
you give it.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
depending which orientation
you give it.
When it fills up
a row or column,
it'll wrap to a new
one and continue on.
FlowLayout supports
sections with optional header
and footer views, and it
is generally very powerful
and customizable, so even
if you do need to subclass,
usually you'll want to start
with FlowLayout, and subclass
from there to get what you want.
You're always free to subclass
NSCollectionViewLayout,
to get a completely
custom layout.
Our sample code todaydoes
just that.
Layout attributes objects aren't
always immediately intuitive
to those who look at
them for the first time.
This is a concept -- the
same concept as on iOS,
and once you understand what it
is, it really is very simple.
Imagine that you can
take a view's frame
and other assorted properties
and encapsulate them
separately from the view.
That's what LayoutAttributes'
job is.
You have an instance
of these frames,
the most obvious one , right?
you need to know the
position and size of an item,
but there are other ancillary
attributes, such as Alpha value,
Opacity in other words, Zindex
for back-to-front sort order,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Opacity in other words, Zindex
for back-to-front sort order,
and whether the view
is hidden or not,
which can also be
considered layout state.
You're taking state,
and snapshotting it,
what this enables the new APIs
to do, is to reason about items
that are not currently
instantiated.
Remember, we're just lazily
instantiating items on demand.
We end up creating these,
and passing them around,
these layout attributes
instances,
that's what the Layout APIs
deal with, they pass them around
and then eventually they end
up getting applied to items
or views at layout time.
Applied in the sense of
setting an animation target
for a transition to a new state.
That's all they are really.
You can group items, that's
pretty straightforward,
you can break your items
up into groups now,
each group can potentially
have a header above it,
and a footer below it, or
this also works sideways,
ifyou're doing that orientation.
The header, and footer,
together with the items
that they bracket,
constitute a section,
our first section
here is section 0.
The items within that section
are numbered 0, 1, 2, so on.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The items within that section
are numbered 0, 1, 2, so on.
This is exactly the
same as on iOS.
The next section can have
a header, a footer view,
together with the items,
now we've got section 1
and the items in that
section are again numbered 0,
1, 2, and so forth.
So clearly we have a need for a
different way to address items.
We're going to start addressing
items like we do on iOS.
We need to know not
only the item index,
but the section index.
This has consequences for
existing APIs, and accounts
for a lot of the API
changes that you will see.
For example, the
ItemAtIndex method,
which takes a single-integer
index,
is no longer sufficient.Now
that we have sections,
we need to know the
section number too.
So APIs like this are now
soft-deprecated in favor of ones
that take index paths.
And NSIndexPath is just
an existing value type
that lets us very conveniently
encapsulate a section index,
and an item index, together
in an object, a value object
that we can pass around,
throw into collections, so on.
A lot of the API changes you
will see actually are just
accountfor this simple
transition away
from single item indices.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
from single item indices.
You can still use the old APIs
if you have a single-section
CollectionView,
which is the default, but if
you might be using sections,
we encourage you to
use the new APIs.
We're obviously starting
to get into nuts and bolts,
we'll embrace that, and get down
to looking at our example code.
The example today is
CocoaSlideCollection,
and it's basically
an image browser
that uses a CollectionView
to present a folder
of ImageFiles for
you to look at.
For each ImageFile
in the folder,
we show a thumbnail image
and assorted image info.
We position these using the
Flow layout that comes stock
on the system, and our
own custom layouts,
that you will see
how to implement.
We're going to suppose that each
of our Image Files can have
tags associated with it
and we're going to
use that as an excuse
to show off the ability to
have sections with headers
and footers, we're going to be
able togroup our items by tag.
We'll also support
selection and Drag-and-Drop
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We'll also support
selection and Drag-and-Drop
of our items using the APIs
that we'll discuss today.
To break this down into
parts, we'll break it
down into six parts, so we
can do this step by step.
First, of course, we want
to make items appear.
That's always nice.
That's the big hurdle.
When you get stuff to show
up, you can get more advanced.
We'll do that quickly.
Thenwe'll look at grouping
those items into sections.
Next we want to look
at how do we handle it
when the model changes,
the ImageFiles come and go,
how do we update
our CollectionView.
We'll see how to
do that properly.
We'll look at handling
selection, and highlighting,
of the semantics of that,
handling Drag-and-Drop and last
but not least, the really
fun part, we'll look at how
to make custom layouts
of ourown.
First, making items appear,
back to our model here.
This is the new API again.
We need to provide a data source
that implements those
two required methods.
We'll need to provide an
item nib, simple enough.
Then a CollectionView layout.
The two required methods are
simply give the CollectionView
the ability to ask how many
items are in this section,
by default we have one
section, it is going to pass 0
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
by default we have one
section, it is going to pass 0
for the section index, it'll
just return the number of items.
The second method's
responsibility,
is to actually instantiate
items,
or it could be actually
reusing the recycled items
under the hood, with help
from the CollectionView
and return them back
to the CollectionView.
In CocoaSlideCollection
our basic model object
to understand is the ImageFile.
An ImageFile basically
references a URL of an ImageFile
that we found on disk in
the folder we're scanning,
that includes the file name
that we're displaying at the top
of the slide, the file's type
which we displayed a
user-readable description of,
the pixel dimensions
of the original image,
then a thumbnail, of course.
You will see those
around in the source code.
An image collection owns
an array of ImageFiles,
An image collection also
owns an array of tags,
each of which owns an array
of ImageFiles that have
that tag applied, and there is
an untagged ImageFiles array
as well.
First we'll look at
making items appear.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
First we'll look at
making items appear.
We'll go over to the
demo machine here.
Let's get this up and running.
We'll open our Xcode project.
Things are, you know,
mostly ready to go,
but we have no CollectionView
in our window.
That's going to be a problem.
We'll look at how to
actually get a CollectionView.
So going into our
Resources group here.
We have a BrowserWindow nib
that holds our main window.
Let's look at that.
We'll go in the library here,
and search for a CollectionView.
We'll drag it out.
We'll size it to
fill our window.
Apply constraints to it.
That's going to be our main
document view for this window.
Okay. Now what we did, what we
actually got when we dragged
out a CollectionView,
this is a lot like working
with a Table View
or Outline View,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with a Table View
or Outline View,
you're actually getting
a CollectionView embedded
in a scroll view unlike on iOS.
Scroll view is a separate
thing that's composed
with a document view
that you want to scroll,
you don't inherit the
scrolling behavior,
it is done through composition.
We have a scroll view.
I said that the new
CollectionView is designed
to run layer-backs, we're
going to go over here
to our inspector, and we'll set
the [indecipherable] property
on the scroll view to
ensure layer-backing.
Now, we'll drill down to
the CollectionView itself,
which is the scroll
view's document view.
We have a new properties
inspector here in Xcode 7
that supports some of
the new capabilities.
We choose a layout we
want to use, such as Flow,
and even set its properties.
In this sample app
we're actually going
to switch programmatically
between the layouts,
so we don't really need the one
with we unarchived from the nib,
but we can set that there.
You can do fun, simple things,
like set the background color,
as soon as I find
the color panel.
The more interesting thing,
is that you have to hook
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The more interesting thing,
is that you have to hook
up that data source, right?
So, our file's owner in
this project is an instance
of APL Browser Window
Controller.
We have a window controller
that manages the window,
that's also going tp be our
data source, and our delegate
for our CollectionView.
We'll wire that up here
from the CollectionView
to the file's owner, it's going
to be the CollectionView's
data source.
It will be its delegate too, to
so we can handle Drag-and-Drop,
we'll wire from the file's owner
back to the CollectionView,
we have an ImageCollectionView
outlet that we've defined
to make it easier to
find our CollectionView.
That's basically what we
need to do in our nibs.
We have also got a slide
nib that we created.
It holds basically a container
view that's referenced
by a slide, our slide class
is a subclass of collection,
NSCollectionViewItems.
We've subclassed so we can
add some functionality there,
our own custom controller
functionality,
the root view is just a
container that will be sized
by the CollectionView's
layout algorithm.
Then, we have controls,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Then, we have controls,
text fields that have autolayout
constraints set on them,
relative to their containers.
The layout will set the frame of
the item, the item's root view,
and the rest will all be done
by autolayout internally.
I have also used bindings
to basically connect the
value displayed by each
of these text fields, through
the slides-represented object.
Remember a slide is a
CollectionView item,
therefore it is a
ViewController,
ViewController has a
represented object.
That's where we're going
to connect our item
to the model object
it represents,
to the ImageFile instance.
We can access properties
of that instance.
All we really are going to
need to do is wire our item
up to the represented object,
i.e. its ImageFile, and then all
of these controls
will just populate,
including the image
view over here.
Because we're using a separate
nib file for the modern API
for CollectionView, we're
going to prune some stuff
that Xcode put in
here by default still.
Our image CollectionView
still has an item prototype.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Our image CollectionView
still has an item prototype.
We want to get rid of that.
Let's unwire it.
That will interfere
with what we're doing.
We'll delete the item prototype,
we'll delete the views
associated with it.
We don't need those.
We can build and
we're almost okay.
If we look in the warnings
here, we see a reminder,
we didn't implement the
required data source methods,
there are just two of them, so
let's go do that real quick.
We'll go to Browser
Window Controller.
Look here, where the data
source methods should be.
Fortunately I typed
some in advance.
We'll just drag in.
For a non-section CollectionView
this is very simple,
we implement CollectionView,
number of items in section
by default, the CollectionView
assumes one section,
we return the count
of ImageFiles
in our image collection,
and the other thing we need
to do is make items on demand.
The CollectionView will
send us CollectionView Item
For Represented Object
At Index Path.
The important thing here
is that we're calling back
to the CollectionView,
and saying make item
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to the CollectionView,
and saying make item
with identifier, which
is a little misleading,
make really means
make or give me
than existing one you can
recycle for index path.
We just pass in the index
path that we were given,
that identifies the item.
As I said, we want to wire up
the items represented objects,
so we can find the corresponding
properties to display just
for that item instance.
We've got a little method
here that we factored out,
ImageFile At Index
Path, that lets us dig
into our data model real simply,
and find the corresponding
ImageFile instance.
That's all we need to
do, return the item back
to the CollectionView.
If we're feeling brave maybe
we can build and run this,
and see if it actually works.
So, we're going to come
up with -- there you go.
By default we have
a window pointing
at library desktop pictures,
and it scans that folder.
It looks for the ImageFiles
and presents them using
CollectionView items
and we scroll through here, the
items that were out of view,
are actually being instantiated
on demand, or even recycled
from items that just
scrolled off the top.
You can resize, the
layout reflows
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and we get a lot
of stuff for free.
This is, I call it the
wrapped layout here,
it is a simple subclass
of the Flow layout,
then we have some custom layouts
that we have implemented, -
we can layout - these
are implemented
by plugging a different layout
object into the CollectionView.
We have got group by tag here,
but that doesn't
really do anything yet.
Let's go back to the slides
and see what it takes
to get that working.
[Applause]
Thank you.
>> That's always a good start,
to get the first demo running.
Now we want to group the
ImageFiles by tag, not satisfied
to display them in one
section, we want to see
which ones correspond
to which tags.
What we're going to do, for
each tag we have an array
of ImageFiles.
That are implicitly
ordered in some way,
and we want to show
them in that order.
An ImageFile may have many
tags, meaning we'll show it
in more than one section.
That's fine.
We also may have ImageFiles that
don't appear in any section.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We also may have ImageFiles that
don't appear in any section.
We are going to have an
untagged ImageFile section,
one additional section
at the end.
Where we show all
of the ImageFiles
with that have no tag.
We'll give each of our sections
a header and footer view,
because we want to show
off that we can do that.
Show you how to do it.
As with item types, the
instantiation process for header
and footer views, you'll
see, is very similar.
A header or footer is in general
considered what CollectionView
calls a supplementary view,
it doesn't represent an item,
but [is] something
that sort of augments,
or brackets the display of items
such as a header or footer.
We're going to implement
the data source as optional,
CollectionView, View For
Supplementary Element OF Kind,
that is a fancy way of asking,
in our case, for a header
or footer, with a
given index path.
We'll go back to the
demo machine for that.
We'll hook this up real quick.
We'll need to take our
existing data source methods
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and replace them with slightly
more sophisticated ones,
that understand how to
deal with sectioning.
Here they are.
We'll go through them briefly.
Now we need to be able to tell
the CollectionView how many
sections there are in it.
If our GroupByTag
check box is checked,
which with will set
the property,
we just return the count
of the number of tags
in the image collection.
Plus one because we want
that extra untagged
ImageFiles collection section,
sorry, at the end.
Simple enough.
Reporting the number
much items in a section,
again it is a little different
if we're grouping by tag,
basically we want to say if
the section corresponds to one
of our tags in our collection,
we'll return the count
of the number of
ImageFiles in the tag
that corresponds
to that section.
If we're in the special
untagged ImageFile section
at the end we'll
return the count
of untagged ImageFiles,
and so on.
It's pretty straightforward.
We'll look at Item
For Represented Object
At Index Path.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
For Represented Object
At Index Path.
This is the same implementation
as before, it is able to be
because I factored out this
ImageFile At Index Path method
for my own use which, actually,
this one is not suitable
because it looks at the item
index and not the section index.
We'll replace it with
a smarter version
that knows we might
want to group by tag.
If we're grouping by tag, again,
if the section corresponds
to one of our tags, we'll
find the ImageFile in the list
of ImageFiles for that tag,
according to the item index,
and the section index that tells
us which tag we're dealing with.
Let's try building
and running now.
We can check group by tag here
and now we have our
items grouped by tag
and we get the same flow
and re-layout as before,
and if we zoom in we can see.
This is our header view
which we defined in a nib,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This is our header view
which we defined in a nib,
it is basically a container,
gives us a light gray background
and has a text field,
you can put any kind
of controls you want
in here in these,
this is our footer view here,
this is sort of a darker gray,
telling us - we have
put a text field
in telling us how many
ImageFiles are in the group.
That's really all it takes
to implement sections,
it is basically the
same as on iOS.
the one thing that I elided
here, oh, two things I elided,
are the creation of the
supplementary views, the.
headers or footers, there
is a bit of code here,
but basically it is
really very parallel.
The main point of interest
is where we call back
to the CollectionView and say,
make Supplementary Element View,
sorry, Make Supplementary
Element View of kind,
the Flow layout defines,
are section header,
and section footer.
It will be one of those.
We know when it is
section header we'll look
for header.nib, we're
going to look
for footer.nib if
it is the footer.
We pass that in as
an identifier.
Once we've got our view,
we're getting a view,
and not a ViewController
this time.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We can find and set up
the value for TextField,
do whatever we want, and return
it back to the CollectionView.
Last thing we need to do is
implement these delegate methods
the Layout uses to figure
out what's the proper size,
basically the height to display
the header at, and the height
to display the footer at.
We have NSIs in each case,
and since we have a
vertically-scrolling flow
layout, only the height matters,
the width will just get clipped
to the width of the scroll view.
We had to do that to
make sure that ourheaders
and footers showed up.
That's it.
Now we can move on to updating
when our model changes.
So ImageFiles will come
and go in the folder,
we need to tell the
CollectionView
when our model changes so that
we can update what it is showing
the user.
This is done very similarly to
the way that this is handled
with Outline View on OS X.
Basically, these are
the four operations:
Items can be inserted,
deleted, an item can be moved
from one place to another,
or an item can be reloaded
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
from one place to another,
or an item can be reloaded
which basically means
it is still there
but the properties have changed,
you need to redisplay it,
you need to regather
properties from it.
It turns out that
these operations apply
to sections as well as items.
This is the same as on iOS
for those who are familiar.
You can insert, delete, move,
and reload sections as well.
Similar approach to view-based
outline view as I mentioned,
which basically means any
time the model changes,
it is the responsibility of your
data source or some other part
of your code that
deals with the model,
to notify the CollectionView,
describing exactly the
changes that were made.
I inserted items at
these index paths.
I removed items here, so
that it can will keep up,
staying in sync with the model.
If you do it right,
it is very simple.
By default, any changes you
notify the CollectionView of,
will appear instantly but you
can easily get an animated
change, by messaging through
the CollectionView's animator,
this is a general proxy
object that views have,
that you can message through,
to request an animated change,
usually when setting a
property in this case
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
usually when setting a
property in this case
when notifying the
CollectionView
that items have been inserted.
That's what we do in our example
and that's why we see items come
and go in animated way.
Items are inserted, other
items move out of the way
in an animated fashion.
In our example,
CocoaSlideCollection we're going
to watch our ImageFolder
for changes,
when changes occur
we're going to notify--
first we immediate
to update the model
and then we notify
the CollectionView,
after we changed the model,
what we did to the model.
ImageFiles may come and
go, they may be changed,
these are the types of updates
that we'll need to handle.
We are going to use
a little feature,
a foundation feature
called Key-ValueObserving,
which basically gives you
a way to observe properties
of objects, and be
notified automatically,
so that you can then react
in whatever way you need to,
our example uses KVO
throughout for this.
Let's go back to the
demo machine real quick.
I have this already
working here.
We'll run our example
first, to see what it does.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We'll run our example
first, to see what it does.
Instead of looking at the
desktop pictures folder,
I'm going to open this vacation
pictures folder, on my desktop.
Let's suppose that I have taken
some pictures on vacation,
gone to some neat places.
I have Finder windows
down here at the bottom,
pointing to desktop pictures,
I'm going to copy some stuff
from desktop pictures,
pretending I went
to these places.
I'll drag and drop some
items into the folder.
CocoaSlideCollection is
monitoring the folder,
it will notice the change,
and add items to its model,
add ImageFile instances,
and then it's going
to notify the CollectionView,
okay,
some ImageFiles were added,
so display some more items
and that happens in a very
synchronized, animated way.
We can drag an item out, a file
out, and, when it disappears,
do an updated File system
scan, notice the change,
update our model, and
the CollectionView
updates accordingly.
The KVO mechanics of
this are pretty standard,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The KVO mechanics of
this are pretty standard,
run of the mill.
The interesting, part is how
you talk to the CollectionView.
So, we'll elide the former, and
we'll just look at the latter.
You want to look at these
methods at the bottom
of the Window Controller class,
Handle Image Files Inserted
At Index Paths, that's
just something we defined
for our own use, and
this is where we talk
to the image CollectionView
and use this Insert Items
at Index Paths API,
basically what we have had
to do is figure out, OK, what
are the index paths of the items
that are affected by this?
Where did we insert items?
We messaged the CollectionView,
and since we're messaging
through the animator, we'll
get an animated change,
where the re-layout
that needs to happen,
happens in a smooth way,
instead of instantaneously.
You can make it instantaneous
if you want, by omitting this.
If you want an animated
response,
message through the animator,
you can even control
the duration
by setting the animation
context duration.
Similar thing for
when ImageFiles go,
use Delete Items At Index Paths.
Then there are even sections,
InsertSections, DeleteSections,
and other related APIs,
for dealing with
sections coming and going.
We're even equipped to handle
the new tags being added
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We're even equipped to handle
the new tags being added
and tags being removed.
That's pretty much
all there is to it.
So selection and
highlighting are important
when interacting with users.
We'll look at those
in some detail.
Basically selection
and highlighting are both
visually indicated states.
Highlighting in particular
is sort of a transient state
on the way to items becoming
selected, or deselected,
or used as a drop target.
Here in this illustration
we have items
that were briefly flashed orange
as I was dragging over them,
they were candidates for
selection, we're indicating
that with the orange border,
but then they become blue
when they become selected,
rather than highlighted.
So on OS X an item
has a highlightState.
This is a little
different than on iOS,
there is a just a Boolean
highlight property,
we needed a bit more flexibility
on the desktop to be able
to describe different
kinds of states.
The highlightState has
four possible values.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The highlightState has
four possible values.
The default is none, basically
means don't highlight this item.
You'll want to look at whether
the item is selected or not,
to decide how to present it.
If it is not selected
or highlighted,
you may display it normally.
an item may be highlighted
for selection meaning it
is not currently selected,
but we're considering
selecting it, based on something
that the user is doing, such
as dragging across items.
Then you may want to
present it with some kind
of highlight indication, this is
entirely up to you how you want
to design this in your UI,
we're using an orange border
around the slide to
show it is highlighted
for selection, but
not yet selected.
An item can also be
highlighted for deselection.
This is possible with the shift
drag behavior that's the same
as in Finder icon views.
Basically the trick here is the
item is selected, but you want
to suppress showing the
usual selected appearance.
You want to show
something different,
to indicate to the user
that the item was selected,
but we're looking at
making it deselected now.
You might want to show it
normally, this is really
up to you what you want to do,
according to your new iDesign.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
up to you what you want to do,
according to your new iDesign.
Lastly, an item can
be highlighted
to indicate it is a
potential Drop Target
which doesn't make a lot of
sense in our example today,
because a slide is
the leaf node,
we don't really have a semantic
for dropping slides
onto another slide.
But, if we had something
that was more of a container,
it might make sense, and
we'd want to indicate
that that container is where
things are going to get dropped
if the user lets the mouse
up at that current point.
Those are the different
highlight states.
One handy thing to
remember, as I said,
everything is layer-backed now,
with the new CollectionView
implementation.
That gives you the
opportunity to take advantage
of backing-layer
properties as an easy way
to change the appearance
of an item
without having to do redraw.
So, CN layer properties such as
background color, border color,
border width, corner radius,
you've probably worked
with these before, are
real handy for this.
So we might set an item's root
views layer's background color
to some color, and then give
it a corner radius, and boom,
in two lines of code we've got
a quick highlight indication
or selection indication,
nice and easy.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
or selection indication,
nice and easy.
You don't have to
do it that way.
That's just optional,
something to keep
in mind now they're we're
in a layer-backed world.
When to apply highlighting?
Real simple.
Any time your item's
highlightState changes,
in Swift you can do that, in
a DidSetObserver clause here,
you will also want to
do the same for watching
when the items selected state,
the Boolean, changes to yes
or no, you want to take
the highlightState,
and the selected state,
into account together,
and decide visually how to
present that item to indicate
that according to your UI style.
Selection of course is
what we're working toward,
we want users to be
able to select items
so that they can then
operate on them by dragging,
or with menu commands.
With a CollectionView,
items are the things
that constitute the selection,
they're what can
become selected.
NSCollectionView supports single
or multiple selection,
as before.
The master switch is whether
it is selectable or not.
If you make it selectable,
you can make it allow
multiple selection,
or force just single
selection, or no selection,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
or force just single
selection, or no selection,
and you can deny the ability
to have an empty selection
making the CollectionView try
to always maintain at
least one item selected.
These are pretty standard,
they are common to other types
of AppKit CollectionViews
and controls
such as Table View,
Outline View.
Selection is tracked by the new
Selection Index Path Property
on NSCollectionView.
That's the authoritative
representation
of what's selected in
the CollectionView,
and we are using index paths
rather than the items, right?
Because items come and go, but
the index paths stick around.
An item, if it happens
to be instantiated,
does know whether it is
part of the selection
as I have mentioned, but
again, items come and go.
CollectionViews are forever,
so usually you want to look
at the SelectionIndexPaths
at the CollectionView,
to do your operations, and there
are Select Items At Index Paths,
and Deselect Items At Index
Paths, methods that you can use,
you can also just set
selection index paths directly.
When you select items at
index paths as on iOS,
you can also ask
the CollectionView
to scroll those items into view
with a particular alignment.
If you want.
User selection is what
we're usually dealing with.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
User selection is what
we're usually dealing with.
The delegate has the
opportunity as on iOS
to approve selection
and deselection.
We made the API a little
different, because again we want
to be able to handle
bulk operations a little
more efficiently.
Now we have CollectionView,
Should Select Items
At Index Paths, and
CollectionView,
Should Deselect Items
At Index Paths.
Each of which takes a set of
index paths as the parameter.
These are the proposed
index paths we are going
to to select or deselect.
Notice that, instead
of returning a Boolean,
these return also, a
set of index paths.
So, if you just want to
say, do whatever you want,
CollectionView, just return the
set of index paths we gave you,
but you also have
the opportunity here,
to return a different
set of index paths,
you can do a line item
detail here if you want,
based on whatever
criteria you want,
you have fine-grain control over
which items can become selected
or deselected in
certain situations.
There are also DidSelect and
DidDeselect delegate methods,
so you can find out
after the fact
when the selection
change has been committed.
Similarly for highlighting,
the delegate has methods
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Similarly for highlighting,
the delegate has methods
for approving and
reacting to these changes.
So, Should Change Items At Index
Paths to highlightState, again,
you can return a different
set of index paths,
you have fine-grain control
over highlighting behavior
with your delegate.
We'll look at this real quickly
again on the demo machine.
Fortunately, for time's sake,
I have the code all
written and running.
We just want to go
into our nib file,
and drill down to our
CollectionView here.
We'll make sure that it
is marked as selectable,
we'll allow empty selection,
and we'll allow multiple
selection too.
The rest of the implementation
is pretty straightforward,
based on the understanding
that we now have.
We'll stop, build, and run.
Now we can click on
items and select them.
We have chosen, for illustration
purposes, to show items
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We have chosen, for illustration
purposes, to show items
that are candidates
for selection.
They're highlighted in orange
before they become selected,
when I let up on the Trackpad,
it becomes blue, it's selected,
and no longer highlighted, we
can click in the background
to clear the selection, I can
click and drag across items,
again we are showing items as
highlighted to become selected,
they're not selected yet, but
when I let up on the Trackpad,
they cease to be highlighted,
now they're selected.
As I mentioned as in
the Finder icon view,
if you hold down shift, and
drag-select you actually end
up sort of inverting
the selection.
Here is an example of
items that were selected,
that become highlighted
for deselection.
So, even though they're
selected,
we're letting the
highlightState override that,
and how we visually
present them,
and we're just showing them
in an ordinary fashion,
with no border around them.
Then, when I let go, the
selection is committed.
Now, since I can select, I can
Drag-and-Drop things around,
reorder them which is nice.
Once you have selection
there is a lot
of neat stuff that you can do.
Since this is all implemented
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Since this is all implemented
in a very generalized way that's
agnostic in different layouts,
we can go look at
our custom layouts,
since they implement
the required methods,
we can also drag-select across
items in our custom layouts,
click select, and that
happens automatically,
because they conform
to the standard NSCollectionView
Layout API.
That's kind of a nice
thing to get for free.
Even when we're in
section mode here,
Flow layout lets us drag-select
across sections, and so forth.
That's kind of neat.
It just works.
Two more things to talk about.
We'll talk real quick
about Drag-and-Drop,
which is important to support.
It hasn't fundamentally changed
since the old CollectionView
API,
but there are some new
things to understand.
We can drag-select items now,
and then if you have a cluster
of items selected,
or just a single,
you can drag it, move it around.
The CollectionView,
as you're dragging,
computes candidate
targets for where to drop.
In the case of this example,
we're not allowing dropping
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In the case of this example,
we're not allowing dropping
on items because they
don't represent containers,
but we are allowing
dropping between items,
which is the new thing that
we have to be concerned
with on OS X and not on iOS.
So drag and drop, as before,
is handled by the
NSCollectionView's delegate,
it's responsible for your
drag-and-drop response.
The model is intentionally very
similar to NSOutlineView's API,
there is no fundamental reason
for it to be very different.
If you've seen the drag-and-drop
outline view example,
a lot of the same concepts that
you'll see implemented there,
[it's] basically the same
idea with NSCollectionView.
If you want your CollectionView
to be a dragging source,
meaning that items can
be dragged out of it,
your basic responsibility
is to be able to put items
on the pasteboard when
requested by the CollectionView.
If you want to be a
dragging destination,
if you want to receive
drops, you need to be able
to assess a proposed drop,
CollectionView will call you,
say I want -- I'm proposing
to drop these objects
from the pasteboard onto
this target position,
which will be an index path,
indicating either a gap
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
which will be an index path,
indicating either a gap
between items, before an item
that's named, or a position
on top of an existing item,
if you're letting it
act like a container.
There will be an operation,
these are the standard
drag operations,
like copy, move, et cetera.
You can look at this proposal,
you can optionally override any
of these parameters, say
no, I would like to propose
that instead, you actually
target this position
for drop, or refuse the drop.
You need to be able to
implement the drop acceptance,
which is very similar, but
then the user has committed
to the drop, and you
need to go through,
and look at modifying
your model accordingly,
and updating the
CollectionView accordingly.
The mechanics of this boil down
to these APIs, you need to,
like any other NSView, you want
to register for the drag types
that you want to
be able to accept,
because collection view
generically doesn't know what
types of objects you deal
with in terms of your model.
CollectionView has a Dragging
Source Operation Mask,
both for local and
non-local drags.
This is just basically
letting you set in advance,
I support copy and move but not
alias, or something like that.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I support copy and move but not
alias, or something like that.
You want to set that up.
We do that in our
example as you will see.
Then the required delegate
methods that correspond
to the responsibilities I
mentioned on the previous slide.
Again, you need to be able to
write items to the pasteboard,
in the modern API you can
provide a pasteboard writer
for an item in an index path.
That lets you deal
with multi-item drags
much more gracefully.
Certain data types are
pasteboard writers.
In this example, NSURL,
if it is an absolute URL,
you can just return the
URL as a pasteboard writer,
and it knows how to write
itself to the pasteboard.
Alternatively, you can implement
Write Items At Index Paths,
toPasteboard, either
way, you're covered.
Now, to be a dragging
destination, again,
there's a Validate
Drop Delegate method,
and an Accept Drop
Delegate method,
to abbreviate them
a little bit there.
And you'll see those
implemented in our code sample.
We don't have time to walk
through the code sample
in detail today, because drag
and drop is fairly involved.
It's designed to be,
enabling you to drag items
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It's designed to be,
enabling you to drag items
from one application to another.
There is a lot to it, but
there are some fundamental tips
to understand.
Once you get these concepts,
the rest is just mechanics,
and you'll be able to see it all
in the heavily-commented
code for our sample today.
The important things to
remember, it is worth figuring
out and especially handling the
case where a drag is happening
within your CollectionView.
When you start to get dragging
destination delegate messages,
it is worth being
able to say, hey,
I know that this drag
originated within myself,
I know which items, which
index paths, are being dragged
so I can handle this a lot
more simply than, sort of,
the general, oh, this drag
can be coming from anywhere
in the system, I have to pull
things off the pasteboard,
and so on.
This lets you, with
CollectionView,
it lets you tell
the CollectionView
that you're just moving
items from these index paths,
to these new index paths,
and can give you a
nice slick animation
as a side benefit of that.
It's a lot better,
more sophisticated
than removing the
items and then, oh,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
than removing the
items and then, oh,
I have to reinsert these
same items somewhere else,
and reconstitute them.
A handy place to do this
is in the CollectionView,
dragging Session Will
Begin At Point For Items
At Index Paths delegate method.
It's an optional method,
but it's a good place
to catch those index paths,
stash them in a private property
of your data source, so you can
find that later, and say, aha,
I can handle this much more
simply, and you will see
where the code sample does that.
I wanted to leave time to
look at customizing layout.
That's more interesting and fun.
Let's go to that.
It's our last task, we're going
to look at both what you need
to do to adjust an
existing layout,
let's say Flow does almost
what you want, but you want
to tweak it just a bit to
get everything pixel perfect,
you know, I have heard
of doing that before!
Or, maybe you want to implement
a completely custom new type
of layout as we have done here,
with our various other
arrangements of slides.
We'll look at what it
takes to do that too.
Adjusting an existing layout
takes a little less work.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Adjusting an existing layout
takes a little less work.
We'll look at that first.
Let's say you want to
subclass the flow layout class
to adjust item positioning
just a little bit,
tweak things here and there.
You can do that with a
delegate, but let's just suppose
that you want to do something
that you find you can't do,
with the existing delegate API.
This is the main workhorse
method to understand.
So far this is the
same as on iOS.
Layout Attributes For Elements
In Rect is a very general API.
CollectionView calls in,
and it passes you a
rectangle that's a rectangle
in the CollectionViews internal
bounds coordinate system.
It's basically saying, hey,
what's in this rectangle?
You're obliged to
return an array
of layout attributes objects.
Remember, that's our
encapsulation of descriptions
of items, independent of having
to actually instantiate
the items just yet.
You are going to return it
information about items,
and if you have header
and footer views,
or other supplementary views
that could be in that area,
you have to figure
out what's there,
and return those descriptions.
This is obviously
highly dependent
on what your layout
algorithm is.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
on what your layout
algorithm is.
It could be anything, right?
So you are going to traverse
your own internal data
structures, you want
to figure out how
to do this really
efficiently for your layout.
That is this methods'
responsibility,
to return descriptions of
everything in a rectangle.
That's the workhorse,
that's what gets called,
when the CollectionView
first lays
out the items you have given it.
Then, there is this companion,
Layout Attributes For Item
At Index Path, almost
seems superfluous,
but the CollectionView needs to
ask about specific items, say,
just describe this item to me,
and that's what you're
supposed to do here.
If there is no item at that
index path you return nil.
Usually, there is,
if it is asking.
This gets invoked when you're
doing things like moving items
from one place to another.
So you want to implement that
too, and the results need
to be consistent with
the first method.
Then there is Invalidate Layout
With Context, which is sort
of a general invalidation method
that CollectionView will invoke
with a context, that, if
you look at its properties,
examine it, it is
the same as on iOS,
it describes what's changed.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
it describes what's changed.
Items were inserted or removed,
maybe the CollectionView is
resizing, any of a number
of things could be happening.
Examining the context properties
gives you the opportunity
to just try to be as smart
and efficient as you can.
This is sort of a later
optimization you might want
to do, after you get your layout
just basically working the way
you want it to.
This is your chance to blow
away any invalidated state stuff
that is internal state that
you track for your layout,
your own description of it
when certain changes happen.
So we're just seeing
Flow layout,
then let's say we're going
to implement those
first two methods,
the layout attributes returning
methods, to call up to super,
see what NSCollectionView
Flow layout proposes,
we can examine the resultant
layout attributes instance,
or array of them, and make
whatever tweaks we want to,
and return a new array
of layout attributes,
or a single array of
layout attributes.
That's pretty much
what there is to that,
as long as the changes you're
making don't change the amount
of space the layout needs.
What if you want to implement
a completely custom layout,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
What if you want to implement
a completely custom layout,
like we have done here?
You can subclass
NSCollectionView layout
directly, to just do
everything from scratch,
if your layout has nothing in
common with Flow, for example.
You implement the same
methods that we described
on the previous slide.
In addition, you need to be able
to answer certain basic
questions, like, what's the size
that you need, the width and
height, to display the items
that the CollectionView
has to offer?
You basically just telling the
CollectionView here what's the
size of my document view within?
-- this determines
your scrollable area.
Should Invalidate Layout For
Bounds Change returns a Boolean,
so CollectionView is
going to invoke this
when it's being resized.
And typically you'll look at,
What's my layout algorithm?
Is my layout affected
by this resize?
If you're a Flow layout
for example, a vertical one
that lays things out into rows,
maybe you don't care so much
if the CollectionViews
height is changing, right?
That just gives you
more or less space.
But,if the width is changing,
you may have to reflow.
You may return yes in
that case for example.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You may return yes in
that case for example.
That's what that method does.
If you're modifying the flow
layout so that the amount
of space you need changes,
you may actually need
to implement those two, even
for a slightly customized flow.
These methods, however,
are brand-new on OS X,
I mentioned we have the
ability now to hit test,
to have a layout
in the abstract,
hit test for drop targets.
That's a powerful new feature.
You can define this for
any of your custom layouts,
Layout Attribute For Drop Target
At Point is the first method.
If the target is an item,
that's pretty straightforward.
You're going to return
an attribute,
a layout attributes instance,
whose represented
element category is Item.
You're proposing
dropping on an item,
you plug the index path in, of
the item you have identified
that would be dropped
onto, and then you want
to return the bounding box
of that item as the frame
of the layout attribute.
That's imple enough.
A more interesting case, now,
that we didn't have to deal
with on iOS, is gaps
between items.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with on iOS, is gaps
between items.
If you determine that the point
that's being hit tested is
between items, and you
can identify, in some sort
of serial order of the
items, where that gap is, OK,
t is between item at index
6 and index 7, you may want
to return an Inter Item Gap.
That will let users drop between
your items in your layout.
You return one whose element
category is Inter Item Gap,
the attribute's index
path is the index path
of the item after the gap.
If you're between 6 and 7,
you return the index path
that specifies item
7 in that section.
Then again, you return as the
attributes frame, a bounding box
of that gap, the CollectionView
will use that bounding box
to figure out how to draw its
standard indicators somewhere
in that rectangle.
Next there is a method
called Layout Attributes
For Inter Item Gap
Before Index Path.
CollectionView sometimes needs
this too, and it will ask
about a particular position, and
ask you to describe that gap.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
about a particular position, and
ask you to describe that gap.
So here we return an Attributes
With Element Category
Inter Item Gap,
it's represented element kind
is Inter Item Gap Indicator,
so this is really,
we're using this to set
up a supplementary view.
That's how the Inter Item
Gap Indicator is implemented,
you just plug in the index
path that you are given,
and your return is
the attributes frames
as the Rect of the gap.
With these two methods together,
CollectionView can support drop
target indication between items,
even for potentially-arbitrary
custom layouts
of your own design,
which is pretty neat.
We'll look briefly at
our custom layouts,
and how they're implemented
as our last demo.
Looking here on the
left-sidebar,
we have the code categorized.
We have a layouts group,
you want to look in there.
We'll look at one example today.
The circular layout.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It is fairly simple.
We implement Layout Attributes
For An Item At Index Path,
that's where we're asked
about a particular item.
All we're doing here in concept,
is we're taking the item index
from the index path,
and that's going
to define how far we
are around the circle.
We use that to compute an
angle from 0 to 2 Pi radians.
That lets us compute a frame
for where the slide should go.
Then the important part is
here, the API is a little touchy
to how you instantiate
layout attributes instances,
to get one that's
bound to the index path
that it references correctly,
you want to be careful
to do it this way.
We'll actually talk
to the layouts class,
and get the corresponding
layout attributes class,
basically having this API
allows for layout attributes
for the NSCollectionView
Layout Attributes Class
to be subclassed and extended.
You may have some really
custom layout, just as on iOS,
that needs to work
with other attributes
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that needs to work
with other attributes
or remember other things about
items that it's laid out,
you can add those
properties by subclassing.
You override layout
attribute class
to return your own subclass.
This way we make sure we're
instantiating a subclass
if we need to.
The appropriate one.
We invoke this factory method,
Layout Attributes For Items
With Index Path, we pass
in that path we were given.
Once we have got a layout
attributes object back,
we set the properties we
want to, we set the frame,
the Z index for back-to-front
sort order in the layer world,
and then we return
that attributes instance
back to CollectionView.
We have a superclass,
where for all
of our custom layouts we have
implemented the Rect-taking
method, Layout Attributes
For Elements In Rect,
and we can do that, because
in this case, what's special
about all of these layouts,
in this case is rather
than being scrollable
layouts, that just grow
to whatever size they need
to display their items,
these all choose to display all
of the CollectionViews
items in the visible area.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of the CollectionViews
items in the visible area.
So the implementation of this
method is basically always
the same.
We are looking at the Rect,
and we are going to look
at every item we have.
We're returning descriptions of
those back to CollectionView,
so we're actually just
leveraging the Layout Attributes
For Item At Index Path method,
that we implement
in the subclass.
CollectionView Content
Size is the same for all
of these slide layouts,
we're just looking
at the clipped view's bound
size, what area do we have,
that's visible to the user?
We're going to lay out
everything out within there,
and because we're doing
that, we're also going
to invalidate layout
when the bounds change,
regardless of what the change
is, we want to re-layout,
so that we can use the
available space appropriately.
Prepare Layout, as on iOS, this
is just a handy little hook
for when layout parameters have
changed, and you're being called
at the start of a
new layout cycle,
you can do any pre-computation
you want to in there,
and just gets invoked once,
at the start of the cycle.
We can look at our
layouts in action here.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We can look at our
layouts in action here.
And say for the circular
layout as we resize,
the layout is getting
invalidated each time,
because we want to make
the biggest circle we can,
leaving some margins
within the available area.
By implementing those
relatively-few required methods,
we have a completely
custom layout.
And again, as before,
it supports crossing selection
here, and click selection,
and it is very versatile.
So, it doesn't take much to
define your own layouts for use
within NSCollectionView, and
in fact the layout classes,
the APIs you will find,
except for those additions,
those augmentations we made to
support drop target hit-testing,
basically the API
is the same as iOS,
so if you have the layouts
you have used on iOS,
you should find it very
easy to port those to OS X.
We have covered a lot
of topics here today,
we've basically made an
example run, and you have access
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
we've basically made an
example run, and you have access
to the complete source
code to that.
I encourage you to study it,
it should help you get started
using the new NSCollectionView
on El Capitan.
In conclusion, we have
got a greatly enhanced
NSCollectionView, I hope
you'll agree on El Capitan,
it is ready now to handle
scalability to large numbers
of items, flexibility
to arbitrary layouts,
and all of the toughest projects
you may want to throw at it.
We encourage you to do so.
Let us know what works.
Let us know what you
have challenges with.
If you need any help
or guidance,
we have a lab dedicated
to CollectionView
specifically tomorrow morning
in Foundation Lab B downstairs,
Frameworks Lab B, sorry,
at the foundation of the
building, 9:00 a.m. tomorrow.
I'll be there along with
other engineers from our team
who understand CollectionView.
Be sure to look at not
just the documentation,
but also the Application
Kit Release Notes,
I have personally put notes
about CollectionView use
in there, details about how
to set them up, and also,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in there, details about how
to set them up, and also,
you will find information
about all the other
great new stuff we have
in AppKit in 10.11.
If you missed What's New in
Cocoa, another great place
to find out about all the new
features that we have added,
it is quite a lot, it
didn't even fit in one talk,
I encourage you to
check that out,
on the session videos
that are available.
Last but not least we have
two great auto layout sessions
earlier today, if you're
using Auto Layout constraints
to position your controls
within your items,
it might be really helpful to
understand Auto Layout in depth.
Thank you very much for coming.
I look forward to
seeing what you create.
Enjoy the WWDC bash!
I'll see you tomorrow
morning in the lab.
[Applause]