Reputation: 793
How do i select all text when clicking inside the textfield? Just like how a web browser like chrome would when you click inside the address bar.
import SwiftUI
import AppKit
struct ContentView: View {
var body: some View {
TextField("Enter a URL", text: $site)
}
}
Upvotes: 18
Views: 11695
Reputation: 3343
macOS 12.0+
struct ContentView: View {
@State var text: String = ""
@FocusState var focused: Bool
var body: some View {
TextField("", text: $text)
.focused($focused)
.overlay {
if !focused {
Color.clear
.contentShape(Rectangle())
.onTapGesture {
focused = true
}
}
}
}
}
Upvotes: 0
Reputation: 119177
You can use the pass a TextSelection
to text editing controls like:
@State private var selection: TextSelection?
var body: some View {
TextField("Enter a URL", text: $site, selection: $selection)
}
Upvotes: 7
Reputation: 13527
I had issues when using code from some of the answers previously posted here, so I'm just sharing what worked for me.
First of all, you will have to import Combine
:
import Combine
Then you can add this to your TextField
:
.onReceive(NotificationCenter.default.publisher(
for: UITextField.textDidBeginEditingNotification)) { _ in
DispatchQueue.main.async {
UIApplication.shared.sendAction(
#selector(UIResponder.selectAll(_:)), to: nil, from: nil, for: nil
)
}
}
Alternatively, you could use a ViewModifier
for a more reusable approach:
public struct SelectAllTextOnBeginEditingModifier: ViewModifier {
public func body(content: Content) -> some View {
content
.onReceive(NotificationCenter.default.publisher(
for: UITextField.textDidBeginEditingNotification)) { _ in
DispatchQueue.main.async {
UIApplication.shared.sendAction(
#selector(UIResponder.selectAll(_:)), to: nil, from: nil, for: nil
)
}
}
}
}
extension View {
public func selectAllTextOnBeginEditing() -> some View {
modifier(SelectAllTextOnBeginEditingModifier())
}
}
And then just add this to your TextField
:
.selectAllTextOnBeginEditing()
Upvotes: 5
Reputation: 580
Here’s my solution:
struct ContentView: View {
@FocusState var isFocused
@State var text = "Text"
var body: some View {
TextField("Some Text", text: $text)
.focused($isFocused)
.onChange(of: isFocused) { focus in
if focus {
DispatchQueue.main.async {
UIApplication.shared.sendAction(#selector(UIResponder.selectAll(_:)), to: nil, from: nil, for: nil)
}
}
}
}
}
If .focused
doesn’t work for some weird reason, you can add a .onTapGesture
to the TextField
and use a Bool
variable.
Like this:
struct ContentView: View {
@State var isFocused = false
@State var text = "Text"
var body: some View {
TextField("Some Text", text: $text)
.onTapGesture {
isFocused = true
}
.onSubmit {
isFocused = false
}
.onChange(of: isFocused) { focus in
if focus {
DispatchQueue.main.async {
UIApplication.shared.sendAction(#selector(UIResponder.selectAll(_:)), to: nil, from: nil, for: nil)
}
}
}
}
}
Upvotes: 11
Reputation: 720
I've created a ViewModifier
to select all the text in a TextField
.
Only downside is, it won't work with multiple TextFields
.
public struct SelectTextOnEditingModifier: ViewModifier {
public func body(content: Content) -> some View {
content
.onReceive(NotificationCenter.default.publisher(for: UITextField.textDidBeginEditingNotification)) { obj in
if let textField = obj.object as? UITextField {
textField.selectedTextRange = textField.textRange(from: textField.beginningOfDocument, to: textField.endOfDocument)
}
}
}
}
extension View {
/// Select all the text in a TextField when starting to edit.
/// This will not work with multiple TextField's in a single view due to not able to match the selected TextField with underlying UITextField
public func selectAllTextOnEditing() -> some View {
modifier(SelectTextOnEditingModifier())
}
}
usage:
TextField("Placeholder", text: .constant("This is text data"))
.selectAllTextOnEditing()
Upvotes: 6
Reputation: 66
Here is my solution
import SwiftUI
import PlaygroundSupport
struct ContentView: View {
@State private var renameTmpText: String = ""
@FocusState var isFocused: Bool
@State private var textSelected = false
var body: some View {
TextEditor(text: $renameTmpText)
.padding(3)
.border(Color.accentColor, width: 1)
.frame(width: 120, height: 40)
.onExitCommand(perform: {
renameTmpText = ""
})
.onAppear {
renameTmpText = "Test"
isFocused = true
}
.focused($isFocused)
.onReceive(NotificationCenter.default.publisher(for: NSTextView.didChangeSelectionNotification)) { obj in
if let textView = obj.object as? NSTextView {
guard !textSelected else { return }
let range = NSRange(location: 0, length: textView.string.count)
textView.setSelectedRange(range)
textSelected = true
}
}
.onDisappear { textSelected = false }
}
}
let view = ContentView()
PlaygroundPage.current.setLiveView(view)
Upvotes: 1
Reputation: 18904
SwiftUI Solution:
struct ContentView: View {
var body: some View {
TextField("Placeholder", text: .constant("This is text data"))
.onReceive(NotificationCenter.default.publisher(for: UITextField.textDidBeginEditingNotification)) { obj in
if let textField = obj.object as? UITextField {
textField.selectedTextRange = textField.textRange(from: textField.beginningOfDocument, to: textField.endOfDocument)
}
}
}
}
Note : import Combine
Use UIViewRepresentable
and wrap UITextField
and use textField.selectedTextRange
property with delegate.
Here is the sample demo
struct HighlightTextField: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextField {
let textField = UITextField()
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ textField: UITextField, context: Context) {
textField.text = text
}
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
class Coordinator: NSObject, UITextFieldDelegate {
var parent: HighlightTextField
init(parent: HighlightTextField) {
self.parent = parent
}
func textFieldDidBeginEditing(_ textField: UITextField) {
textField.selectedTextRange = textField.textRange(from: textField.beginningOfDocument, to: textField.endOfDocument)
}
}
}
For macOS
struct HighlightTextField: NSViewRepresentable {
@Binding var text: String
func makeNSView(context: Context) -> CustomTextField {
CustomTextField()
}
func updateNSView(_ textField: CustomTextField, context: Context) {
textField.stringValue = text
}
}
class CustomTextField: NSTextField {
override func mouseDown(with event: NSEvent) {
if let textEditor = currentEditor() {
textEditor.selectAll(self)
}
}
}
Upvotes: 31