I've got a window with a single text editing field next to a scrolling view. The document view of the scrolling view contains multiple sub-views, and some of those sub-views contain text editing fields created programmatically as NSTextViews.
When the app starts the window up, the top-level text editing field is shown with focus, so it is (I think) the first responder. The user then hits the TAB key, but the first text editing field (among many) is in a sub-view of the document view that has been scrolled out of sight of the user.
The app's default behavior is to move focus to the "next" text field. Except the user has no idea where this is because it's out of view.
So there are two possible ways the app should behave. Either the app should figure out that the next responder is visibly out of bounds, and prevent the TAB key from changing the current focus. Or the app should determine which text edit field has received the new focus, and automatically scroll so that that text field is now visible to the user. It can be argued that either scenario is logical, but I think the latter is more useful.
How does one determine that the focus has been automatically changed to a vanilla text editing control that thinks it is visible but is not, due to being clipped by a parent scroll view?
It sounds like you've got a couple of issues. They're easily solved, but none of this is automatic.
First, the order of views you cycle through when pressing the Tab key is the "key view loop". You can read up on that. It's sort of, kinda, automatic but you can express an explicit order by setting the
nextKeyViewandpreviousKeyViewproperties of the text fields (buttons, other controls, ...).If you want anything in the document view of a scroll view to become visible, you need to reorient the clip view. There's a ton of ways to do that (most of them are kind of hard to understand), but what you want is so common that there's a convenience method in
NSViewthat does just that:scrollRectToVisible:So when your text field becomes active, all you have to do is
[textField scrollRectToVisible:textField.bounds].One place to do that would be whenever the text field begins editing, which could be accomplished by attaching a delegate to the text field(s) and catching
textDidBeginEditing:or observe theNSControlTextDidBeginEditingNotificationnotification and determine if it's one of your text fields.