SwiftUI layout is very different from what we are used to. Currently I'm fighting against TextField
s. Specifically their touchable Area.
TextField( .constant(""), placeholder: Text("My text field") ) .padding([.leading, .trailing]) .font(.body)
This results in a very small TextField
(height wise)
Adding the frame modifier fixes the issue (visually)
TextField( .constant(""), placeholder: Text("My text field") ).frame(height: 60) .padding([.leading, .trailing]) .font(.body)
but the touchable area remains the same.
I'm aware of the fact that the frame modifier does nothing else other than wrap the textField in another View with the specified height.
Is there any equivalent to resizable()
for Image
that will allow a taller TextField with wider touchable Area?
If you don't mind using Introspect you can do it by saving the UITextField and calling becomeFirstResponder()
on button press.
extension View { public func textFieldFocusableArea() -> some View { TextFieldButton { self.contentShape(Rectangle()) } } } fileprivate struct TextFieldButton<Label: View>: View { init(label: @escaping () -> Label) { self.label = label } var label: () -> Label private var textField = Weak<UITextField>(nil) var body: some View { Button(action: { self.textField.value?.becomeFirstResponder() }, label: { label().introspectTextField { self.textField.value = $0 } }).buttonStyle(PlainButtonStyle()) } } /// Holds a weak reference to a value public class Weak<T: AnyObject> { public weak var value: T? public init(_ value: T?) { self.value = value } }
Example usage:
TextField(...) .padding(100) .textFieldFocusableArea()
Since I use this myself as well, I will keep it updated on github: https://gist.github.com/Amzd/d7d0c7de8eae8a771cb0ae3b99eab73d
The Button solution will add styling and animation which might not be wanted therefore I now use a new method using my ResponderChain package
import ResponderChain extension View { public func textFieldFocusableArea() -> some View { self.modifier(TextFieldFocusableAreaModifier()) } } fileprivate struct TextFieldFocusableAreaModifier: ViewModifier { @EnvironmentObject private var chain: ResponderChain @State private var id = UUID() func body(content: Content) -> some View { content .contentShape(Rectangle()) .responderTag(id) .onTapGesture { chain.firstResponder = id } } }
You'll have to set the ResponderChain as environment object in the SceneDelegate, check the README of ResponderChain for more info.
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