How to make first responder in SwiftUI macOS
If your MyField
is a NSTextField
the following works. Tested with Xcode 11.4 / macOS 10.15.4
func makeNSView(context: Context) -> MyField {
let view = MyField()
// ... other properties set up here
// wait for next cycle, so field be already in window
DispatchQueue.main.async {
view.window?.makeFirstResponder(view)
}
return view
}
SwiftUI: How to make TextField become first responder?
iOS 15.0+
macOS 12.0+,
Mac Catalyst 15.0+,
tvOS 15.0+,
watchOS 8.0+
Use focused(_:)
if you have a single TextField.
focused(_:)
Modifies this view by binding its focus state to the given Boolean state value.
struct NameForm: View {
@FocusState private var isFocused: Bool
@State private var name = ""
var body: some View {
TextField("Name", text: $name)
.focused($isFocused)
Button("Submit") {
if name.isEmpty {
isFocued = true
}
}
}
}
Use focused(_:equals:)
should you have multiple TextFields.
focused(_:equals:)
Modifies this view by binding its focus state to the given state value.
struct LoginForm: View {
enum Field: Hashable {
case usernameField
case passwordField
}
@State private var username = ""
@State private var password = ""
@FocusState private var focusedField: Field?
var body: some View {
Form {
TextField("Username", text: $username)
.focused($focusedField, equals: .usernameField)
SecureField("Password", text: $password)
.focused($focusedField, equals: .passwordField)
Button("Sign In") {
if username.isEmpty {
focusedField = .usernameField
} else if password.isEmpty {
focusedField = .passwordField
} else {
handleLogin(username, password)
}
}
}
}
}
SwiftUI Documentation
- focused(_:)
- focused(_:equals:)
- @FocusState
Update
I tested this in xCode version 13.0 beta 5 (13A5212g)
. It works
Disable autofocus on TextField in SwiftUI after App launch
This really looks like a bug (file a feedback to Apple if you want).
A found workaround is to disable temporary control on launch (disabled TextField
cannot get focus) and reenable it in next event cycle.
Tested with Xcode 13.3 / macOS 12.2
Here is main part:
TextField("", text: $txt)
.disabled(disabled) // << here !!
.onAppear {
DispatchQueue.main.async { disabled = false } // << here !!
}
Complete code in project is here
How to move cursor when new NSTextView becomes FirstResponder (MacOS)?
I was able to get the desired behaviour by doing this:
func makeNSView(context: NSViewRepresentableContext<TextView>) -> TextView.NSViewType {
let textView = NSTextView()
textView.textContainer?.lineFragmentPadding = 10
textView.textContainerInset = .zero
textView.font = NSFont.systemFont(ofSize: 12)
DispatchQueue.main.async {textView.window?.makeFirstResponder(textView)
textView.setSelectedRange(NSMakeRange(0, 0)) }
print("\(textView) is first responder") //proof that the first responder is shifting, but the cursor does not for some reason
return textView
}
The answer originally comes from here: How to make first responder in SwiftUI macOS
Thanks for all the help!
Get the current first responder without using a private API
In one of my applications I often want the first responder to resign if the user taps on the background. For this purpose I wrote a category on UIView, which I call on the UIWindow.
The following is based on that and should return the first responder.
@implementation UIView (FindFirstResponder)
- (id)findFirstResponder
{
if (self.isFirstResponder) {
return self;
}
for (UIView *subView in self.subviews) {
id responder = [subView findFirstResponder];
if (responder) return responder;
}
return nil;
}
@end
iOS 7+
- (id)findFirstResponder
{
if (self.isFirstResponder) {
return self;
}
for (UIView *subView in self.view.subviews) {
if ([subView isFirstResponder]) {
return subView;
}
}
return nil;
}
Swift:
extension UIView {
var firstResponder: UIView? {
guard !isFirstResponder else { return self }
for subview in subviews {
if let firstResponder = subview.firstResponder {
return firstResponder
}
}
return nil
}
}
Usage example in Swift:
if let firstResponder = view.window?.firstResponder {
// do something with `firstResponder`
}
MacOS swiftUI Custom ui TextField field with rounded edge
Try to use rounded rectangle in background (with needed parameters, like corner radius, color, etc) instead of border, like
.background(
RoundedRectangle(cornerRadius: 8)
.stroke(your_color_here)
)
MacOs SwiftUI textfield focus effect color change
It is possible to use background with focused dependent state, like
.background(RoundedRectangle(cornerRadius: 4)
.stroke(Color.gray, lineWidth: 0.5).cornerRadius(4)
.background(focused ? .black : .clear) // << here !!
.clipShape(RoundedRectangle(cornerRadius: 4))
)
Complete test module is here
Related Topics
How to Dynamically Hide Navigation Back Button in Swiftui
Swift Error "Static Member Cannot Be Used on Instance of Type"
How to Specify The Name of The Output Executable
Convert Input Data to Integer in Swift
How to Fill Triangle in Swift Using Core Graphics
Drawing at Cocoa with Swift Creates an Error
Difference Between Any? and Any
Swift Combine: Turn a Publisher into a Read-Only Currentvaluesubject
Realitykit - Add Force to Entity at Specific Point
Swift Set UIbutton Setbordercolor in Storyboard
Swift Video to Document Directory
How to Pass a Completion Block to Another Class in Swift
Can't Set @Ibinspectable Computed Property in UIview
Nsextensionpointidentifier Error Only on Real Device
Underlying Type for Tuple in Swift