App Frameworks • macOS • 37:50
Touch Bar replaces the function keys that have long occupied the top of your keyboard with a versatile MultiTouch input device that features a Retina display. AppKit provides powerful APIs to let you easily leverage the power of Touch Bar in your applications. Learn how to use Touch Bar in your application to add context sensitive commands and flexible content to your user experience. This session will cover the basic concepts, design considerations, standard controls, IB support, and API that you will need to get started using Touch Bar.
Speakers: Chris Dreessen, John Tegtmeyer
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
Good morning
[ Applause ]
. Thank you. I'm Chris Dreessen. This is Touch Bar Fundamentals. If you have no idea whatsoever what Touch Bar is, I'm not sure how you got here, but I'm glad you're here. Likely most of us are a bit more familiar with Touch Bar, but we may not have had a chance to actually play with it. So, let me orient you to it.
So, we have here a picture of a MacBook Pro and in place of the F keys you might be used to, we have this thing we call Touch Bar. And this is an interactive input and display device. And let me familiarize you with these parts. On the left, we have the escape key, which should be pretty familiar to everyone.
And on the right, we have this thing called the control script. And you can go ahead and disclose the control strip if you want. And you'll have basically the old media functions the F keys offer. And you can use this the same way you always have, button presses. You don't have to disclose it thought.
You can actually just go ahead and use it in its collapsed form. And when it's its collapsed form it has some neat functions too. We can just do like a glancing swipe over the volume button and adjust the volume directly. So, there's a lot of conveniences here for adjusting certain system functions.
But, that's not really the most interesting parts of Touch Bar, the most interesting parts are between the escape key and the control strip. And that's where your application content is going to go. And so, let me show you what some of our system applications have done with this.
So, here we have photos. And this is just browsing the photos library. And we can actually go ahead and scrub through our photo library here. It's just like in iOS with direct input with our finger, so we plop our finger down on the Touch Bar and it's just tracking it.
We also have momentum swipes there if we want to browse through it quickly. If you go to edit a photo, this is the photos crop and rotate tool. And they have this rotation thing in the middle of the Touch Bar and it tracks your finger directly, which is pretty fun, because it's sort of like actually rotating a picture on a table.
Finally, photos also exposes filters. So, we can scrub and swipe through our filters here. And this is an interesting use of Touch Bar, because normally if we were using a mouse or a track pad, we'd go ahead and look at our photo and then look at the filters section and move the mouse or track pad to that, select the next filter. And with Touch Bar we can actually keep our eyes on the cat.
Here's QuickTime Player. QuickTime Player has a scrubber control directly in the touch bar, so we can move a movie back and forth, it's pretty neat. And they've also gone ahead and exposed a similar control for trimming, so we can adjust the beginning and end of a movie that we've recorded. Something I'd like to point out about QuickTime Player here, is that QuickTime Player didn't write any code to do this, this is all inside of AVKit and AVPlayer view. So, if you're already using AVKit, you've probably got this functionality for free, congratulations.
Let's look at text edit for a moment. So, everyone's familiar with QuickType on iOS. And We've gone ahead and brought QuickType over to Touch Bar on macOS, and as everyone know QuickType is a great short fiction writing tool. So, if we go ahead and write a short story here, 'the fact is he has to;' this is not the best short fiction I've read. But that's okay, because Touch Bar gives us a way of spicing that up. We also have the emoji picker.
And, let's go ahead and spice it up a bit. We can browse our emoji here and say I laughed until I cried, I was turned into a frog, and I'm happy I'm no longer a frog. So, we've added some nice human emotion and drama to our story, all thanks to Touch Bar.
TextEdit of course, is a text editing tool also, so we can collapse the QuickType options here and bring up text formatting controls. And maybe the most useful thing is to make it bold, or italic, or add some color to it and pink feels right for the story where I'm turned into a frog, and not a frog again. Anyway, let's never speak of that.
Something else I want to point out about all these examples I've show you is that they're customizable. We have a customization panel for Touch Bar. And you can rearrange items in it. You can add items from the customization panel on the screen or remove them from the Touch Bar.
And this is important, because every user's workflow is a little bit different. Some are doing different things with your application, and others just prefer to use the computer in a different way. And by enabling customization, you can give users the exact experience they want. And I'll teach you how to do that programmatically in just a little bit.
Let's cover some of the technical details and some of the implications that come with that. So, the Touch Bar is the beautiful P3 retina display. It has a nice P3 color gamut, great blacks, wonderful contrast. And that means that our assets we include in our applications don't have to cover as much as what we do on the main screen.
Additionally, it's a true multi touch device, which means we can actually track multiple fingers. And that affords us some new options for what sort of controls we might make. You're going to hear this a lot about Touch Bar, that it's context sensitive. And that's very neat in terms of enabling the user to work with functions in the application that are appropriate, but it has implications for event handling, because the context in the application might change, which the user is using the Touch Bar, and our controls need to react to that.
And finally, we actually go ahead and take some care to match the key taps and glyphs on the Touch Bar to those on the physical keyboard, and we do that by watching the ambient brightness, and knowing whether or not the keyboard backlight is on. But this has implications for how we might draw custom controls. And we're not going to go into detail on any of those implications in this session, but we do have a session later this afternoon that will cover all these topics.
So, I'm assuming that once you're done here, maybe even before that, you're going to be really jazzed to add Touch Bar support to your application if you haven't already. But when you're coming up with your UI's there's a few things to keep in mind. And the first of them, the prime directive of Touch Bar is that the Touch Bar is an input device. It's meant to be interacted with by the user. It's not supposed to be displaying things. So, no status indicators or stock tickers.
The next thing we should keep in mind when making our Touch Bar UI's is that we don't want to put functionality in the Touch Bar that doesn't exist anywhere else in the application. It's great to have null and fun Touch Bar UI's, but it shouldn't be the only way of accessing functionality. And there's a good reason for a lot of that, and that's that not every user has a Touch Bar, so if you only put something in the Touch Bar, you're going to be losing out on functionality for a lot of users.
And finally, this is almost a side effect of saying the Touch Bar is an input device. While we want creative beautiful UI's in the Touch Bar, they shouldn't be taking center stage. The content the user's working with on the main screen should always be their focus. So, the Touch Bar shouldn't be distracting.
With that out of the way, we're going to go ahead and cover the core classes that let you use the Touch Bar in your application. We're going to cover how the responder change is integrated with these for discovering what context sensitive functionality to display. And then, we're going to go ahead and take a deep dive on one of those core classes and show you most of what it can do. So, let's start with the classes.
The first class is of course NSTouchBarItem. And that plays with NSTouchBar and NSResponder. And let's just take a closer look. This is a mockup of the mail Touch Bar I've made. And everything I'm highlighting here, is an NS view, or NS control, or NS button. They're all things you're very familiar with because Touch Bar is reusing the existing view functionality we've been using in our Cocoa apps for very long time. There's a few things though that Touch Bar does, that view isn't prepared to do. So, we need some way of adapting that. And that's what this NSTouchBarItem class does. So, it binds a view to the Touch Bar.
NSTouchBarItem itself is a very basic class. It's intended to be sub classed and that's probably not something you're actually going to have to do. Because AppKit includes about half a dozen existing Touch Bar subclasses that will handle a lot of the needs you're going to have. And finally one of the most important features of the NSTouchBarItem class is that it has an identifier that uniquely identifies that item and functionality within its NSTouchBar instance.
So, let's talk about NSTouchBar itself. The most important thing is that it has an array of those item identifiers that identify the items. And this is important for resolving what functionalities goes into the Touch Bar to the views used to display it. Let's take a quick look at a code snippet.
So, here we're going to go ahead and just declare some identifiers for a shark and sea turtle. Usually when you come up with identifiers for our code, we recommend using reverse DNS, but these are a little bit more legible. And once we have those identifiers, we're going to go ahead and instantiate a new NSTouchBar and just set the default the item identifiers array. And this let's AppKit know what sort of semantic functionality we're putting in the Touch Bar.
What we're going to cover now is how AppKit resolves that. And there's two ways we do this look up. There's two ways we find NSTouchBarItem from the item identifiers. And the first is a property on NSTouchBar called template items. And this is just a set of items. So, if we go back to some code snippets, this is what we had before, exactly the same, and we've added some. So, here I'm using an NSCustomTouchBar item class for the shark and turtles respectively. And this is one of those subclasses I mentioned. And we're just setting the view of these items to an NS button.
And we go ahead and we make the title, you know the shark emoji or the turtle emoji. You'll notice we're using the NS button convenience constructor we introduced in macOS 10.12, and that's important because these convenience constructors will configure the buttons to be appearance sensitive to use the right styling and font.
And if we build an NS button directly, we may not get that functionality. So, this is a big time saver. But, finally after instantiating these items, we're just going to go ahead and stuff them in the template item set. And if we do all of this, we're going to wind up with the Touch Bar we see at the bottom of the screen, with our shark button and our turtle button.
Something I'd like to mention, if you go ahead and copy and paste the code on the slide into a Swift playground, XCode will go ahead and preview the Touch Bar items we construct and the Touch Bar itself. And this is a pretty useful way of rapidly prototyping your Touch Bar UIs.
So, that's template items. Let's go ahead and cover what we can do with the delegate. So, there's a single delegate method in the NSTouchBarDelegate protocol. And that's Touch Bar, makeItemForIdentifier. And it's pretty simple. If we take a look at this code here, this is exactly the same as the template items case.
What's different is we've structured it in a switch statement, so we can go ahead and conditionally create a new item when AppKit asks for one of our specific identifiers. AppKit cahces the result of this method. So, you really can just treat this as a factory and make a new instance each time. You don't have to maintain a back pointer yourself, unless that's useful for other reasons.
Something else that's important to mention is, you know I've covered customizability a little bit, and let's take that Touch Bar we've made and make it customizable. So, that involves adding a few things. The first bit is actually this top line, where we go ahead and tell NS application to set isAutomaticCustomize TouchBarMenuItemEnabled. That's a mouthful, but it's actually a very simply way of handling this. If you set this to true, NSApplication is going to go ahead and create a menu item for you automatically that will show and hide the customization panel.
You don't have to use that. NSApplication has a method to show and hide it explicitly and you can wire that up to your menu item if you want a little bit more control. But with that out of the way, let's look at the bottom of the code in this slide, where we set the customization identifier. And in this case, I'm just making up an ocean animal identifier. But it's important to set this, because this is the token which enables persistence of the Touch Bar configuration across launches of your application or reboots of the system.
And there's one other important step for enabling customization, and that is to set this customizationAllowedItem Identifiers array. And we're just going ahead and set it to our shark and sea turtle again. But setting this allows the customization panel to know which items can be added and removed. If we do all of that, we can bring up the customization panel and we'll see exactly this, the defaultItemIdentifiers array is translated faithfully to the default set of items on the left. And the individual items from the allowed item identifiers are shown on the right. This is kind of a boring customization panel and we can spice it up a little.
So, here's a whole menagerie of ocean animals. Something I want to mention, and it will come into play with deciding whether you're going to set the template items on a Touch Bar when you create it, or whether to use the delegate is by default we were only showing the shark and sea turtle.
And there's a lot of applications where your default functionality in the Touch Bar is going to be a very small subset of the total functionality you can add through customization. By using the delegate, users who don't bring up the customization panel aren't going to pay the CPU time of creating new items.
Something else to mention here is you may have a situation where you're building a Touch Bar UI and there's some functionality you want to be there all the time, you don't want the user to be able to remove it in customization, and if you have a case like that you can set the customization required item identifiers array.
And in this case, obviously, the sea turtle is critical for the function of our application. So, we're going to prevent it from being removed. So, that kind of covers how to make instances of NSTouchBar and how to facilitate item lookup by the item identifier, through the template items and delegate methods. But one of the things we're missing is how the applicant finds those instances of NSTouchBar. And I big part of that is the NSTouchBarProvider protocol.
And it's a fairly simple protocol. It's just exposing a read-only Touch Bar property. NSResponder itself implements this protocol right out of the box. And we'll cover that in just a second. But sometimes it's useful to attach a Touch Bar to your application delegate, or window delegate. And neither of those is likely to be a subclass of NSResponder. So, let's see how you go ahead and implement that protocol yourself.
This looks like a lot of code, but really we're just using a Swift lazy variable here for the Touch Bar property. And the first time the Touch Bar property is accessed, Swift is going to go ahead and run this block to instantiate our Touch Bar. All the code to create the item in bar and stuff we looked at in the previous slides. Something else to mention is that AppKit key value observes this property. So, if you feel the need to replace your Touch Bar wholesale, we'll notice that sort of change.
Let's look at how NSResponder implements this. First, it exposes that Touch Bar property as a read-write property instead of read-only. And the significance of that is that you can set instances of NSTouchBar on various pieces of your application. On the responders, you have in your windows. Like views and view controllers, and window controllers. And that's really neat because you don't necessarily have a subclass for each and every one of those controls. If you are making a subclass of a control, or really any NSResponder, NSResponder also exposes this makeTouchBar method.
So, makeTouchBar is pretty simple. The first time the Touch Bar property is accessed on an NSResponder, it's going to call self makeTouchBar and run this code. And we just have to return a new Touch Bar for it. A lot of the system controls and system frameworks, which expose functionality use this method to provide it.
So, I mentioned that NSResponder has a read-write Touch Bar property and you can set the touch bar. And one of the most important clients of that is actually Interface Builder. So, let me show you how to build a Touch Bar UI from Interface Builder. If we go ahead and start with a new story board, we have a window controller seen here, and we can filter the object library to show us Touch Bar controls.
So, if we just check the object library, here an instance of NS Touch Bar and we can drag that onto our window controller. And now we have an empty Touch Bar to play with and going back to the object library, we can go ahead and see that there's dozens and dozens of preconfigured controls and Touch Bar items we can just drag into the Touch Bar. And from here, we can wire these items up with ID connections, or bindings or whatever. And it's actually very possible to write Touch Bar apps that are perfectly functional and useable without ever writing a line of code for it.
So, that covers creating instances of NSTouchBarItem. Let's see how this fits into the bigger responder chain and how we discover all of these individual Touch Bar instances. So, a refresher, a responder chain is made up of instances of the NSResponder class. And one of the most important properties of the NSResponder class is this next responder property it has. And that just points at another responder.
But it basically means that given a responder, we've anchored an entire chain of responders capable of handling events and actions and things. And AppKit uses many different responders as the anchors for chains for handling keyboard events, and actions and kit testing and routing mouse events and things, but let's cover how keyboard event works. Because Touch Bar is part of the keyboard.
So, we're going to have an NSEvent handed to us by the system, and that's going to go over the NSApplication. And NSApplication is going to say what do I do with this keyboard event. And most NSApplications are going to say do I have a key window? Okay, it gets the keyboard event now.
And the key window meanwhile is going to have the same question, what do I do with this keyboard event. Every NS Window had a property called first responder and that's designating where the responder chain starts for keyboard events and actions and things. So, the key window is going to go ahead and say, all right let's send this event to my first responder, like in its key down or key up method.
So, the first responder meanwhile it's interesting, because that's where it's anchoring the responder chain, where we're going to be handling this as a responder method, not just generic event routing. But it's going to have a decision, do I handle the event in key down, or do I call super and let it pass that to the next responder. So, let's say it passes it to the next responder. Usually the first responder will be a view, the second responder will be a super view.
It will make the same choice. And these days, use and view controllers tend to be [inaudible] in the responder chain. So, pass it up to a view controller, have the same choice handler call super. It doesn't handle it. It might even go and reach all the way back to the initial window that routed the event in the first place. And that, as part of the responder chain, can make the same decisions whether to handle it or pass it on.
And that can percolate all the way back up to the application. So, that's how we handle keyboard events. Touch Bar is part of the keyboard. So, it also turns out these are all the places we can attach instances of NSTouchBar. And we search them in exactly the same order the keyboard event was routed through the responder chain.
So, one question you should be asking is hey, I notice you have five instances of NSTouchBar here. How do you go from that to one Touch Bar on the device. And I'm going to cover that in just a second. But first I want to make a small note about views and views controllers.
You're probably going to be attaching a Touch Bar to a view controller at some point, making your application. And you'll run and test this. And you're going to see that your Touch Bar doesn't show up at all and you'll think, oh, I guess my view controller is not in the responder chain. And you'll go ahead and look at your view controllers view and see that its next responder is indeed your view controller.
And what's going on here is that while your particular responder chain is set up correctly, it's not anchored in the first responder of the window. And that's often because the first responder of the window has to return true for the acceptsFirstResponder method. So, if you wind up in this situation, it's really easy to subclass NS View or whatever your first responder is to accept first responder and make a valid responder chain anchored at the first responder.
So, let's get back to how we're going to handle multiple NSTouchBar instances on this. The easiest thing to remember is that the responder, with an NSTouchBar closest to that first responder, so closest to the keyboard input, its Touch Bar is going to win and take over the whole thing.
Calling back to earlier where I mentioned that AVKit and some other system frameworks provide support, you're probably thinking that they're likely going to provide support in NS Views which are going to be closer to the first responder than your window controllers or application delegates might be. So, we need some way of sharing the device Touch Bar across multiple instances of NSTouchBar and we have a way of doing that. And that's accomplished with this special item identifier, called the otherItemsProxy.
I say it's a special item identifier because you don't have to create any item for this. You don't have to put it in your template item set, you don't have to handle that identifier in your delegate and make item for identifier case. But when you go ahead and include other items proxy in your default item identifier array, when AppKit is harvesting NSTouchBar from the responder chain, it will go ahead and replace the otherItemsProxy with the items from responders closer to the first responder.
So, let's look at that in action. Here's an example of mail. My keyboard focus is on the recipient's field. And the recipient's field is providing suggestions for who I might to send the email to. I also have this send button on the left side of the application section of the Touch Bar.
If I were to change my keyboard focus instead to the composition view in the window, I have a bunch of text formatting controls and an emoji picker. But I still have that send button. And the way this breaks down is that mail's composed window controller has a Touch Bar with a send button and an otherItemsProxy.
And the recipient's field is providing the candidates. And the recipient's field is very close to the first responder, so it's going to get first shot at that. But the window controller including the otherItemsProxy means we can merge those two Touch Bars. Likewise, for the composition view, the window controller is exactly the same instance, it's just the responder chain anchored at the first responder includes the composition view before the window controller.
Something else to mention is that this is completely compatible with customization. We use the otherItemsProxy to build the default set of items, like you'd expect. And we go ahead and union the allowed items from the eligible touch bars. So, we can see we can customize the send button in mail, even though it's provided by a different responder than the formatting controls.
You might think, hey the otherItemsProxy sounds pretty great for the reliable functioning of my Touch Bar stuff, and you'd be right, but there's a few cases where you do want to omit it. And if we go back to mail, but close all the windows, we're going to see that we have a new viewer window button in the Touch Bar.
And that's provided by the application, but it omits the otherItemsProxy. When we go ahead and bring a window up that has Touch Bar content it's going to be closer to the first responder, and the lack of the otherItemsProxy in the farther out Touch Bar means it gets replaced entirely.
So, there's another sort of special item identifier I want to cover and those are spaces. So, if you see here, we've made a mockup Touch Bar and we have a shark item and an angelfish. And the angel fish probably isn't that comfortable being so close to the shark. Thankfully, the shark is facing the wrong way so the fish probably isn't on the menu yet.
But we can go ahead and give the angelfish some breathing room. And we can do that by adding a fixed space small item identifier in the default item identifiers array in between the shark and angelfish item identifiers. And we don't have to settle for small, we can also use a large one and give it a little bit more space. And it's useful to use these instead of hard coding your own space, because these are our system defined values that may change from release to release, but they also give your app an appearance similar to other apps on the system.
We don't have to stop with fixed spaces though, we also have a flexible space identifier. And the flexible space is interesting in that it's going to push the adjacent items as far away from each other as they can get. So, in this case, the angelfish probably feels a lot better with that flexible space between it and the shark.
You might be thinking you could put flexible space on two side of an item to center it. And that's a very reasonable thought. If you do that, you're going, actually, let's say we do that with our purple circle. We put flexible space on the left and right sides of it.
The circle is centered within the application section of the Touch Bar, which might be what you're going for. But you might also want to be centering that item on the actual device, and it's not there. We're a little bit to the left. So, we can fix that by using and NSTouchBar property called the principal item identifier.
And we can go ahead and set a Touch Bar's principalItemIdentifier to the identifier of any visible item, and it's going to go ahead and actually place that item in the center of the device. So, if we go ahead and look at this example, all the code in here is stuff we see in our previous slides except this last line where we set the principalItemIdentifier.
And by setting to the shark identifier, we go ahead and move and the shark to the middle of the Touch Bar and lay out the items left to right like we did in other cases. If we were to use the turtle instead, the shark winds up on the left side like it would normally, and the turtle is centered on the device.
And this plays really well with flexible spaces and other things. Son you can make some nuance device with that. And there's additionally types of NSTouchBar items subclasses that modify the behavior of the principalItemIdentifier. And John is going to go ahead and cover those as we take a deep dive into NSTouchBar item. Welcome John Tegtmeyer.
[ Applause ]
So, Chris gave us an overview over the NSTouchBar API and how it's tied to the responder chain allowing us to provide context sensitive controls to our users. He also eluded to this NSTouchBar item object, which is the wrap around all the views in the Touch Bar. Now, AppKit provides a lot of subclasses of this item, and they all offer some really unique, very cool functionality. So, I'm here to give us a deep dive into those items.
NSTouchBar item is a base class of everything that we'll talk about today. That means the properties on this will be inherited by the subclass. The first thing that all Touch Bar items have is a unique identifier. This is what NSTouchBar will use when looking up your item through the template items array, or through the delegate.
Items also have a view or a view controller. This is what's actually presented to your users. And if you're using the view controller, this is a good opportunity to lazily load your views. We also have a customization label. And this is the string that's presented in the customization UI. And describes what your control actually does.
I hope you notice one thing that we don't have here is an explicit minimum or maximum size property. That's because, unlike tool bar item, which does have these explicit properties Touch Bar items are actually measured using constraints. That means if you're using something like an NS button which has an intrinsic content size, it will automatically be sized to fit its title and its image.
You can also choose to use inequality constraints to set up minimum and maximum sizes. And AppKit will automatically size you view based on how much space is available in the application section. And you can find out more about how items are sized at the "Advanced Touch Bar Talk" later today.
Now, as I mentioned, AppKit provides lots of subclasses of this item. And we'll talk about each of these. We'll talk about the custom Touch Bar item, pop overs, sliders, group item, as well as a few bonus topics at the end. So, let's get started with the custom Touch Bar item.
Now, the custom item offers rewrite properties on everything that we just talked about on the base class. That means you can simply set the view of the view controller rather than subclassing your item. This is likely the item that you'll use if you want to show something like a button or a segmented control. Anything that you're familiar with through AppKit, or custom container views.
Now, this is also a really great opportunity to use some of the convenience constructors that we introduced in 10.12. Let's take a look. In this example, we're going to create a simple button for Touch Bar. We're doing that by creating a custom Touch Bar item and providing a unique identifier.
And then we're going to set the items view to be an NS button using the title target action constructor that we saw earlier. And as Chris mentioned, this will assign the correct font and the correct appearance to this button. So, we have a great looking button that's ready for Touch Bar in two simple lines of code.
This is also true for a more complicated control. In this case, this is a segmented control. Segmented control also has a convenience constructor. And so, again with two lines of code, my spacing for clarity, we have a great looking control that's ready for Touch Bar with the right appearance and the right font.
Next, let's talk about popovers. Popover item is really cool because it allows you to provide extra content to your user, but only when the user requests it. Popovers have two parts. The first is the class representation, which is the view presented to your user when the popovers close. And the second piece is the popover's NSTouchBar, which actually takes over the application section when the popover is open. And this lets you use things like the principalItemIdentifier, or even enabling customization. Let's talk more about the class representation.
AppKit will provide a default on for you and you can customize the way it looks by using the class representation image, or label properties. And you can see an example of this in the list in alignment popovers and the formatting controls. You can also choose to use something more custom.
Mail chooses to use a segmented control. And if you tap the main portion of this control, it will immediately move a message to the suggest mailbox. But if you tap the arrow, it will show a popover with additional suggestions. This is actually really easy to achieve by providing your own view for the class representation and then using the show popover and dismiss popover methods.
Popovers also have two interaction models. First is touch and show. This happens when the user taps the class representation. The popover's opened and it's sticky allowing you to make multiple selections. It's only closed when the user taps the closed button. The second interaction model is press and hold.
And this happens when the user presses and holds on the class representation. The popover's open directly by the user's finger when possible and immediately starts tracking their input. It's closed when the user lifts their finger and a selection is made. But you'll notice that in these two examples, the popovers actually showed different content.
Touch and show showed several controls whereas press and hold only showed a single segmented control. And that's because press and hold is tracking the user's finger the entire time. And so, it's best to leave that kind of interaction to a single control. In this case a segmented control, or even something like the slider item.
This is easy to achieve because popovers actually have two different NSTouchBar properties. One for the touch and hold popover and another for the press and hold. Press and hold, if you do not provide an NSTouchBar for press and hold, press and hold will not be enabled. It is possible to provide the same NSTouchBar object for both of these properties and that will work just fine. But as I mentioned press and hold is best left reserved for single things, single items like a segmented control or a slider item.
Speaking of the slider item, let's talk about it. Now, you might be thinking what's the difference between a slider item and a custom Touch Bar item with an NSSlider as its view. Well, let me explain. Sliders have a few different parts. First we have the slider itself. Then, we have these new value accessories, which are images and are actually intractable. You can tap on them to increment or decrement the value of your slider. We also have a label.
This can make it extra clear to your users what this slider is actually controlling. And it's really useful if you have multiple sliders in your UI. As I mentioned these make really great content for press and hold popover. And that's because the immediately start tracking the user's finger, even though the touch is offset from the knob of the slider. That means the user can immediately start interacting with it and not go searching around for the knob for interacting with the slider.
Let's take a look at what this actually looks like in code, though. First, we're going to create the item itself. We're going to provide a unique identifier. Next, we're going to assign it minimum and maximum value accessories and we're going to use images that AppKit provides. And lastly, we're going to assign a label, because maybe we want multiple sliders in our UI. But you'll notice that the slider is actually taking up the entire application section. Well, that's because sliders do not have an intrinsic content size. They're happy to be whatever size is available in the application section.
You can change this by adding a constraint to the slider and AppKit will check that and automatically remeasure and resize the item. But notice that we're doing this on the slider itself, and not the slider items view and that's because we have a label here. And if we change localizations the length of this string will also change and we don't want to cause clipping.
Next, let's talk about group Touch Bar item. Group item is neat because it allows you to group multiple Touch Bar items into a single NSTouchBarItem instance. This is because it's similar to popovers in that it offers its NSTouchBar property. An example of this is the formatting controls above me. These have actually been grouped into a single NSTouchBarItem.
There are several reasons you might want to do this, and we'll talk about each of these. When centering multiple items, there's some tricks you can play with customization as well as localization purposes. If you remember a few minutes ago, when Chris was talking about the principalItemIdentifier, you'll recall that a single item identifier is actually provided as principal. But what happens if you want to center multiple items together like FaceTime is doing here. Well, you can group these items to a single group Touch Bar item and then provide that item's identifier as the principal item identifier.
You can also play some cool tricks with the customization. If you have a non-customizable group like we do here, you'll notice that these items are actually grouped together. That means when the user drags these things into, these buttons into the Touch Bar, all three of these will come together. There's also a single customization label describing these controls as the playback controls.
If you do choose to enable customization on your groups, you get some cool behavior there as well. In this example, we have two group Touch Bar items. Both of them have customization enabled. One contains a group of animals that you might find in the ocean, and another on a farm.
If I start customizing this, you'll notice that I'm free to re-order these items however I choose within their groups. If I try, however, to grab one of the ocean animals and put it into the farm animals group, it snaps back to where it was. Because that would be removing the item from its group and that's not supported.
GroupTouchBarItem also has really cool purposes for localization. Now, I'm sure your applications reach lots of users. Some of those users might be native right to left speakers of languages like Hebrew or Arabic. And I'm sure your applications are already flipping were appropriate for those users. And we want Touch Bar to reflect that as well.
A good example of this is FaceTime's UI. FaceTime chooses to show a full screen and a mute button both on the screen as well as within Touch Bar. And you'll notice that the order of these buttons match. If I go ahead and change the language to Arabic, you'll notice that the on-screen buttons will actually reverse their order. And we do the same in Touch Bar to maintain that matching order.
But it's important to note that not everything actually flips. The escape key and the control strip stay where they're at whether it's left to right or right to left. And only specific groups of items should possibly flip. Such as the center controls here, which we're flipping to match on-screen UI.
As well as the image and label about the incoming call are flipped. But the position of that item did not move to the opposite side of the Touch Bar. This is easy to achieve using GroupTouchBarItem's new group user interface layout direction property in 10.13. You can simply set this to reflect NSAppuserInterface LayoutDirection.
Now, I'm sure you're aware languages aren't just left to right or right to left, they also have variable length strings. And it's important to remember that when you're designing your UI. In this example, I have a list of some of my favorite ocean animals. And I ran this exact same app in both English and in German. In English I was able to fit 6 items here. But in German I only have 5. That's because the shark item actually didn't have enough room to fit in Touch Bar and so it was hidden from the user. Which is really unfortunate for our German friends.
Now, you might be tempted to fix this using constraints, tying each button to be a specific width. But that's actually not a great solution because as we change localizations, we're almost certainly going to cause clipping in one of them. Now, GroupTouchBarItem actually has a great way of handling this for you automatically starting in 10.13. And I encourage you to check out the "Advanced Touch Bar Talk" later today which will do a dive into exactly what happens.
Now, we have a few bonus topics. These are all covered great in documentation, but we'll mention them briefly now. First is the ColorPickerTouchBarItem. This allows users to interact with the color picker right through Touch Bar. They can choose the exact color that they want. They can even change color models and your document can restrict which color models are supported. Users also have access to their favorite color swatches. So, it's a really great experience. We also have a SharingServicePicker. This lets you easily share a document through mail, messages, air drop, or even third-party insurance services. And these are all the same services available through the share sheet.
And finally, we have an NSScrubber, which is actually a view, not an item. This could be the view of a Touch Bar item. And you can see in an application such as calendar's timeline, Safari's tabs or even the color swatches of the color picker that we just talked about. It's a very versatile, very fluid control. And it was designed specifically for Touch Bar. You can find out more about this at the advanced talk, which will do a deep dive on exactly how to use this control.
Now, we've covered a ton of material today. We talked about the NSTouchBar API, how it's tied to the responder chain, how you can use it to provide context-sensitive controls for your users. We've talked about the NSTouchBarItem and all of its subclasses that AppKit provides and their unique functionality.
So, you now know enough to go adopt Touch Bar in your applications today. While you're there, you should definitely enable user customization so that users can get the exact experience that they're looking for. And definitely remember to design you UI with localization in mind so that all users have a great experience.
For more information, you can check out our developer website. We have some related sessions you might be interested in. "Choosing the Right Cocoa Container View" will look at when you might want to choose a grid view over a stack view. And this could be important because you could use one of these container views as the content view of a TouchBarItem. We also have the "Advanced Touch Bar Talk" which we mentioned several times, which will do a dive into extra functionality of Touch Bar. Thank you all so much for joining us today. Enjoy the rest of your conference
[ Applause ]
.