I have a cocoa app written in Swift. The app has a number of NSControls
for user entries. The user can use the tab key to move between the controls, most of them being textfields. I am doing all in Code, I do not use the Interface Builder.
Some of them are dynamic: I have a custom NSControl
, let's call it myRow
which itself is hosting two ´NSTextFields´. myRow itself is hosted in a superView, let's call it myRowManager
. When the user makes an entry this myRow
notifies the myRowManager
, and another myRow
is placed below the first one. When one field's content is deleted by the user the myRowManager
then deletes that myRow
and re-arranges the remaining myRows
. The whole setup is mimicking a table view, where there is always one more row than there are entries so that the user can always add an entry at the end.
Using the tab key when modifying existing entries works just fine.
But the nature of my setup means, that when a row is added or deleted a method .layoutSubviews()
is called, there all myRows
are removed from the superView (the manager) and then new myRows
are created, reflecting the new number and order, which is of course reflecting the underlying data.
But by removing the myRow which just had the focus from the view hierarchy sets the window's initial responder as the key-view
, as the current and next element in the key-view loop
are no longer present.
I therefore am trying to set the key-view
manually to the newly created textfield. To do this, a reference to this textfield is kept by the layoutSubviews
method.
Unfortunately I have not been successful so far.
What I am doing now (this is the method of the manager which is called by a myRow
when an entry is added):
func rowAddedAtEnd(_ index: Int) {
layoutSubviews()
self.window?.recalculateKeyViewLoop()
self.window?.selectKeyView(following:targetView)
}
What strikes me as odd is that there is no method th set a specific view as the key view. I can either use .selectKeyView(following:)
or (preceding:)
But anyway - it does not work. The focus ring just gets reset to the top left element in the window.
How can I solve this?
From the documentation of func selectKeyView(following view: NSView)
:
Sends the
nextValidKeyView
message toview
and, if that message returns anNSView
object, invokesmakeFirstResponder(_:)
with the returned object.
To select targetView
, skip nextValidKeyView
and call makeFirstResponder(_:)
.
self.window?.makeFirstResponder(targetView)