Reputation: 165
I'd like to create a TextField, where it's possible to quickly enter multiple String items into the same field, by typing in the item, then hitting return to add it.
I've already got the adding functionality, however I don't want to dismiss the keyboard each time an item is added to the list upon hitting return, as that's cumbersome for the users to tap the textfield each time in order to bring back the keyboard.
I'm looking for a pure SwiftUI solution if possible.
What I've got:
import SwiftUI
struct StackOverflowSubmissions: View {
@State var item: String = ""
var body: some View {
TextField("Enter item...", text: $item, onCommit: {
// Add item to CoreData database
})
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(5)
.background(Color(.gray))
.cornerRadius(10)
.padding()
}
}
struct StackOverflowSubmissions_Previews: PreviewProvider {
static var previews: some View {
StackOverflowSubmissions()
}
}
Upvotes: 3
Views: 2334
Reputation: 1801
Here is the CustomTextField
that does not minimise the keyboard instead the next CustomTextView
is focused. This process continues until the current CustomTextField
is the last CustomTextField
.
struct CustomTextField: UIViewRepresentable {
@Binding var text: String // String value of the TextView
let placeholder: String // Placeholder Text
let keyboardType: UIKeyboardType // Keypad layout type
let tag: Int // Tag to recognise each specific TextView
var commitHandler: (()->Void)? // Called when return key is pressed
init(_ placeholder: String, text: Binding<String>, keyboardType: UIKeyboardType, tag: Int, onCommit: (()->Void)?) {
self._text = text
self.placeholder = placeholder
self.tag = tag
self.commitHandler = onCommit
self.keyboardType = keyboardType
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UITextField {
// Customise the TextField as you wish
let textField = UITextField(frame: .zero)
textField.keyboardType = self.keyboardType
textField.delegate = context.coordinator
textField.backgroundColor = UIColor(white: 0.0, alpha: 0.025)
textField.layer.borderWidth = 0.5
textField.layer.borderColor = UIColor.tertiaryLabel.cgColor
textField.font = UIFont.systemFont(ofSize: 16.0, weight: .light)
textField.layer.cornerRadius = 6
textField.isUserInteractionEnabled = true
textField.text = text
textField.textColor = UIColor.lightGray
textField.tag = tag
textField.placeholder = placeholder
// For left inner padding
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 15, height: 120))
textField.leftView = paddingView
textField.leftViewMode = UITextField.ViewMode.always
return textField
}
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.text = self.text
uiView.setContentHuggingPriority(.init(rawValue: 70), for: .vertical)
uiView.setContentHuggingPriority(.defaultLow, for: .horizontal)
}
class Coordinator : NSObject, UITextFieldDelegate {
var parent: CustomTextField
init(_ uiTextView: CustomTextField) {
self.parent = uiTextView
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let value = textField.text as NSString? {
let proposedValue = value.replacingCharacters(in: range, with: string)
parent.text = proposedValue as String
}
return true
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let nextTextField = textField.superview?.superview?.viewWithTag(textField.tag + 1) as? UITextField {
nextTextField.becomeFirstResponder()
} else {
textField.resignFirstResponder()
}
return false
}
func textFieldDidEndEditing(_ textField: UITextField) {
parent.commitHandler?()
}
}
}
Use CustomTextView
in the ContentView
like this:
struct ContentView: View {
@State var firstName: String = ""
@State var lastName: String = ""
@State var email: String = ""
var body: some View {
VStack {
Text("First Name Value: \(firstName)")
CustomTextField("First Name", text: self.$firstName, keyboardType: .default, tag: 1, onCommit: nil).padding().frame(height: 70)
Text("Last Name Value: \(lastName)")
CustomTextField("Last Name", text: self.$lastName, keyboardType: .default, tag: 2, onCommit: {
print("Last Name is: \(self.lastName)")
}).padding().frame(minWidth: 0, maxWidth: .infinity, minHeight: 70, maxHeight: 70)
Text("Email Value: \(email)")
CustomTextField("Email", text: self.$email, keyboardType: .emailAddress, tag: 3, onCommit: {
print("Email is: \(self.email)")
}).padding().frame(minWidth: 0, maxWidth: .infinity, minHeight: 70, maxHeight: 70)
}
}
}
Upvotes: 2