完善任务流程、键盘适配与页面交互
This commit is contained in:
14
Pods/IQKeyboardReturnManager/IQKeyboardReturnManager/Assets/PrivacyInfo.xcprivacy
generated
Normal file
14
Pods/IQKeyboardReturnManager/IQKeyboardReturnManager/Assets/PrivacyInfo.xcprivacy
generated
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyTrackingDomains</key>
|
||||
<array/>
|
||||
<key>NSPrivacyCollectedDataTypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyTracking</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@ -0,0 +1,286 @@
|
||||
//
|
||||
// IQKeyboardReturnManager+UITextFieldDelegate.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardReturnManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
|
||||
// MARK: UITextFieldDelegate
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc extension IQKeyboardReturnManager: UITextFieldDelegate {
|
||||
}
|
||||
|
||||
@objc public extension IQKeyboardReturnManager {
|
||||
|
||||
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
||||
|
||||
var returnValue: Bool = true
|
||||
|
||||
if delegate == nil,
|
||||
let textFieldDelegate: any UITextFieldDelegate = textInputViewCachedInfo(textField)?.textFieldDelegate {
|
||||
let selector = #selector((any UITextFieldDelegate).textFieldShouldBeginEditing(_:))
|
||||
if textFieldDelegate.responds(to: selector) {
|
||||
returnValue = textFieldDelegate.textFieldShouldBeginEditing?(textField) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
if returnValue {
|
||||
updateReturnKey(textInputView: textField)
|
||||
}
|
||||
|
||||
return returnValue
|
||||
}
|
||||
|
||||
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
|
||||
|
||||
guard delegate == nil else { return true }
|
||||
|
||||
if let textFieldDelegate: any UITextFieldDelegate = textInputViewCachedInfo(textField)?.textFieldDelegate {
|
||||
let selector = #selector((any UITextFieldDelegate).textFieldShouldEndEditing(_:))
|
||||
if textFieldDelegate.responds(to: selector) {
|
||||
return textFieldDelegate.textFieldShouldEndEditing?(textField) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||
|
||||
var aDelegate: (any UITextFieldDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textField) {
|
||||
aDelegate = model.textFieldDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textFieldDidBeginEditing?(textField)
|
||||
}
|
||||
|
||||
func textFieldDidEndEditing(_ textField: UITextField) {
|
||||
|
||||
var aDelegate: (any UITextFieldDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textField) {
|
||||
aDelegate = model.textFieldDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textFieldDidEndEditing?(textField)
|
||||
}
|
||||
|
||||
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) {
|
||||
|
||||
var aDelegate: (any UITextFieldDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textField) {
|
||||
aDelegate = model.textFieldDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textFieldDidEndEditing?(textField, reason: reason)
|
||||
}
|
||||
|
||||
func textField(_ textField: UITextField,
|
||||
shouldChangeCharactersIn range: NSRange,
|
||||
replacementString string: String) -> Bool {
|
||||
|
||||
guard delegate == nil else { return true }
|
||||
|
||||
if let textFieldDelegate: any UITextFieldDelegate = textInputViewCachedInfo(textField)?.textFieldDelegate {
|
||||
let selector: Selector = #selector((any UITextFieldDelegate).textField(_:shouldChangeCharactersIn:
|
||||
replacementString:))
|
||||
if textFieldDelegate.responds(to: selector) {
|
||||
return textFieldDelegate.textField?(textField,
|
||||
shouldChangeCharactersIn: range,
|
||||
replacementString: string) ?? false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func textFieldDidChangeSelection(_ textField: UITextField) {
|
||||
|
||||
var aDelegate: (any UITextFieldDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textField) {
|
||||
aDelegate = model.textFieldDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textFieldDidChangeSelection?(textField)
|
||||
}
|
||||
|
||||
func textFieldShouldClear(_ textField: UITextField) -> Bool {
|
||||
|
||||
guard delegate == nil else { return true }
|
||||
|
||||
if let textFieldDelegate: any UITextFieldDelegate = textInputViewCachedInfo(textField)?.textFieldDelegate {
|
||||
let selector: Selector = #selector((any UITextFieldDelegate).textFieldShouldClear(_:))
|
||||
if textFieldDelegate.responds(to: selector) {
|
||||
return textFieldDelegate.textFieldShouldClear?(textField) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||
|
||||
guard delegate == nil else { return true }
|
||||
|
||||
var isReturn: Bool = true
|
||||
|
||||
if let textFieldDelegate: any UITextFieldDelegate = textInputViewCachedInfo(textField)?.textFieldDelegate {
|
||||
let selector: Selector = #selector((any UITextFieldDelegate).textFieldShouldReturn(_:))
|
||||
if textFieldDelegate.responds(to: selector) {
|
||||
isReturn = textFieldDelegate.textFieldShouldReturn?(textField) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
if isReturn {
|
||||
goToNextResponderOrResign(from: textField)
|
||||
return true
|
||||
} else {
|
||||
return goToNextResponderOrResign(from: textField)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if compiler(>=5.7) // Xcode 14
|
||||
@available(iOS 16.0, *)
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardReturnManager {
|
||||
|
||||
func textField(_ textField: UITextField, editMenuForCharactersIn range: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu? {
|
||||
|
||||
guard delegate == nil else { return nil }
|
||||
|
||||
if let textFieldDelegate: any UITextFieldDelegate = textInputViewCachedInfo(textField)?.textFieldDelegate {
|
||||
|
||||
let selector = #selector((any UITextFieldDelegate).textField(_:editMenuForCharactersIn:suggestedActions:))
|
||||
if textFieldDelegate.responds(to: selector) {
|
||||
return textFieldDelegate.textField?(textField, editMenuForCharactersIn: range, suggestedActions: suggestedActions)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func textField(_ textField: UITextField, willPresentEditMenuWith animator: any UIEditMenuInteractionAnimating) {
|
||||
var aDelegate: (any UITextFieldDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textField) {
|
||||
aDelegate = model.textFieldDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textField?(textField, willPresentEditMenuWith: animator)
|
||||
}
|
||||
|
||||
func textField(_ textField: UITextField, willDismissEditMenuWith animator: any UIEditMenuInteractionAnimating) {
|
||||
var aDelegate: (any UITextFieldDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textField) {
|
||||
aDelegate = model.textFieldDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textField?(textField, willDismissEditMenuWith: animator)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if compiler(>=6.0) // Xcode 16
|
||||
@available(iOS 18.0, *)
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardReturnManager {
|
||||
|
||||
#if compiler(>=6.1) // Xcode 16.3
|
||||
@available(iOS 18.4, *)
|
||||
func textField(_ textField: UITextField, insertInputSuggestion inputSuggestion: UIInputSuggestion) {
|
||||
var aDelegate: (any UITextFieldDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textField) {
|
||||
aDelegate = model.textFieldDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textField?(textField, insertInputSuggestion: inputSuggestion)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if compiler(>=6.2) // Xcode 26
|
||||
@available(iOS 26.0, *)
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardReturnManager {
|
||||
|
||||
func textField(_ textField: UITextField, shouldChangeCharactersInRanges ranges: [NSValue], replacementString string: String) -> Bool {
|
||||
guard delegate == nil else { return true }
|
||||
|
||||
if let textFieldDelegate: any UITextFieldDelegate = textInputViewCachedInfo(textField)?.textFieldDelegate {
|
||||
let selector: Selector = #selector((any UITextFieldDelegate).textField(_:shouldChangeCharactersInRanges:
|
||||
replacementString:))
|
||||
if textFieldDelegate.responds(to: selector) {
|
||||
return textFieldDelegate.textField?(textField,
|
||||
shouldChangeCharactersInRanges: ranges,
|
||||
replacementString: string) ?? false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func textField(_ textField: UITextField, editMenuForCharactersInRanges ranges: [NSValue], suggestedActions: [UIMenuElement]) -> UIMenu? {
|
||||
|
||||
guard delegate == nil else { return nil }
|
||||
|
||||
if let textFieldDelegate: any UITextFieldDelegate = textInputViewCachedInfo(textField)?.textFieldDelegate {
|
||||
|
||||
let selector = #selector((any UITextFieldDelegate).textField(_:editMenuForCharactersInRanges:suggestedActions:))
|
||||
if textFieldDelegate.responds(to: selector) {
|
||||
return textFieldDelegate.textField?(textField, editMenuForCharactersInRanges: ranges, suggestedActions: suggestedActions)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,532 @@
|
||||
//
|
||||
// IQKeyboardReturnManager+UITextViewDelegate.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardReturnManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
|
||||
// MARK: UITextViewDelegate
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc extension IQKeyboardReturnManager: UITextViewDelegate {
|
||||
}
|
||||
|
||||
@objc public extension IQKeyboardReturnManager {
|
||||
|
||||
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
|
||||
|
||||
var returnValue: Bool = true
|
||||
|
||||
if delegate == nil,
|
||||
let textViewDelegate: any UITextViewDelegate = textInputViewCachedInfo(textView)?.textViewDelegate {
|
||||
if textViewDelegate.responds(to: #selector((any UITextViewDelegate).textViewShouldBeginEditing(_:))) {
|
||||
returnValue = textViewDelegate.textViewShouldBeginEditing?(textView) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
if returnValue {
|
||||
updateReturnKey(textInputView: textView)
|
||||
}
|
||||
|
||||
return returnValue
|
||||
}
|
||||
|
||||
func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
|
||||
|
||||
guard delegate == nil else { return true }
|
||||
|
||||
if let textViewDelegate: any UITextViewDelegate = textInputViewCachedInfo(textView)?.textViewDelegate {
|
||||
if textViewDelegate.responds(to: #selector((any UITextViewDelegate).textViewShouldEndEditing(_:))) {
|
||||
return textViewDelegate.textViewShouldEndEditing?(textView) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func textViewDidBeginEditing(_ textView: UITextView) {
|
||||
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textViewDidBeginEditing?(textView)
|
||||
}
|
||||
|
||||
func textViewDidEndEditing(_ textView: UITextView) {
|
||||
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textViewDidEndEditing?(textView)
|
||||
}
|
||||
|
||||
func textView(_ textView: UITextView,
|
||||
shouldChangeTextIn range: NSRange,
|
||||
replacementText text: String) -> Bool {
|
||||
|
||||
var shouldChange = true
|
||||
|
||||
if delegate == nil {
|
||||
|
||||
if let textViewDelegate: any UITextViewDelegate = textInputViewCachedInfo(textView)?.textViewDelegate {
|
||||
let selector = #selector((any UITextViewDelegate).textView(_:shouldChangeTextIn:replacementText:))
|
||||
if textViewDelegate.responds(to: selector) {
|
||||
shouldChange = (textViewDelegate.textView?(textView,
|
||||
shouldChangeTextIn: range,
|
||||
replacementText: text)) ?? true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.dismissTextViewOnReturn, text == "\n" {
|
||||
goToNextResponderOrResign(from: textView)
|
||||
return false
|
||||
}
|
||||
|
||||
return shouldChange
|
||||
}
|
||||
|
||||
func textViewDidChange(_ textView: UITextView) {
|
||||
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textViewDidChange?(textView)
|
||||
}
|
||||
|
||||
func textViewDidChangeSelection(_ textView: UITextView) {
|
||||
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textViewDidChangeSelection?(textView)
|
||||
}
|
||||
|
||||
@available(iOS, deprecated: 17.0)
|
||||
func textView(_ aTextView: UITextView,
|
||||
shouldInteractWith URL: URL,
|
||||
in characterRange: NSRange,
|
||||
interaction: UITextItemInteraction) -> Bool {
|
||||
|
||||
guard delegate == nil else { return true }
|
||||
|
||||
if let textViewDelegate: any UITextViewDelegate = textInputViewCachedInfo(aTextView)?.textViewDelegate {
|
||||
|
||||
let selector: Selector = #selector(textView as (UITextView, URL, NSRange, UITextItemInteraction) -> Bool)
|
||||
if textViewDelegate.responds(to: selector) {
|
||||
return textViewDelegate.textView?(aTextView,
|
||||
shouldInteractWith: URL,
|
||||
in: characterRange,
|
||||
interaction: interaction) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@available(iOS, deprecated: 17.0)
|
||||
func textView(_ aTextView: UITextView,
|
||||
shouldInteractWith textAttachment: NSTextAttachment,
|
||||
in characterRange: NSRange,
|
||||
interaction: UITextItemInteraction) -> Bool {
|
||||
|
||||
guard delegate == nil else { return true }
|
||||
|
||||
if let textViewDelegate: any UITextViewDelegate = textInputViewCachedInfo(aTextView)?.textViewDelegate {
|
||||
let selector: Selector = #selector(textView as
|
||||
(UITextView, NSTextAttachment, NSRange, UITextItemInteraction)
|
||||
-> Bool)
|
||||
if textViewDelegate.responds(to: selector) {
|
||||
return textViewDelegate.textView?(aTextView,
|
||||
shouldInteractWith: textAttachment,
|
||||
in: characterRange,
|
||||
interaction: interaction) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@available(iOS, deprecated: 10.0)
|
||||
func textView(_ aTextView: UITextView,
|
||||
shouldInteractWith URL: URL,
|
||||
in characterRange: NSRange) -> Bool {
|
||||
|
||||
guard delegate == nil else { return true }
|
||||
|
||||
if let textViewDelegate: any UITextViewDelegate = textInputViewCachedInfo(aTextView)?.textViewDelegate {
|
||||
|
||||
let selector: Selector = #selector(textView as (UITextView, URL, NSRange) -> Bool)
|
||||
|
||||
if textViewDelegate.responds(to: selector) {
|
||||
return textViewDelegate.textView?(aTextView,
|
||||
shouldInteractWith: URL,
|
||||
in: characterRange) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@available(iOS, deprecated: 10.0)
|
||||
func textView(_ aTextView: UITextView,
|
||||
shouldInteractWith textAttachment: NSTextAttachment,
|
||||
in characterRange: NSRange) -> Bool {
|
||||
|
||||
guard delegate == nil else { return true }
|
||||
|
||||
if let textViewDelegate: any UITextViewDelegate = textInputViewCachedInfo(aTextView)?.textViewDelegate {
|
||||
|
||||
let selector: Selector = #selector(textView as (UITextView, NSTextAttachment, NSRange) -> Bool)
|
||||
|
||||
if textViewDelegate.responds(to: selector) {
|
||||
return textViewDelegate.textView?(aTextView,
|
||||
shouldInteractWith: textAttachment,
|
||||
in: characterRange) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
#if compiler(>=5.7) // Xcode 14
|
||||
@available(iOS 16.0, *)
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardReturnManager {
|
||||
func textView(_ aTextView: UITextView,
|
||||
editMenuForTextIn range: NSRange,
|
||||
suggestedActions: [UIMenuElement]) -> UIMenu? {
|
||||
|
||||
guard delegate == nil else { return nil }
|
||||
|
||||
if let textViewDelegate: any UITextViewDelegate = textInputViewCachedInfo(aTextView)?.textViewDelegate {
|
||||
|
||||
let selector = #selector((any UITextViewDelegate).textView(_:editMenuForTextIn:suggestedActions:))
|
||||
if textViewDelegate.responds(to: selector) {
|
||||
return textViewDelegate.textView?(aTextView,
|
||||
editMenuForTextIn: range,
|
||||
suggestedActions: suggestedActions)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func textView(_ aTextView: UITextView,
|
||||
willPresentEditMenuWith animator: any UIEditMenuInteractionAnimating) {
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(aTextView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textView?(aTextView, willPresentEditMenuWith: animator)
|
||||
}
|
||||
|
||||
func textView(_ aTextView: UITextView,
|
||||
willDismissEditMenuWith animator: any UIEditMenuInteractionAnimating) {
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(aTextView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textView?(aTextView, willDismissEditMenuWith: animator)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if compiler(>=5.9) // Xcode 15
|
||||
@available(iOS 17.0, *)
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardReturnManager {
|
||||
|
||||
func textView(_ aTextView: UITextView,
|
||||
primaryActionFor textItem: UITextItem,
|
||||
defaultAction: UIAction) -> UIAction? {
|
||||
guard delegate == nil else { return nil }
|
||||
|
||||
if let textViewDelegate = textInputViewCachedInfo(aTextView)?.textViewDelegate {
|
||||
let selector = #selector((any UITextViewDelegate).textView(_:primaryActionFor:defaultAction:))
|
||||
|
||||
if textViewDelegate.responds(to: selector) {
|
||||
return textViewDelegate.textView?(aTextView,
|
||||
primaryActionFor: textItem,
|
||||
defaultAction: defaultAction)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func textView(_ aTextView: UITextView,
|
||||
menuConfigurationFor textItem: UITextItem,
|
||||
defaultMenu: UIMenu) -> UITextItem.MenuConfiguration? {
|
||||
guard delegate == nil else { return nil }
|
||||
|
||||
if let textViewDelegate = textInputViewCachedInfo(aTextView)?.textViewDelegate {
|
||||
let selector = #selector((any UITextViewDelegate).textView(_:menuConfigurationFor:defaultMenu:))
|
||||
if textViewDelegate.responds(to: selector) {
|
||||
return textViewDelegate.textView?(aTextView,
|
||||
menuConfigurationFor: textItem,
|
||||
defaultMenu: defaultMenu)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func textView(_ textView: UITextView,
|
||||
textItemMenuWillDisplayFor textItem: UITextItem,
|
||||
animator: any UIContextMenuInteractionAnimating) {
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model = textInputViewCachedInfo(textView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textView?(textView, textItemMenuWillDisplayFor: textItem, animator: animator)
|
||||
}
|
||||
|
||||
func textView(_ textView: UITextView,
|
||||
textItemMenuWillEndFor textItem: UITextItem,
|
||||
animator: any UIContextMenuInteractionAnimating) {
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model = textInputViewCachedInfo(textView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textView?(textView, textItemMenuWillEndFor: textItem, animator: animator)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if compiler(>=6.0) // Xcode 16
|
||||
@available(iOS 18.0, *)
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardReturnManager {
|
||||
|
||||
func textViewWritingToolsWillBegin(_ textView: UITextView) {
|
||||
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textViewWritingToolsWillBegin?(textView)
|
||||
}
|
||||
|
||||
func textViewWritingToolsDidEnd(_ textView: UITextView) {
|
||||
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textViewWritingToolsDidEnd?(textView)
|
||||
}
|
||||
|
||||
func textView(_ textView: UITextView,
|
||||
writingToolsIgnoredRangesInEnclosingRange enclosingRange: NSRange) -> [NSValue] {
|
||||
guard delegate == nil else { return [] }
|
||||
|
||||
if let textViewDelegate = textInputViewCachedInfo(textView)?.textViewDelegate {
|
||||
let selector = #selector((any UITextViewDelegate).textView(_:writingToolsIgnoredRangesInEnclosingRange:))
|
||||
if textViewDelegate.responds(to: selector) {
|
||||
return textViewDelegate.textView?(textView,
|
||||
writingToolsIgnoredRangesInEnclosingRange: enclosingRange) ?? []
|
||||
}
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
func textView(_ textView: UITextView, willBeginFormattingWith viewController: UITextFormattingViewController) {
|
||||
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textView?(textView, willBeginFormattingWith: viewController)
|
||||
}
|
||||
|
||||
func textView(_ textView: UITextView, didBeginFormattingWith viewController: UITextFormattingViewController) {
|
||||
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textView?(textView, didBeginFormattingWith: viewController)
|
||||
}
|
||||
|
||||
func textView(_ textView: UITextView, willEndFormattingWith viewController: UITextFormattingViewController) {
|
||||
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textView?(textView, willEndFormattingWith: viewController)
|
||||
}
|
||||
|
||||
func textView(_ textView: UITextView, didEndFormattingWith viewController: UITextFormattingViewController) {
|
||||
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textView?(textView, didEndFormattingWith: viewController)
|
||||
}
|
||||
|
||||
#if compiler(>=6.1) // Xcode 16.3
|
||||
@available(iOS 18.4, *)
|
||||
func textView(_ textView: UITextView, insertInputSuggestion inputSuggestion: UIInputSuggestion) {
|
||||
|
||||
var aDelegate: (any UITextViewDelegate)? = delegate
|
||||
|
||||
if aDelegate == nil {
|
||||
|
||||
if let model: IQTextInputViewInfoModel = textInputViewCachedInfo(textView) {
|
||||
aDelegate = model.textViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
aDelegate?.textView?(textView, insertInputSuggestion: inputSuggestion)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if compiler(>=6.2) // Xcode 26
|
||||
@available(iOS 26.0, *)
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardReturnManager {
|
||||
|
||||
func textView(_ textView: UITextView, shouldChangeTextInRanges ranges: [NSValue], replacementText text: String) -> Bool {
|
||||
|
||||
var shouldChange = true
|
||||
|
||||
if delegate == nil {
|
||||
|
||||
if let textViewDelegate: any UITextViewDelegate = textInputViewCachedInfo(textView)?.textViewDelegate {
|
||||
let selector = #selector((any UITextViewDelegate).textView(_:shouldChangeTextInRanges:replacementText:))
|
||||
if textViewDelegate.responds(to: selector) {
|
||||
shouldChange = (textViewDelegate.textView?(textView,
|
||||
shouldChangeTextInRanges: ranges,
|
||||
replacementText: text)) ?? true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.dismissTextViewOnReturn, text == "\n" {
|
||||
goToNextResponderOrResign(from: textView)
|
||||
return false
|
||||
}
|
||||
|
||||
return shouldChange
|
||||
}
|
||||
|
||||
func textView(_ textView: UITextView, editMenuForTextInRanges ranges: [NSValue], suggestedActions: [UIMenuElement]) -> UIMenu? {
|
||||
|
||||
guard delegate == nil else { return nil }
|
||||
|
||||
if let textViewDelegate: any UITextViewDelegate = textInputViewCachedInfo(textView)?.textViewDelegate {
|
||||
|
||||
let selector = #selector((any UITextViewDelegate).textView(_:editMenuForTextInRanges:suggestedActions:))
|
||||
if textViewDelegate.responds(to: selector) {
|
||||
return textViewDelegate.textView?(textView,
|
||||
editMenuForTextInRanges: ranges,
|
||||
suggestedActions: suggestedActions)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
#endif
|
||||
278
Pods/IQKeyboardReturnManager/IQKeyboardReturnManager/Classes/IQKeyboardReturnManager.swift
generated
Normal file
278
Pods/IQKeyboardReturnManager/IQKeyboardReturnManager/Classes/IQKeyboardReturnManager.swift
generated
Normal file
@ -0,0 +1,278 @@
|
||||
//
|
||||
// IQKeyboardReturnManager.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardReturnManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
import IQKeyboardCore
|
||||
|
||||
/**
|
||||
Manages the return key to work like next/done in a view hierarchy.
|
||||
*/
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objcMembers public final class IQKeyboardReturnManager: NSObject {
|
||||
|
||||
// MARK: Private variables
|
||||
private var textInputViewInfoCache: [IQTextInputViewInfoModel] = []
|
||||
|
||||
// MARK: Settings
|
||||
|
||||
/**
|
||||
Delegate of textInputView
|
||||
*/
|
||||
public weak var delegate: (any UITextFieldDelegate & UITextViewDelegate)?
|
||||
|
||||
/**
|
||||
Set the last textInputView return key type. Default is UIReturnKeyDefault.
|
||||
*/
|
||||
public var lastTextInputViewReturnKeyType: UIReturnKeyType = .default {
|
||||
|
||||
didSet {
|
||||
if let activeModel = textInputViewInfoCache.first(where: {
|
||||
guard let textInputView = $0.textInputView else {
|
||||
return false
|
||||
}
|
||||
return textInputView.isFirstResponder
|
||||
}), let view: any IQTextInputView = activeModel.textInputView {
|
||||
updateReturnKey(textInputView: view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var dismissTextViewOnReturn: Bool = false
|
||||
|
||||
// MARK: Initialization/De-initialization
|
||||
|
||||
public override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
@available(*, unavailable, message: "Please use addResponderSubviews(of:recursive:)")
|
||||
public init(controller: UIViewController) {
|
||||
super.init()
|
||||
addResponderSubviews(of: controller.view, recursive: true)
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
// for model in textInputViewInfoCache {
|
||||
// model.restore()
|
||||
// }
|
||||
|
||||
textInputViewInfoCache.removeAll()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Registering/Unregistering textInputView
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardReturnManager {
|
||||
|
||||
/**
|
||||
Should pass TextInputView instance. Assign textInputView delegate to self, change it's returnKeyType.
|
||||
|
||||
@param textInputView TextInputView object to register.
|
||||
*/
|
||||
func add(textInputView: any IQTextInputView) {
|
||||
|
||||
let model = IQTextInputViewInfoModel(textInputView: textInputView)
|
||||
textInputViewInfoCache.append(model)
|
||||
|
||||
if let view: UITextField = textInputView as? UITextField {
|
||||
view.delegate = self
|
||||
} else if let view: UITextView = textInputView as? UITextView {
|
||||
view.delegate = self
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Should pass TextInputView instance. Restore it's textInputView delegate and it's returnKeyType.
|
||||
|
||||
@param textInputView TextInputView object to unregister.
|
||||
*/
|
||||
func remove(textInputView: any IQTextInputView) {
|
||||
|
||||
guard let index: Int = textInputViewCachedInfoIndex(textInputView) else { return }
|
||||
|
||||
let model = textInputViewInfoCache.remove(at: index)
|
||||
model.restore()
|
||||
}
|
||||
|
||||
/**
|
||||
Add all the TextInputView responderView's.
|
||||
|
||||
@param view object to register all it's responder subviews.
|
||||
*/
|
||||
func addResponderSubviews(of view: UIView, recursive: Bool) {
|
||||
|
||||
let textInputViews: [any IQTextInputView] = view.responderSubviews(recursive: recursive)
|
||||
|
||||
for view in textInputViews {
|
||||
add(textInputView: view)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Remove all the TextInputView responderView's.
|
||||
|
||||
@param view object to unregister all it's responder subviews.
|
||||
*/
|
||||
func removeResponderSubviews(of view: UIView, recursive: Bool) {
|
||||
|
||||
let textInputViews: [any IQTextInputView] = view.responderSubviews(recursive: recursive)
|
||||
|
||||
for view in textInputViews {
|
||||
remove(textInputView: view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardReturnManager {
|
||||
@discardableResult
|
||||
func goToNextResponderOrResign(from textInputView: any IQTextInputView) -> Bool {
|
||||
|
||||
guard let textInfoCache: IQTextInputViewInfoModel = nextResponderFromTextInputView(textInputView),
|
||||
let textInputView = textInfoCache.textInputView else {
|
||||
textInputView.resignFirstResponder()
|
||||
return true
|
||||
}
|
||||
|
||||
textInputView.becomeFirstResponder()
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Internal Functions
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
internal extension IQKeyboardReturnManager {
|
||||
|
||||
func nextResponderFromTextInputView(_ textInputView: some IQTextInputView) -> IQTextInputViewInfoModel? {
|
||||
guard let currentIndex: Int = textInputViewCachedInfoIndex(textInputView),
|
||||
currentIndex < textInputViewInfoCache.count - 1 else { return nil }
|
||||
|
||||
let candidates = Array(textInputViewInfoCache[currentIndex+1..<textInputViewInfoCache.count])
|
||||
|
||||
return candidates.first {
|
||||
guard let inputView = $0.textInputView,
|
||||
inputView.isUserInteractionEnabled,
|
||||
!inputView.isHidden, inputView.alpha != 0.0
|
||||
else { return false }
|
||||
|
||||
return inputView.iqIsEnabled
|
||||
}
|
||||
}
|
||||
|
||||
func textInputViewCachedInfoIndex(_ textInputView: some IQTextInputView) -> Int? {
|
||||
return textInputViewInfoCache.firstIndex {
|
||||
guard let inputView = $0.textInputView else { return false }
|
||||
return inputView == textInputView
|
||||
}
|
||||
}
|
||||
|
||||
func textInputViewCachedInfo(_ textInputView: some IQTextInputView) -> IQTextInputViewInfoModel? {
|
||||
guard let index: Int = textInputViewCachedInfoIndex(textInputView) else { return nil }
|
||||
return textInputViewInfoCache[index]
|
||||
}
|
||||
|
||||
func updateReturnKey(textInputView: some IQTextInputView) {
|
||||
|
||||
let returnKey: UIReturnKeyType
|
||||
if nextResponderFromTextInputView(textInputView) != nil {
|
||||
returnKey = .next
|
||||
} else {
|
||||
returnKey = lastTextInputViewReturnKeyType
|
||||
}
|
||||
|
||||
if textInputView.returnKeyType != returnKey {
|
||||
// If it's the last textInputView in responder view, else next
|
||||
textInputView.returnKeyType = returnKey
|
||||
textInputView.reloadInputViews()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Deprecated
|
||||
// swiftlint:disable unused_setter_value
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
@objc public extension IQKeyboardReturnManager {
|
||||
|
||||
@available(*, unavailable, renamed: "lastTextInputViewReturnKeyType")
|
||||
var lastTextFieldReturnKeyType: UIReturnKeyType {
|
||||
get { .default }
|
||||
set { }
|
||||
}
|
||||
|
||||
@available(*, unavailable, renamed: "add(textInputView:)")
|
||||
func addTextFieldView(_ textInputView: any IQTextInputView) { }
|
||||
|
||||
@available(*, unavailable, renamed: "remove(textInputView:)")
|
||||
func removeTextFieldView(_ textInputView: any IQTextInputView) { }
|
||||
|
||||
@available(*, unavailable, renamed: "addResponderSubviews(of:recursive:)")
|
||||
func addResponderFromView(_ view: UIView, recursive: Bool) { }
|
||||
|
||||
@available(*, unavailable, renamed: "removeResponderSubviews(of:recursive:)")
|
||||
func removeResponderFromView(_ view: UIView, recursive: Bool = true) { }
|
||||
}
|
||||
// swiftlint:enable unused_setter_value
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
fileprivate extension UIView {
|
||||
|
||||
func responderSubviews(recursive: Bool) -> [any IQTextInputView] {
|
||||
|
||||
// Array of TextInputViews.
|
||||
var textInputViews: [any IQTextInputView] = []
|
||||
for view in subviews {
|
||||
|
||||
if let view = view as? IQTextInputView {
|
||||
textInputViews.append(view)
|
||||
}
|
||||
// Sometimes there are hidden or disabled views and textInputView inside them still recorded,
|
||||
// so we added some more validations here (Bug ID: #458)
|
||||
// Uncommented else (Bug ID: #625)
|
||||
else if recursive, !view.subviews.isEmpty {
|
||||
let deepResponders = view.responderSubviews(recursive: recursive)
|
||||
textInputViews.append(contentsOf: deepResponders)
|
||||
}
|
||||
}
|
||||
|
||||
// subviews are returning in opposite order. Sorting according the frames 'y'.
|
||||
return textInputViews.sorted(by: { (view1: any IQTextInputView, view2: any IQTextInputView) -> Bool in
|
||||
|
||||
let frame1: CGRect = view1.convert(view1.bounds, to: self)
|
||||
let frame2: CGRect = view2.convert(view2.bounds, to: self)
|
||||
|
||||
if frame1.minY != frame2.minY {
|
||||
return frame1.minY < frame2.minY
|
||||
} else {
|
||||
return frame1.minX < frame2.minX
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
56
Pods/IQKeyboardReturnManager/IQKeyboardReturnManager/Classes/IQTextInputViewInfoModel.swift
generated
Normal file
56
Pods/IQKeyboardReturnManager/IQKeyboardReturnManager/Classes/IQTextInputViewInfoModel.swift
generated
Normal file
@ -0,0 +1,56 @@
|
||||
//
|
||||
// IQTextInputViewInfoModel.swift
|
||||
// https://github.com/hackiftekhar/IQKeyboardReturnManager
|
||||
// Copyright (c) 2013-24 Iftekhar Qurashi.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
import IQKeyboardCore
|
||||
|
||||
@available(iOSApplicationExtension, unavailable)
|
||||
@MainActor
|
||||
internal final class IQTextInputViewInfoModel: NSObject {
|
||||
|
||||
weak var textFieldDelegate: (any UITextFieldDelegate)?
|
||||
weak var textViewDelegate: (any UITextViewDelegate)?
|
||||
weak var textInputView: (any IQTextInputView)?
|
||||
let originalReturnKeyType: UIReturnKeyType
|
||||
|
||||
init(textInputView: any IQTextInputView) {
|
||||
self.textInputView = textInputView
|
||||
self.originalReturnKeyType = textInputView.returnKeyType
|
||||
if let textInputView = textInputView as? UITextField {
|
||||
self.textFieldDelegate = textInputView.delegate
|
||||
} else if let textInputView = textInputView as? UITextView {
|
||||
self.textViewDelegate = textInputView.delegate
|
||||
}
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
func restore() {
|
||||
textInputView?.returnKeyType = originalReturnKeyType
|
||||
if let textInputView = textInputView as? UITextField {
|
||||
textInputView.delegate = textFieldDelegate
|
||||
} else if let textInputView = textInputView as? UITextView {
|
||||
textInputView.delegate = textViewDelegate
|
||||
}
|
||||
}
|
||||
}
|
||||
21
Pods/IQKeyboardReturnManager/LICENSE
generated
Normal file
21
Pods/IQKeyboardReturnManager/LICENSE
generated
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Mohd Iftekhar Qurashi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
68
Pods/IQKeyboardReturnManager/README.md
generated
Normal file
68
Pods/IQKeyboardReturnManager/README.md
generated
Normal file
@ -0,0 +1,68 @@
|
||||
# IQKeyboardReturnManager
|
||||
|
||||
[](https://travis-ci.org/hackiftekhar/IQKeyboardReturnManager)
|
||||
[](https://cocoapods.org/pods/IQKeyboardReturnManager)
|
||||
[](https://cocoapods.org/pods/IQKeyboardReturnManager)
|
||||
[](https://cocoapods.org/pods/IQKeyboardReturnManager)
|
||||
|
||||

|
||||
|
||||
## Example
|
||||
|
||||
To run the example project, clone the repo, and run `pod install` from the Example directory first.
|
||||
|
||||
## Requirements
|
||||
|
||||
## Installation
|
||||
|
||||
IQKeyboardReturnManager is available through [CocoaPods](https://cocoapods.org). To install
|
||||
it, simply add the following line to your Podfile:
|
||||
|
||||
```ruby
|
||||
pod 'IQKeyboardReturnManager'
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
To handle keyboard return key automatically:-
|
||||
|
||||
```swift
|
||||
import IQKeyboardReturnManager
|
||||
|
||||
class ViewController: UIViewController {
|
||||
|
||||
let returnManager: IQKeyboardReturnManager = .init()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// This will add all textInputView of the controller and start observing for textFieldShouldReturn events
|
||||
returnManager.addResponderSubviews(of: self.view, recursive: true)
|
||||
|
||||
// If you would like to dismiss the UITextView on tapping on return then add this
|
||||
returnManager.dismissTextViewOnReturn = true
|
||||
|
||||
// If you would like to change last textInputView return key type to done or something else, then add this
|
||||
returnManager.lastTextInputViewReturnKeyType = .done
|
||||
|
||||
// If you would like to customize the navigation between textField by your own order then add them manually
|
||||
returnManager.add(textInputView: textField1)
|
||||
returnManager.add(textInputView: textField2)
|
||||
returnManager.add(textInputView: textField3)
|
||||
returnManager.add(textInputView: textField4)
|
||||
}
|
||||
}
|
||||
|
||||
// IQKeyboardReturnManager will forward all delegate callbacks to you, so you can customize the decisions
|
||||
extension ViewController: UITextFieldDelegate {
|
||||
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {...}
|
||||
}
|
||||
```
|
||||
|
||||
## Author
|
||||
|
||||
Iftekhar Qurashi hack.iftekhar@gmail.com
|
||||
|
||||
## License
|
||||
|
||||
IQKeyboardReturnManager is available under the MIT license. See the LICENSE file for more info.
|
||||
Reference in New Issue
Block a user