lukeredpath / swift-responsive-textfield

A SwiftUI wrapper around UITextField with binding-based state and responder control
Apache License 2.0
85 stars 15 forks source link

Expose Delegate Methods #17

Open mergesort opened 1 year ago

mergesort commented 1 year ago

I'm trying to add functionality to my ResponsiveTextField that normally would be exposed through a UITextFieldDelegate, such as preventing a UITextField from dismissing.

final class AlwaysDisplayingTextFieldDelegate: NSObject, UITextFieldDelegate {
    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        false
    }
}

My initial approach was to try creating a delegate and setting that delegate within the configuration. (Note: that leads to a correct warning Instance will be immediately deallocated because property 'delegate' is 'weak'.)

static var `default`: Self {
    ResponsiveTextField.Configuration(configure: {
        $0.autocapitalizationType = .none
        $0.autocorrectionType = .no

        $0.delegate = AlwaysDisplayingTextFieldDelegate()
    })
}

Is there any way to add functionality to a ResponsiveTextField through the delegate, or to prevent a keyboard from ever dismissing that I may be overlooking?

lukeredpath commented 1 year ago

You can use the onFirstResponderStateChanged property and specifically the FirstResponderStateChangeHandler.canResignFirstResponder property for this.

ResponsiveTextField(
  ...
  onFirstResponderStateChanged: .init(canResignFirstResponder: { false })
)
mergesort commented 1 year ago

Oh gosh, I completely missed this! I gave your idea a shot and I seem to be running into an issue with this technique.

I thought my bug had to do with presentation detents, but I removed my usage of detents so I'm pretty confident it has to do with ResponsiveTextField, or perhaps a bug in SwiftUI that I can't track down.

In this video I present a screen with a ResponsiveTextField, and then pull it down to dismiss. The sheet does correctly dismiss, I can confirm that by hooking into onDisappear. As you can see though keyboard sticks past the View being dismissed.

https://github.com/lukeredpath/swift-responsive-textfield/assets/716513/adbb68c8-c254-40b1-8a15-365bf19c8154


My code looks approximately like this, any typos are transcription issues.

ResponsiveTextField(
    text: $text,
    firstResponderDemand: $firstResponder,
    onFirstResponderStateChanged: FirstResponderStateChangeHandler(
        handleStateChange: { state in
            print("State changed", state)
        },
        canResignFirstResponder: {
            return false
        }
    ),
    handleReturn: {
        Task {
            await self.save()
        }
    }
)

I've also tried a few variants, like setting isShowingKeyboard = false in .onDisappear and canResignFirstResponder { isShowingKeyboard }, but I can't get the timing right to make this process work well.

mergesort commented 1 year ago

Sorry to bump this but I was wondering if you had any potential insights for this issue, or if it's just the way it'll have to be in a SwiftUI world?