Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> Hi.
>> Hope you all had
a good lunch.
This is Session 220,
Adopting Advanced Features
of the New UI in
Mac OS X Yosemite.
I'm Chris Dreessen, and let
me start by showing off some
of those new UI features
in Yosemite.
So to begin with here's
a simple Finder window,
and the big changes here,
you'll notice the dock is kind
of just grabbing the color
from the desktop picture.
Likewise, the Finder sidebar is
infused with the bright pinks
and oranges of the
desktop picture,
and it's really complimenting
the user's content onscreen.
Likewise, we have a picture of
Safari here, and the content
in the Safari window
is very different
than the Finder window, but
the toolbar is just grabbing
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
than the Finder window, but
the toolbar is just grabbing
that color from the webpage
and making the UI really,
really compliment
the web content here.
And finally, we have
Notification Center,
which has been around
a little while now,
but in Yosemite you can see it's
using one of our new appearances
and it's pulling up the
really bright reds and oranges
and yellows from
the desktop picture.
And it's not just
the background,
also the text is pulling it up
and the buttons are pulling
it up, and we're going
to show you how to build
UI's that also grab color
from the environment like this.
So to start with I'm going
to mention a few changes
in existing AppKit API's,
especially NSColor, NSImage.
Then I'm going to spend a
while talking about title bars
and toolbars in a
section I like to call,
title bars and toolbars.
And after that I'll invite
Corbin on stage to talk
about some important new
classes that allow you
to use these visual effects,
particularly a visual effect we
like to refer to as Vibrancy.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
like to refer to as Vibrancy.
And finally we'll top
that off with discussion
of performance regarding
these new effects.
So to begin reviewing our
oldie but goodie API's,
this is NSSegmentedControl
in Yosemite.
You'll notice we have Finder in
the background in this picture,
Safari in the foreground,
and these are the
back/forward controls,
and these are separate
elements now,
but they're not actually
separate NSControls.
This is the same
NSSegmentedControl as always,
we just configured its segment
style property with a new value.
The NSSegmentStyle
enumeration has been augmented
with NSSegmentStyleSeparated,
and this gives you the
disjoint appearance
between the back
and forward buttons.
So, when you replicate
that appearance,
don't throw two NS
buttons at it,
just use an NSSegmentedControl,
and just NSSegmentStyle.
So, I'd like to talk
about NSImage now,
especially if you've been using
UIImage you'll be familiar
with some of the things
I'm talking about.
But let's just start with
this little sample image here.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But let's just start with
this little sample image here.
This is kind of a button
or a bubble or a background
of some sort, and if you tried
to stretch it using the
NSImage API right now,
you put it in NSImage view
or you draw it yourself,
you're going to notice the
image is stretched uniformly.
So the corners here distort
as the image is resized,
and that's kind of neat but
if we're going for a button
or a window background it's
not really the effect we want.
And UIImage has had this
for quite a few releases,
but NSImage now joins it
in introducing the
capInsets property,
and this takes an
NSEdgeinsets struct [applause].
Thank you.
This takes an NSEdgeinsets
struct
which lets you specify
the distance
to the edges to make these caps.
And those capInsets are in
the image coordinate system,
so to review, the NSImage
coordinate system begins at a --
sorry, zero, zero on the
lower left, the image size
and height on the right.
Anyway, if you set the capInsets
on an image and draw it
like you used to
resize you'll note
that we're now holding the edges
and corners constant while
resizing the interiors
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and corners constant while
resizing the interiors
of the image, so this lets you
get those stretchable buttons,
those stretchable
backgrounds quite easily.
There's one other thing I
want to mention about this.
So again, if you're familiar
with UIImage you know
the UIImageResizingMode,
we now have NSImageResizingMode,
which offers Stretch
and Tile options.
Stretch is the default, it
matches the behavior we've used
on Mac OS X, pretty
much forever now.
Tile is a new option,
and these are exposed
on the surprisingly named
or resizing mode property
on NSImage [applause].
Thank you, again.
So, as an example here, this
is setting the resizing mode
to Tile, and Keynote
doesn't quite do it justice.
There's a crossfade here,
but you can see how the
image is actually being tiled
into these larger sizes.
So if you have interesting
detail you don't want stretched,
you want replicated instead.
This is how you would pull
it off, and you can use
that with an NSButton
or any NSImage view.
So, to set up the slicing,
I've taught you how
to do it programmatically
now, but you can also do this
with Xcode, and to do that
you just open your image
in your asset catalog, and you
get a nice preview of it here.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in your asset catalog, and you
get a nice preview of it here.
Here's the nine slice
checkerboard image,
and you can set this up
using the IB Inspector
in this area here.
We've got the slicing
mode, you have horizontal
and vertical here for
a nine slice image.
You can also do three slice,
just horizontal, just vertical.
And if you want to change
the tiling mode we have the
Stretches option here.
So you can do that graphically
without ever having
to change your code.
That covered NSImage, I'd
like to mention a few things
about NSAppearance in Yosemite.
So, NSAppearance is an API we've
had a reinterest in Mavericks.
We offer two appearances in
Mavericks, which you could get
at using the appearanceNamed
class method
on the NSAppearance class.
And the default is
NSAppearanceNameAqua,
which is what we've
used forever.
We continue to use this
as the default appearance,
and we had this other
appearance called
NSAppearanceNameLightContent,
which was used by popovers.
And in Yosemite we
are saying goodbye
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And in Yosemite we
are saying goodbye
to LightContent,
don't use it anymore.
Instead, popovers use one
of our new appearance names,
which is VibrantLight
and VibrantDark.
And Corbin's going to talk a
lot about these in his section.
But let me just give you a
preview to what these look like.
We have VibrantLight
on the left,
and VibrantDark on the right.
And you can see how the
background and the elements are
like what's pulling up that
color from beneath the window
in this case, and how the house
image offers much more contrast
against that background
that it might have before.
So I mentioned color here, so it
probably won't surprise anyone
to know that NSColor has
some notable mentions here.
The big one is that system
colors are appearance sensitive,
so if you use VibrantLight
or VibrantDark,
the system colors are going
to return different
effective values.
So system colors are things
like controlBackgroundColor,
controlTextColor.
There's dozens more,
they're in the NSColor header
and the documentation.
We also have two new system
colors and that's labelColor
and SecondaryLabelColor,
and Corbin will also talk
about these in depth.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and Corbin will also talk
about these in depth.
All right, this is my
favorite section here,
title bars and toolbars.
We're all familiar with
title bars and toolbars,
but in Yosemite they have
new default appearance,
and one of the key elements of
that new default appearance is
that they blur document content.
So here's a slightly awkward
video of me scrolling a picture
and preview, and you can see
that as I scroll the title bar
and toolbar are actually
absorbing and blurring
that content in real-time,
and preview didn't have
to do anything to
gain this state,
they got that feature for free.
Let me explain how that works.
So, if you have a scroll
view and it's adjacent
to your title bar or toolbar,
we're going to automatically
draw
that previously obscured content
and we'll blur it for you.
If your scroll view isn't
adjacent to the title bar,
we're going to ignore it.
So you can see on
the left I've kind
of made a mock-up showing
the title bar blurring
that orange document content,
and on the right it's not
adjacent to the title bar
so we're not blurring it
or absorbing it at all.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
so we're not blurring it
or absorbing it at all.
And that works really well for
almost all content out there,
but there's a few
cases I want to call
out where our magic there
can use a little bit of help.
So, one of those is movie
views, this is a big area
where we can't just
automatically replicate the
content for you.
Likewise, OpenGL views
are in a similar place.
You may notice kind of a
hardware accelerated theme going
on using the GPU, and
that's a good observation.
Some types of layers
also need a little bit
of help in these areas.
Movie layers and OpenGL layers
kind of get grandfathered
in with the views, but
other things like layers
with 3D transforms and layers
with Core Image filters also
require a little bit of help
to show up in a title
bar and toolbar.
Let me show you how
you can do that.
We have to place them
there explicitly,
and we can do this using this
new window style mask called
NSFullSize ContentView
WindowMask.
This is a simple demo
app I threw together.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This is a simple demo
app I threw together.
This is using a style mask
that does not include the
full size content view flag,
and you can see our content view
is vertically beneath the title
bar and toolbar, and this
content view just has a slightly
odd red box and black box.
If we add the full size
ContentView WindowMask,
all of a sudden the content
view size hasn't changed
but the title bar and
toolbar are overlaid
on top of that content.
You can see it blurring
the red and the black
in the title bar there.
So, if you look at this mock-up
and you use the FullSize
ContentView WindowMask,
a problem you'll notice is that
those controls you used to have
at the top of your window are
still at the top of your window
but the title bar overlays them.
And unless you're trying to
play a very intricate mind game
with your user, and if
you are your job is done,
congratulations, you're going
to want figure out a way
to get your controls to
be anchored at the bottom
of the title bar again.
And probably the easiest way to
do this is by using Auto Layout.
So, NSWindow offers
a new property called
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, NSWindow offers
a new property called
contentLayoutGuide and
this returns an object
that you can use in
a layout constraint,
just like you would
use in NSView.
The example here I'm creating a
constraint which binds the top
of my view to the top of the
windows contentLayoutGuide,
and that means that
the top coordinate
of both our views is going to be
at the same place in the window
when Auto Layout lays them out.
If you're not using Auto
Layout, sorry, we have a new API
in Yosemite on layout
constraints called the active
property, and you can now
install a constraint just
by setting it to be
active, you don't need
to find a common ancestor
to add the constraint to.
In this case,
the contentLayoutGuide doesn't
necessarily have a common
ancestor and this API
takes care of it for you.
If you're not using Auto
Layout we have another property
for you called
contentLayoutRect,
and that's just an NSRect
that represents the
unobscured area of the window.
Its key-value observing
compliant,
which means if you register
as a key-value observer
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
which means if you register
as a key-value observer
for it you're going to get
called back when it changes,
and that's important
because it can change.
The title bar can change height,
the toolbar can have items added
or removed or labels
added and removed.
You can go from small icon
mode to large icon mode,
so it's important
to be aware of it.
Anyway, assuming we use one
of those methods we can now
layout our buttons beneath the
title bar the way we want.
They're accessible
to the user again,
but the scroll view presents
kind of a challenge for us.
We want it to start off
unobscured by the title bar
and we don't want the
scroller to be obscured
by the title bar either.
However, if we just leave the
scroll view positioned to take
up the entire height of the
content view, it will be.
So we need a way to fix that,
and we have a way to fix that.
We have a new API
on NSScrollView called
contentInsets,
and this just adds margins
around the scroll view
where we'll inset
the content view.
So, in this example I'm using
the contentLayoutRect property
of the window and the windows
frame to infer the offset
between the top of the window
and the top of the content area,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
between the top of the window
and the top of the content area,
and I had just gone ahead,
and set a contentInsets
where its top property
is equal to that offset,
there's an easier
way of doing this.
If you do this you're
going to need a key-value
to observe the contentLayoutRect
notice when it changes.
NSScroll view also
offers a Boolean called
automaticallyAdjusts
ContentInsets.
And if you set this to Yes,
it will automatically
adjust your contents
so the scroller isn't
obscured by the title bar
and the content itself
will start unobscured
by the title bar.
So if we hit back our little
simplified example here,
this is how the window will look
like when it's opened
by the user.
When they begin scrolling the
scroll view content can still
slide under the title
bar just the way we want
and we can get this appearance
of blurring the document content
or the title bar without
[inaudible] replicating it
for you.
So I'd like to show you
another screenshot here.
This is a picture of Safari, and
something you're going to notice
about it is that the title
of the window isn't there,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
about it is that the title
of the window isn't there,
instead the window widgets and
the toolbar share the same row.
Likewise here's a
picture of Maps.
It's doing a similar thing.
Notice the title bar is
grabbing that content
from the window again,
but it's also leaving
out the title of the window.
So, if you want to do this in
your apps, it's not difficult.
We have a new enumeration
called NSWindow TitleVisiblity,
it has three states, Visible,
Hidden, and Hidden When Active.
Hidden When Active adds
a little bit of context
so when a window goes to the
background the title comes back.
That could distinguish it from
otherwise similar windows.
These are settable through the
NSWindowTitleVisiblity property.
So just a quick example, here's
that Finder window again,
this is TitleVisible, and you
can see it has a separate row
for the widgets and the title,
followed by the toolbar.
Whereas NSWindowTitleHidden,
it's gone, the title's gone,
the window widgets and the
toolbar share the same row.
Here's another picture, this
is an app called Reminders.
If you didn't know
this was Reminders,
there's a hint at the top.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
there's a hint at the top.
But you can see the window
is divided into two sections.
They have a sidebar that runs
all the way from the bottom
of the window to the
top of the window,
but you'll note the
sidebar is not being blurred
by the title bar.
Likewise, here's a
picture of Notes,
and they're doing
a similar thing,
the note on the right actually
has this nice paper texture
to it and that paper
texture goes all the way
to the top of the window again.
And this is also
easy to accomplish,
NSWindow has a new
property called
titlebarAppearsTransparent.
So, if we go back to my
silly little red box,
black box example, this is
at when titlebar
AppearsTransparent equals No,
and that's the default.
So you can see the title
bar is blurring our content.
If we set it to Yes, the red box
and the black box
are unobscured.
So you can do tricks like
put views that go all the way
from the bottom of
the window to the top
or otherwise augment
the title bar.
So, I'd like to invite
Corbin on stage.
He's going to talk about some
new API's that'll let you take
advantage of our visual effects,
especially one called Vibrancy.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
advantage of our visual effects,
especially one called Vibrancy.
Welcome, Corbin.
>> Thanks, Chris.
So, my name's Corbin Dunn, and
I'm an AppKit Software Engineer.
So, what am I going
to talk about today?
I'm going to talk about
a new class in AppKit
to do these blurring
and visual effects
called NSVisualEffectView.
I'm going to talk about
NSAppearance and some materials
and how to get the custom
colors and whatnot that we have.
Then we'll talk about Vibrancy
and how to get that vibrancy
and how to do it
in your controls
and standard controls in AppKit.
And then finally I'm going
to discuss briefly some
of the standard controls in
AppKit that adopt these features
and how we do it and
how it affects you.
So, first of all let's jump
right in and go to a demo.
This demo is called
VisualEffectPlayground,
and it's not an actual
playground app
like you might think, but what
it has here is it shows a lot
of the features that I'm
going to discuss today.
There are a lot of
buttons in this app,
and they show each
thing that I talk about.
Search on the developer's
site for Yosemite
for VisualEffectPlayground
and you can find this,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for VisualEffectPlayground
and you can find this,
take it apart, and play around
with it and figure out how
to create apps like this.
So some things that it
does, if I click one
of these images here
it shows how
to create basically your
own type of sidebar,
how to do some vibrancy.
There's a couple examples of
how to do some type of blurring
with a maps type of application,
how to get to blur here,
and it also will blur
under the title bar, too.
Another one showing off
our dark look too and how
to do something similar
to what FaceTime does.
So these new visual
effects, I'm going to talk
about a new class called
NSVisualEffectView,
and here's a screenshot of it,
and we see that it's blending
with stuff behind the window.
Here's another screenshot
of the demo application
and it's blending with
stuff inside the window.
And now this is an
important difference to note
because we have two
concepts here.
We have behind window blending,
where whatever's behind the view
and behind the window is blended
with what you see and we have
within window blending.
So there are two
different modes for this.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And so that's reflected in the
API for NSVisualEffectView.
There's an ENUM and it's
NSVisualEffect BlendingMode
and it has two options,
blending mode behind window,
and a blending mode
within window,
and then property to set it.
So, you can just set
and code or you can open
up your application
inside of Interface Builder
and you can go ahead and set
the blending mode directly here.
It's really easy to do,
to get that behind window
or in-window blending.
So how does this work?
How does the behind window
blending actually behave
and what does it do?
Well, our implementation
is in Core Graphics
and the Windows Server.
This means that as your
window is moving around,
none of the content in your
window is actually redrawn,
it's managed for
you automatically
by our Window Server.
What NSWindow EffectView does
is it kind of finds regions
with the Window Server to
tell it, hey, this is the area
that I want to be
vibrant or to be blurred,
and do it automatically.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and do it automatically.
The visual effect view
also implements Vibrancy,
and I'm going to discuss about
that in detail in a little bit.
So, one thing to note about
this and the visual effect view
with behind window blending,
whatever is behind your view
inside your application is going
to be poked out or knocked out.
So if I have this view inside
my window and it's on top
of an image view, a
picture of this elephant,
it's going to poke out
whatever's behind it,
and so it kind of
just knocks it out.
So it's something to be
aware of in your application.
So, how does within
window blending work?
Within window blending
utilizes Core Animation
to achieve this effect.
NSVisualEffectView uses special
layers and special filters
to do this work behind
the scenes.
Core Animation is also used
to implement the Vibrancy,
which I'll talk about
more in a little bit.
Now, if it's used
in Core Animation
and you set the property
to be within window,
it requires layer backing.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
it requires layer backing.
And so this is a
screenshot of what happens
in Interface Builder if you
don't have it layer-backed.
It'll show it has
red, to indicate, hey,
you're doing something wrong
and should probably
make it layer-backed.
But you probably don't want
to make just your visual
effect view the thing that's
layer-backed, you
want to make the thing
that contains it
be layer-backed.
So in this case,
the content view
of your window would
be the thing
that you make layer-backed,
because it needs
to blend those things together
and they both need
Core Animation layers
in order to achieve that.
So, how can you set it?
Well, you can also set this
easily inside of Xcode,
if you don't do any code
for the [inaudible] layer,
and you can just check that box
if you're not familiar with it,
it's been around for a
while, Core Animation layer.
Now let me talk about
some state.
The visual effect view
has an active state,
which we see here
blending with the window.
And it also has a
non-key or inactive state,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
so it automatically removes
the blurring and just goes
to being a solid color fill.
This is also represented in API.
So the visual effect view
has a property called state
and it's an ENUM value
NSVisualEffectState
and it has NSVisualEffect
StateFollows WindowActiveState,
which is probably
what you want to do.
And what this means is
when your window is key
and your window is active that
visual effect view will be key
and active, but you may want
to control it more explicitly.
So you can explicitly
set the active state
or explicitly set the inactive
state and actually full power,
and full control over this.
Now the things about
that, as I said before,
you want probably always use the
FollowsWindowsActiveState value
because if your window
becomes key and non-key,
it'll automatically
do the work for you
and you don't have
to do anything.
You want to use the active state
explicitly, very sparingly.
It can affect performance
and battery life,
because if you have a lot
of visual effect views
around they're always active,
but you probably want to use it
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
around they're always active,
but you probably want to use it
in places where you know
that view is always going
to be active and
maybe it's a panel
that can't become key
for whatever reason.
Internally we use it in things
like popovers and sheets,
which always want to have
that particular look.
So, that was discussing
some of the basic properties
of visual effect view, now
let me discuss how do set the
material and how it
works with NSAppearance
and visual effect view itself.
As Chris mentioned, here are
two screenshots showing two
different appearances.
We have the NSAppearance
NameVibrantLight
to get this light
appearance and light controls.
And we have NSAppearance
NameVibrantDark
to get the dark look
and dark appearance.
And notice the controls
automatically look different
and automatically are
changing the colors as needed.
It's easy to do this,
you can just use
visualEffectView.appearance
and set the appearance
to either VibrantLight
or VibrantDark
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to either VibrantLight
or VibrantDark
and do it in code, very simple.
Or, as usual, you can go
into Interface Builder,
select Visual Effect View,
and when you select the Visual
Effect View the appearance
property will now
have Vibrant Light
and Vibrant Dark as options.
Other views won't
have this option.
So, the vibrant appearances
require and NSVisualEffectView.
I'm going to say more
about this in a bit, why.
That visual effect view can
be a direct ancestor or has
to be a direct ancestor of
your child views in order
to get the vibrant look
in the vibrant effect.
However, whatever
materials shown
by the visual effect
view may be different
than what the appearance is
saying, and let me describe
that a little bit differently.
Visual effect view has a
property called material.
The NSVisual EffectMaterial
has several ENUM values.
The first one is what you
will probably use the majority
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The first one is what you
will probably use the majority
of the time, and
it's NSVisualEffect
MaterialAppearanceBased.
So let me show you
how that one works.
If you have a visual
effect view and it's set
to NSVisualEffect
MaterialAppearanceBased,
the actual materials shown
by the visual effect view
is automatically determined
by the appearance.
So if you set the
VibrantLight appearance,
the MaterialLight will appear
for that visual effect view.
If you set the VibrantDark
appearance,
the MaterialDark will appear
for the visual effect view.
Now you can explicitly
set the material
and not set the appearance,
which is why it's
an ENUM option.
So the last option here is
NSVisual EffectMaterialTitlebar.
And so what this
material is for is for you
to create your own
title bar like views.
So you may have a need
in your application
to replicate the titlebar
that we do inside the AppKit,
and we just use this and this
VisualEffect MaterialTitle Bar
internally, and so
you can also use it
to create your own title
bars if you need to.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to create your own title
bars if you need to.
All right, so that was
discussing visual effect view,
appearance, and some
of the materials.
So now I'm going to talk about
Vibrancy and custom controls.
First of all, well,
what is Vibrancy?
And Vibrancy is just
basically a special blend mode
where we're taking
two difference pixels,
combining them together, and
getting a different result
that looks more vibrant when
they're combined together.
Vibrancy is just an abstract
term that we coined in AppKit,
and that way you
don't have to worry
about the actual implementation.
The actual implementation
and blending
that we do could
be a Linear Burn,
a Color Dodge, PlusD, PlusL.
It doesn't matter, we're
abstracting it for you.
But if you don't know
what those terms mean,
let me give an example.
So here's just a simple
image of some flowers,
and if I drop a little
square onto it,
it's just a solid gray
square with a darker border,
and if I set it to
be color burned,
as you can see it
looks more vibrant.
So effectively this is what
we're doing to our controls,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So effectively this is what
we're doing to our controls,
and this is just a very simple
example of what color burn
and what we mean by Vibrancy.
So how does this work
with visual effect view,
and how does the
text become vibrant?
Let's take a look at
what you have to do.
First of all, in order to
get any sort of Vibrancy,
you have to use the
vibrant appearance.
So you have to set
the VibrantLight
or VibrantDark appearance, and
then Vibrancy is automatically
and abstractly applied.
So for this little piece of text
here in order to get this text
to look vibrant, and it
might be difficult to see,
but it is actually blending with
the contents behind the window,
you just use NSColor labelColor,
and it looks more vibrant.
You may also have a need for
a secondary vibrant look,
and this one's just
slightly lighter
and it looks a little
bit different.
And again, we have a new color,
NSColor secondaryLabelColor
to achieve this Vibrancy
in this text field.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to achieve this Vibrancy
in this text field.
Now, let me remind you
about some template images.
You may or may not be aware
that NSImage has had a
template property since 10.5
and it's really simple, you can
create your image as a black
and white image and
do Set Template Yes.
We'll have a specific
naming convention
to make it a template, and
that gives you a template image
where we can apply effects on
top of it instead of AppKit.
So if you're using
a template image,
NSImageView will
automatically apply Vibrancy.
So here's an example
of a regular image,
not a template image,
and it automatically
does not have Vibrancy.
However, this image below
automatically has Vibrancy
because it's using
a template image.
So if you and your application
use template images you can
automatically get Vibrancy.
So that begs the question,
well how does something
like Image View say, hey, I want
to be vibrant or not be vibrant?
And how does it dynamically
choose its answer?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And how does it dynamically
choose its answer?
And the answer is we have new
API and NSView to do this,
and this is basically
the implementation inside
of NSImageView, it says
allowsVibrancy is the new API,
and the answer to
allows Vibrancy is
self.image.isTemplate,
which is saying, hey,
if I'm a template
I can be vibrant,
if I'm not a template,
I can't be vibrant.
Very simple.
So you may be wondering
then, well, how do I signal
to the system that
that's changed?
What if my answer is changing
based on something that I said,
like change the image
or whatnot?
And just like normal AppKit
things if you change the state
of Vibrancy or need the question
to be intAskedYouAgain
[phonetic],
just call setNeedsDisplay and
we'll automatically call back
and update the Vibrancy
effect for your view.
Now, NSTextField
also is vibrant.
NSTextField behaves very
similar to NSImageView
and it answers Yes
to allowsVibrancy
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and it answers Yes
to allowsVibrancy
if you're using our
particular vibrant colors.
So, if you're inside
of a vibrant appearance
and you're using labelColor,
secondaryLabelColor,
or any other colors which might
be custom for that appearance,
they will probably
appear vibrant.
If you don't want the
text to appear vibrant,
you need to explicitly opt out
by setting the controlTextColor
or some other color
that's not there.
NSAppearance also has a method
called allowsVibrancy on it.
This is so you and
your API can know
if a particular appearance
needs Vibrancy or not.
I'm going to discuss more
about this in detail later.
But what this gives us
is it gives us a recipe
to let you know
when a particular view
is going to be vibrant.
Any view will be vibrant
if all these conditions
up here are true.
The appearance has to say
Yes from allowsVibrancy.
Which means currently,
that is, the VibrantLight
or VibrantDark appearance.
Your view subclass has to
override allowsVibrancy
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Your view subclass has to
override allowsVibrancy
and say Yes, have you expressing
that it can be vibrant.
And that view has to be
inside of a VisualEffectView.
The VisualEffectView
is sort of the glue
that binds it all together.
If it's not contained inside
of a VisualEffectView,
Vibrancy will not work.
So when all these conditions
are met your control will
become vibrant.
So let's talk about custom
controls and Vibrancy
and what you can do in your
control to make them vibrant.
So here we have a custom view,
it's just drawing a gray oval
and then another gray
oval inside of it.
And this ones appearing vibrant,
you can see how it's
a deeper orange color,
the gray is being blended
with what's behind the window
to produce this vibrant effect.
And when it's not in
the VisualEffectView
that same exact view is
drawing non-vibrantly,
it's drawing its normal
gray colors with no work
from you the developer.
In addition, another thing
to point out in this view,
this bottom view here, it is
inside of a VisualEffectView
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
this bottom view here, it is
inside of a VisualEffectView
yet it's not appearing vibrant.
I'm going to discuss
how to achieve
that effect, too,
in a short bit.
How do you actually go
ahead and implement this?
Well, first of all, in
your custom view subclass,
as I mentioned before, you'll
override allowsVibrancy
and you'll prior return
Yes, that way when you're
in a vibrant appearance
you automatically will
appear vibrant.
And then inside of your drawRect
you'll probably just do whatever
you're doing today, you set your
particular colors, fill a path,
or do whatever type
of drawing you want
and you'll automatically
become vibrant.
Here I'm just drawing
with some regular colors,
I have a variation of black
with a different Alpha value,
and this view automatically
becomes vibrant.
Now, because that view
says Yes to allowsVibrancy,
anything drawn inside of
that view will automatically
become vibrant.
Even if you drew images,
any text, any color,
everything inside of
it will be vibrant.
You don't have to use labelColor
or secondarylabelColor
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You don't have to use labelColor
or secondarylabelColor
to get Vibrancy in that view.
However, what you can do is you
can utilize the system colors
to have your application
and your custom view be more
dynamic depending on what kind
of appearance it's in.
If it's in a light
appearance or dark appearance.
So, for instance, something
like NSColor controlTextColor
now is dark when it's
on a light appearance and light
when it's on a dark appearance.
Something to be aware of, if
you're taking these colors
and storing them in your
app, store the name color,
don't convert that color to
a CGColor or don't convert it
to a colorspace, don't
extract the RGB elements
and save them off, because
if you do that you'll lose
that dynamic nature
of the color.
Instead just save
the color itself,
like the NSColor
controlTextColor
and utilize it again and again.
Now again, if you
change your appearance
on your particular view it'll
automatically invalidate the
subviews so you're holding
onto that color, you don't have
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
subviews so you're holding
onto that color, you don't have
to worry about invalidating
things it's done automatically.
So let's take a look at some
code that uses a system color,
because you may not
be familiar with it.
We have ColorList, and
so you can easily grab a
colorListNamed System.
And what this sample
code is doing, and again,
this is provided in that
demo application I mentioned
at the start, it's
going to go ahead
and set up some attributes.
It's going to enumerate through
all the colors in the ColorList,
grab a particular color
out based on its key,
the key is the name of
the color, do a set of it,
and just do a RectFill to fill
that color, one after another.
So if we look at a view
where all it's doing is
drawing those colors,
and this looks very busy,
so let me explain it.
This is what we would
get, this is what
that demo application does.
So in the first column this
is just drawing the name
of the particular color.
Next column is drawing
the same color, same view,
in the Aqua Appearance.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Same color, same view in the
Vibrant Light Appearance.
Same color and same view in
the Vibrant Dark Appearance.
And if we zoom in so you
can see one particular row,
this is the controlTextColor,
and as you can see, the Aqua,
Vibrant Light, and Vibrant Dark,
the colors are all
slightly different depending
on what we decide in
AppKit to make it look
for a particular appearance.
The point here is
they are different,
depending on your appearance.
So if we take a look at
that CustomView again
that was drawing the circles,
if we use NSColor labelColor,
NSColor secondaryLabelColor,
that view would look good
if it's in a light
appearance or a dark appearance
without you having
to do anything.
Now one of the things
to note in this view,
at the bottom there is one
of these CustomViews that's
not drawing vibrantly.
So how did it opt-out of
Vibrancy and what did it do?
It's very simple.
All that view is doing, and
this is just done inside
of Interface Builder,
you can do it in code,
is I have it selected
and I go ahead
and set the appearance
back to aqua,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and set the appearance
back to aqua,
and so it no longer
meets the criteria
of being a vibrant control
and it won't draw vibrantly.
So the things to note is
that you can opt-out
your particular controls
from Vibrancy, one at a
time, or you can do it
on a whole view hierarchy.
So you could have a hierarchy
controls, opt in or out
by setting a container to be one
particular appearance or not.
You can opt it in or out
depending on what you need.
One think to note is your view
that's apparent can't have
already said Yes
to allowsVibrancy,
because there are
caveats with that,
which I will discuss
in a little bit.
Let's discuss how you would
actually achieve something
like this where the same view --
where it's in a VisualEffectView
it draws one way and when it's
in a the regular Aqua appearance
it's drawing another way.
And in this case, when it's
in the Aqua appearance I'm
drawing red and purple just
to be dramatically different.
So why would you
want to do this?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Well, in your application
you might want
to provide different artwork
for when you're inside
of a vibrant appearance
than when you're not inside
of a vibrant appearance,
and when you're inside
of a regular Aqua appearance.
Or you could use
different colors
or something along that line.
In this particular case, I'm
just using different colors.
And it's really easy to use.
As I mentioned before
NSAppearance has an
allowsVibrancy property,
and it's Yes when it's
in a vibrant appearance.
And so your code
can key off that.
NSView has a method
called effectiveAppearance
where it finds out what
the appearance set on it
or somewhere up the chain
and you can query that
and see if it allowsVibrancy.
And if it does you can
set one particular color,
if it doesn't you can
set another color.
So here it's just saying
the redColor when it's
in a vibrant appearance.
So let me discuss some caveats
with Vibrancy and blending.
This is the within
window blending mode
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This is the within
window blending mode
and some caveats with it.
So let's say that we have
this super view here,
the one with the gray or
darker square around it,
and it has some subviews.
Now if that super view says Yes
to allowsVibrancy, what's going
to happen is all the subviews
are going to always be vibrant,
and so it's a little
difficult to see here but now
that subview, that image view
is doing a different blending
and it looks a little
bit murky and muddy
because it's doing
a vibrant blending.
And that's not desired.
So, the thing to
be aware of here is
if your custom view is returning
Yes from allowsVibrancy,
all your subviews are
going to be vibrant.
So if you're designing
applications,
you need to keep this in mind
and design all your subviews
to be vibrant or to be aware
that they're going
to be vibrant.
Or design it so that your
parent view is not saying Yes
to allowsVibrancy, overlapping
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to allowsVibrancy, overlapping
with the siblings
-- or children.
There are also some
other caveats
with behind window blending
that has that same once vibrant,
always vibrant effect,
but there's an additional
problem here
that I'm going to highlight.
And what is happening here
is I have this blue box,
which is saying, no I
don't want vibrancy.
However, there's a text
field alongside of it
which is using labelColor,
which as you know from before,
is saying Yes to allowsVibrancy.
So the text wants to be vibrant,
but the thing drawn behind
it wants to not be vibrant,
however, those areas
are overlapping,
and we just described
this to the Window Server
and so what's going to happen
is anything in that square
of the text is going
to be vibrant,
including what was drawn
behind it, that blue area.
And so it gets also
vibrancy applied to it.
So this is another caveat
which you should be
aware of and not do.
Instead, you probably want to
opt your text to not be vibrant
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Instead, you probably want to
opt your text to not be vibrant
or have that blue
control to be vibrant
so that everything is vibrant.
Another thing that we have is
visual effect view can have a
maskImage property.
The mask image allows you to it.
So right here are two
visual effect views,
one using the light
appearance or light material,
and another using
the dark material.
And if I set a mask
image on each of them,
just the area blending behind
it, to behind the window,
is only inside of
that masked area.
So you just see that for
the actual house icon,
or the gear icon,
and what was drawn
in the window you can
now see the poppy flower.
And again, the demo
application shows this.
You can easily set a maskImage,
or you can use NSImage with size
and do the block handler
to create it on the fly.
And so here's setting
it to be a BezierPath,
that's just a RoundRect.
And when you do something
like this,
it's how you would achieve
this shown in the demo app
where it's a RoundRect
for my entire window using
the maskImage property.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for my entire window using
the maskImage property.
Some notes about mask image.
Chris highlighted some of
the new features that we use
with NSImage, so you
know, set those capInsets
so we can properly
stretch the mask image
and everything will work fine.
Okay, so that was discussing
VisualEffectView, mask image,
appearance, and how
to get Vibrancy.
Let me talk about some of our
Standard controls in AppKit
and how they do Vibrancy,
and things to be aware of.
First of all, table view and
outline view, and a table view
and an outline view configured
as a source list is
automatically opting
into a vibrant appearance now.
So you see that in
something like the side bar
in mail, calendars, et cetera.
So how does this work,
and how does this work
with your applications already?
If you're using the
selectionHighlightStyle
of NSTableView
SelectionHighlight
StyleSourceList, that tells the
table, or our only view of that,
it wants to be a source list.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
it wants to be a source list.
And as soon as you set
that, either in code
or in Interface Builder, it
has always had side effects,
and these are documented in
the release notes I'm going
to reiterate them here.
OutlineView's indentation
is automatically affected
and controlled to
meet specific metrics.
New to 10.10 we start tweaking
the intercell spacing just
slightly to make it
meet new metrics.
If you're using a TableCellView,
its position of the imageView
and textView are
automatically controlled
to whatever it needs to be.
And we apply attributes to the
texts to make it appear correct.
So if your application was
using a source list highlighting
before, and doesn't make
any significant changes,
it will automatically
get the new 10.10 look
for SourceList in the side bar.
The last little bit here
is the backgroundColor
for the actual source list
for table is set to a magical,
internal color, and it's
important to be aware of this.
Because it has this magical
color, what's happening inside
of AppKit when we
see that you're using
that special background
color, we're going to go ahead
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that special background
color, we're going to go ahead
and put a VisualEffectView
behind your TableView
and do the blurring
automatically for you.
So you don't have
to do anything.
If you don't want that behavior,
after you set the
selectionHighlightStyle
to SourceList, you can
change the backgroundColor
to anything else.
You can change it back
to clear or to nothing,
and it will not do
the operation.
And this is the way
it's always worked,
and so we respect old
behavior of opting out of
that backgroundColor
or the background blur.
So you could do it manually
in some other super view
if you need to for some reason.
Another note, or thing to be
aware of, is now automatically
in 10.10, the sidebar
SourceList for TableViews,
automatically get
their appearance set
to the VibrantLight
appearance for you,
and you don't have to do that.
Another control inside
of AppKit,
Popover is now utilizing
the Light and Dark materials
as necessary, and it will
have its appearance set
to Vibrant Light or
Vibrant Dark, as necessary,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to Vibrant Light or
Vibrant Dark, as necessary,
and you don't have to
do anything for that.
So, that was an overview
of the standard AppKit
controls inside of AppKit.
I'm going to bring it
back to Chris to talk more
about performance and what you
can do to make your app fast
with these new visual
effects [applause].
>> Thank you, Corbin.
All right, so that was fun.
Let's talk about
performance, which is also fun.
So you notice that blur we had
and this may not surprise you
but the blur effect
isn't exactly free.
It does cost something, and
that something is graphics
performance and battery usage.
And sometimes, though, the
cost is worth the results.
So, something you
should be aware
of here is you're not trying
to not use this effect.
You want your app
to look beautiful.
You just need to pay
attention to striking a balance
between that appearance and
the resource utilization.
So, here's a small example.
These two images on the left
and right appear [inaudible],
it's actually controlled
with three image views
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and these vibrant
template houses.
And you recall that Vibrancy
requires a VisualEffectView.
So there's actually a few
ways of accomplishing this,
but on the left we
choose to accomplish this
with a single visual
effect view.
Meanwhile on the right,
we can accomplish this
with three visual effect views
and there's some obvious reasons
to structure things on the
right versus on the left.
One of them would
be flexibility.
If you needed different
appearances
or difference materials
for those houses
on the right you would need
to use VisualEffectViews.
However, you should be conscious
about how many VisualEffectViews
you're using
and when you're using them.
In this case, the number
of pixels affected here,
the surface area of these
houses is almost identical
between the left and the right.
And in that case a single
VisualEffectView is going
to mean more performance,
if there's less information
for us to track.
The opposite of this
case is also true.
If you had a window with,
say, some very small areas
of Vibrancy and they were on
different edges of the window,
it might be more efficient
to use two VisualEffectViews
instead
of a single enormous
VisualEffectView.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of a single enormous
VisualEffectView.
Something else to be aware of,
especially for in window blurs,
is frequently updated content.
And what do I mean by
frequently updated content?
Well, I mean movies.
I mean animations.
I even mean blinking cursors.
These are going to be
updating at 24 or 35ths,
or 65ths for animation, or
even 2/5 for blinking cursors.
And the thing is whenever these
update we're going to have
to recompute that blur.
This is also true for
behind window blurs,
but you don't usually control
the content behind the window
in your app, so that's not
something you really need
to worry about.
Corbin mentioned that
layers are often required,
especially for in window blurs,
and layer usage is
increasing just in general.
But something I wanted
to mention is
that if you're using layers, the
dirty shapes on screen are going
to be different than if
you're not using layers.
So, here's an example of a
mock text view that just blinks
at insertion point
in this R rectangle,
when it's not layer-backed.
And you can see here we
have this blinking cursor.
What you probably can't
see is I've actually turned
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
What you probably can't
see is I've actually turned
on color flush in one
of our de-bug tools,
and this rectangle is
turning yellow every time the
cursor updates.
For a non-layer backed view,
that small rectangle is all
that's flushed on screen.
If, however, we say we do
want to layer for this,
we're still using
the small dirty rect,
but whenever the view
updates we see this instead.
The entire layer is flushed.
It's not that we're
drawing anymore,
our application is still just
drawing that tiny cursor rect,
it's just that Core Animation
has been built for GPU's,
which involve submitting
Geometry in large batches,
so we just flush
the entire contents
of the layer to the screen.
If, for example, you
had a VisualEffectView
that overlaid the right
side of this view,
even though only the insertion
point on the left is blinking
that blurs going to
have to be recomputed.
So, that is something
to keep in mind.
Something else to be aware of,
if you're using a updateLayer
or you have your own layer tree
and you're setting your
own layer properties,
like the corner radius or
other elements directly,
the entire layer is still going
to be flushed in one pass there.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
the entire layer is still going
to be flushed in one pass there.
So that caveat applies to
update layer users also.
Often, though, you can fix this
by just re-factoring your
view hierarchy a little.
So, for example, if you have
frequently updating content,
try to put it in a
small view and have --
reserve large views for static
or unfrequently updated content.
Something unrelated, but very
important to be aware of,
is NSWindow has an opaque
property and you shouldn't mess
with it if you're using
visual effect views.
In the past if you needed to
punch a hole through your window
or have transparency you
had to set this to Yes.
However, if you're using
VisualEffectViews you don't have
to do that, we take care
of it automatically.
If you set this to No, you're
going to take away a lot
of information the Window Server
uses to call obscured windows
and it'll be doing a lot
more drawing than necessary.
So, avoid this unless
you're already using it
for other reasons.
I want to point out this option
in the Accessibility preference,
this is in the Display
subsection called
reduce transparency.
And that'll actually
turn off our blurs
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And that'll actually
turn off our blurs
on a system-wide basis.
And I'm not suggesting
this as a user feature,
instead I'm suggesting
this as a diagnostic tool.
If you add a lot of
VisualEffectViews to your app
and all of the sudden you notice
that maybe your window
resizing animations
or your full screen
transitions have become slow,
you can set this to Yes,
and this will avoid the cost
we pay when doing that blur.
So if you notice
when this is turned
on your performance is fine,
and when this is turned off your
performance is kind of sluggish,
it's probably you're using a
VisualEffectView that's too
large or too many
VisualEffectViews,
and that's a cue to dial
down the transparency
and blurring in the app.
Some other things I want
to mention is some performance
tools we can use for this.
So I used Quartz Debug to turn
on a coloring of dirty areas
that the Windows
Server had to redraw,
and that can be very
useful for diagnosing cases
where you may be drawing more
content than you're expecting,
or when you're using layers
and you're drawing a little bit
of content but it's
affecting an entire view.
Something I want to
point out about a lot
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Something I want to
point out about a lot
of our drawing here is that the
blur effect actually happens
out of process, it happens
in the Windows Server,
and furthermore, it happens
on the GPU, and that means
that profiling your own process
won't necessarily tell you
as much as you would hope.
I'm still, however, going to
call out the instruments tool,
because the Windows Server and
your app are kind of competing
to get frames on the screen
in a single display cycle,
and the faster you
can make your app
and the less GPU it utilizes
the more that is available
for the Windows Server.
So you can still improve the
performance of the system
as a whole by just improving
the performance of your app,
and instruments gives you the
tools to monitor all that.
If you're just doing a lighter
development on your app,
having activity monitor open
can sometimes be useful.
It's certainly not as
in-depth as instruments
but it will tell you how
much CPU you're using
and more importantly it'll tell
you how much energy your app is
taking to do what it's doing.
And if you see that
operating a little higher
than you're expecting
that may be another cue
that your VisualEffectView usage
has gotten a little excessive.
Finally, for the purists amongst
you who really don't want
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Finally, for the purists amongst
you who really don't want
to impact what their app is
doing by adding some gooey stuff
to profile it, you can access
[inaudible] a new sample
for example, which will tell
you what your app is doing.
So we've covered a lot.
So let me give you a quick
summary of these things.
I mentioned the NSImage
drawing enhancements,
especially capInsets.
I also mentioned the new
behaviors of NSColor,
the importance of NSAppearance,
and some SegmentedControl API.
We covered new window features,
especially the full
size content view,
but also the title
visibility options
so you can make your title
bars look like Safari and Maps.
We also covered the transparent
title bar, which is what Notes
and Reminders are using to have
that crisp appearance all
the way from the bottom
to the top of their windows.
Corbin gave you a
huge run-through
on NSVisualEffectView
and what you can do
with our visual effects
and how appearances
and Vibrancy are accomplished.
And finally, you folks remember
like 40 seconds ago we talked
a little bit about performance,
and I do hope you'll take some
of those performance messages
to heart when you leave.
Oh, thank you, Riley.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Oh, thank you, Riley.
One other thing I failed
to mention, though,
is the new NSScrollView API that
you would use in conjunction
with full size content
view didn't make it
into the CU Guide
earlier this week,
but it will be available
to you shortly.
So, I'd like to point
out Jake Behrens,
our Frameworks Evangelist,
he's here in the plaid shirt
and the dark vibrant
appearance shoes.
We have taken to
describing his appearance
in great detail throughout
the course of the week.
I'm eager to see what we
come up with tomorrow.
We also, of course, have
documentation available online.
At developer.apple.com is also
where you can get the Quartz
Debug tool I mentioned.
And of course our
developer forums.
There's some related
sessions, Adapting Your App
to the New UI was a session
yesterday that's available
online now.
Additionally, later this
afternoon there's What's New
in Interface Builder, which
will cover not only a bit
of what we showed you during
Interface Builder today
but other useful
Interface Builder tools
for designing your app.
And tomorrow morning is
creating Modern Cocoa Apps,
which if you found some of
these new APIs interesting,
that'll cover a lot more of
what's gone into Cocoa recently.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that'll cover a lot more of
what's gone into Cocoa recently.
Thank you very much.
[ Applause ]