Skip to content

Instantly share code, notes, and snippets.

@niw
Last active May 23, 2020 05:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niw/d5f139c896e59bc089ab00e8a1bfdacc to your computer and use it in GitHub Desktop.
Save niw/d5f139c896e59bc089ab00e8a1bfdacc to your computer and use it in GitHub Desktop.
`textInputMode` is not working on iOS 13.0 to iOS 13.3.
final class TextView: UITextView {
private var preferredTextInputModePrimaryLanguage: String?
/**
Use given primary language for the preferred text input mode when next time text view becomes first responder.
- Parameters:
- primaryLanguage: `String` represents a primary language for the preferred text input mode. Use `"emoji"` to use Emoji keyboard.
*/
func usePreferredTextInputModePrimaryLanguage(_ primaryLanguage: String) {
preferredTextInputModePrimaryLanguage = primaryLanguage
}
/**
# UIKit Bug Workaround
- Confirmed on iOS 13.0 to iOS 13.3.
- Fixed on iOS 13.4.
`textInputMode` override is completely ignored on these version of iOS 13 due to bug in `-[UIKeyboardImpl recomputeActiveInputModesWithExtensions:allowNonLinguisticInputModes:]`,
which has a flipped condition check, which doesn't always call `-[UIKeyboardImpl setInputMode:userInitiated:]`.
To workaround this behavior, return non `nil` identifier from `textInputContextIdentifier` to call `-[UIKeyboardImpl setInputMode:userInitiated:]` from
`-[UIKeyboardInputModeController _trackInputModeIfNecessary:]` and bypass `-[UIKeyboardImpl recomputeActiveInputModesWithExtensions:allowNonLinguisticInputModes:]` call.
Also need to clean up text input context identifier once it’s used for the bug workaround.
- See also:
- `becomeFirstResponder()`
- `textInputContextIdentifier`
- `textInputMode`
*/
private let shouldWorkaroundTextInputModeBug: Bool = {
// iOS 13.0 to iOS 13.3
if #available(iOS 13.0, *) {
if #available(iOS 13.4, *) {
return false
} else {
return true
}
}
return false
}()
private let preferredTextInputModeContextIdentifier = ".preferredTextInputModeContextIdentifier"
override func becomeFirstResponder() -> Bool {
let result = super.becomeFirstResponder()
if result {
if shouldWorkaroundTextInputModeBug {
UIResponder.clearTextInputContextIdentifier(preferredTextInputModeContextIdentifier)
}
preferredTextInputModePrimaryLanguage = nil
}
return result
}
override var textInputContextIdentifier: String? {
if shouldWorkaroundTextInputModeBug, preferredTextInputModePrimaryLanguage != nil {
return preferredTextInputModeContextIdentifier
}
return super.textInputContextIdentifier
}
override var textInputMode: UITextInputMode? {
if let preferredTextInputModePrimaryLanguage = preferredTextInputModePrimaryLanguage,
let inputMode = UITextInputMode.activeInputModes.first(where: { $0.primaryLanguage == preferredTextInputModePrimaryLanguage }) {
return inputMode
}
return super.textInputMode
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment