I used the below code to create a custom search bar in SwiftUI. It works great on iOS / Catalyst:
...but when running natively on macOS, the 'focus ring' highlighted border styling (when the user selects the text field) rather ruins the effect:
Using .textFieldStyle(PlainTextFieldStyle())
has removed most of the default styling from the underlying field (which I believe is an NSTextField
), but not the focus ring.
Is there a way to remove this too? I tried creating a custom TextFieldStyle
and applying that, but couldn't find any modifier to style that border.
public struct SearchTextView: View {
@Binding var searchText: String
#if !os(macOS)
private let backgroundColor = Color(UIColor.secondarySystemBackground)
#else
private let backgroundColor = Color(NSColor.controlBackgroundColor)
#endif
public var body: some View {
HStack {
Spacer()
#if !os(macOS)
Image(systemName: "magnifyingglass")
#else
Image("icons.general.magnifyingGlass")
#endif
TextField("Search", text: self.$searchText)
.textFieldStyle(PlainTextFieldStyle())
.foregroundColor(.primary)
.padding(8)
Spacer()
}
.foregroundColor(.secondary)
.background(backgroundColor)
.cornerRadius(12)
.padding()
}
public init(searchText: Binding<String>) {
self._searchText = searchText
}
}
As stated in an answer by Asperi to a similar question here, it's not (yet) possible to turn off the focus ring for a specific field using SwiftUI; however, the following workaround will disable the focus ring for all NSTextField
instances in the app:
extension NSTextField {
open override var focusRingType: NSFocusRingType {
get { .none }
set { }
}
}
If you want to replace this with your own custom focus ring within the view, the onEditingChanged
parameter can help you achieve this (see below example); however, it's unfortunately called on macOS when the user types the first letter, not when they first click on the field (which isn't ideal).
In theory, you could use the onFocusChange
closure in the focusable
modifier instead, but that doesn't appear to get called for these macOS text fields currently (as of macOS 10.15.3).
public struct SearchTextView: View {
@Binding var searchText: String
@State private var hasFocus = false
#if !os(macOS)
private var backgroundColor = Color(UIColor.secondarySystemBackground)
#else
private var backgroundColor = Color(NSColor.controlBackgroundColor)
#endif
public var body: some View {
HStack {
Spacer()
#if !os(macOS)
Image(systemName: "magnifyingglass")
#else
Image("icons.general.magnifyingGlass")
#endif
TextField("Search", text: self.$searchText, onEditingChanged: { currentlyEditing in
self.hasFocus = currentlyEditing // If the editing state has changed to be currently edited, update the view's state
})
.textFieldStyle(PlainTextFieldStyle())
.foregroundColor(.primary)
.padding(8)
Spacer()
}
.foregroundColor(.secondary)
.background(backgroundColor)
.cornerRadius(12)
.border(self.hasFocus ? Color.accentColor : Color.clear, width: self.hasFocus ? 3 : 0)
.padding()
}
public init(searchText: Binding<String>) {
self._searchText = searchText
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With