Auto Layout and tab ordering

· by Steve · Read in about 3 min · (527 Words)

Because SourceTree has continued to support versions of Mac OS X back to 10.6 (Snow Leopard), we’ve still been using the ‘springs and struts’ approach to user interface layout up to now; we couldn’t adopt the newer Auto Layout without restricting support to 10.7+. So I’ve only just started experimenting with Auto Layout recently, and I ended up getting stuck for a while on something that seemed like it should be really simple, and yet I couldn’t find any hard information about it on Stack Overflow or via Google: how to specify tab ordering.

Usually, you don’t have to manually specify tab ordering - when you create a window layout in Interface Builder and drag controls on to it, tabbing between controls is just magically organised for you. The problem arises when you either:

  1. Need to customise that tab ordering, or
  2. Need to dynamically switch subviews in code, after which the ‘magical’ tab ordering fails to work any more

Without Auto Layout enabled, this is easily resolved - you just Ctrl-dragged from one control to the other, starting with the parent view if you’re talking about a custom view you’re switching out, and assigned the ‘nextKeyView’ outlet to the next control which should receive the focus on tabbing:


When using this with custom NSViews which I dynamically switched, when I embedded the new subview I’d use a simple line of code to automatically give the first control keyboard focus:

[viewContainer addSubview:newView];
[[self window] selectKeyViewFollowingView:newView];

That worked in countless interfaces I’d created in the past. But what I found when enabling Auto Layout is that you can’t Ctrl-drag to assign the nextKeyView outlet any more, because Auto Layout completely takes over the Ctrl-drag behaviour between controls to assign constraints:


Where did the outlets go? Why did Apple just completely remove them - these outlets are still useful even if you’re using Auto Layout. How in hell do I set them up now outside of doing it all manually in code?

After a lot of searching and failing to find anything, thinking that maybe I’m the only person to ever have this problem, I eventually discovered this option instead - you can still set the nextKeyView outlets up, but you have to do it backwards, from the next tab receiver to the previous one. And you can’t start it from the Interface Builder canvas. Instead, you do this:

  1. Select the target of the nextKeyView in IB
  2. Switch to the connections inspector (6th tab on the right hand side)
  3. Drag the circle on the ‘New Referencing Outlet’ entry to the previous control (which might be the containing view if this is the first control on the view)
  4. Select nextKeyView, like so:


Using that approach, you can still rig your tab order the way you want in IB with Auto Layout enabled, and make sure that switching subviews dynamically in code doesn’t suddenly break tabbing through your dialogs. Maybe I’m the only person to need this, or maybe there’s a more elegant way to do this that I don’t know about, in which case please tell me in the comments. Otherwise, I hope this saves someone else a bit of time.