完善任务流程、键盘适配与页面交互

This commit is contained in:
2026-07-10 15:56:15 +08:00
parent f88a85a807
commit ab5220e460
189 changed files with 16779 additions and 1038 deletions

View File

@ -0,0 +1,41 @@
//
// IQKeyboardConstants.swift
// https://github.com/hackiftekhar/IQKeyboardCore
// 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 Foundation
/**
`IQEnableModeDefault`
Pick default settings.
`IQEnableModeEnabled`
setting is enabled.
`IQEnableModeDisabled`
setting is disabled.
*/
@available(iOSApplicationExtension, unavailable)
@objc public enum IQEnableMode: Int {
case `default`
case enabled
case disabled
}

View File

@ -0,0 +1,65 @@
//
// IQKeyboardExtended.swift
// https://github.com/hackiftekhar/IQKeyboardCore
// 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
/// Wrapper for IQKeyboardManager compatible types. This type provides an extension point for
/// convenience methods in IQKeyboardManager.
@available(iOSApplicationExtension, unavailable)
public struct IQKeyboardExtension<Base: AnyObject> {
public private(set) weak var base: Base?
fileprivate init(_ base: Base) {
self.base = base
}
}
// swiftlint:disable identifier_name
/// Represents an object type that is compatible with IQKeyboardManager. You can use `iq` property to get a
/// value in the namespace of IQKeyboardManager.
@available(iOSApplicationExtension, unavailable)
public protocol IQKeyboardExtended {
/// Type being extended.
associatedtype Base: AnyObject
/// Instance IQKeyboardManager extension point.
@MainActor
var iq: IQKeyboardExtension<Base> { get set }
}
// swiftlint:disable unused_setter_value
@available(iOSApplicationExtension, unavailable)
public extension IQKeyboardExtended where Self: UIView {
/// Instance IQKeyboardManager extension point.
@MainActor
var iq: IQKeyboardExtension<Self> {
get { IQKeyboardExtension(self) }
set {}
}
}
// swiftlint:enable unused_setter_value
// swiftlint:enable identifier_name
@available(iOSApplicationExtension, unavailable)
@MainActor
extension UIView: IQKeyboardExtended {}

View File

@ -0,0 +1,99 @@
//
// IQTextInputView.swift
// https://github.com/hackiftekhar/IQKeyboardCore
// 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
@available(iOSApplicationExtension, unavailable)
@MainActor
@objc public protocol IQTextInputView where Self: UIView, Self: UITextInputTraits {
#if compiler(>=5.7) // Xcode 14
@available(iOS 16.0, *)
@objc var iqIsFindInteractionEnabled: Bool { get }
@available(iOS 16.0, *)
@objc var iqFindInteraction: UIFindInteraction? { get }
#endif
@objc var returnKeyType: UIReturnKeyType { get set }
@objc var keyboardAppearance: UIKeyboardAppearance { get set }
@objc var iqIsEnabled: Bool { get }
@objc var inputAccessoryView: UIView? { get set }
}
@available(iOSApplicationExtension, unavailable)
@MainActor
@objc extension UITextField: IQTextInputView {
#if compiler(>=5.7) // Xcode 14
@available(iOS 16.0, *)
public var iqIsFindInteractionEnabled: Bool { false }
@available(iOS 16.0, *)
public var iqFindInteraction: UIFindInteraction? { nil }
#endif
public var iqIsEnabled: Bool { isEnabled }
}
@available(iOSApplicationExtension, unavailable)
@MainActor
@objc extension UITextView: IQTextInputView {
#if compiler(>=5.7) // Xcode 14
@available(iOS 16.0, *)
public var iqIsFindInteractionEnabled: Bool { isFindInteractionEnabled }
@available(iOS 16.0, *)
public var iqFindInteraction: UIFindInteraction? { findInteraction }
#endif
public var iqIsEnabled: Bool { isEditable }
}
@available(iOSApplicationExtension, unavailable)
@MainActor
@objc extension UISearchBar: IQTextInputView {
#if compiler(>=5.7) // Xcode 14
@available(iOS 16.0, *)
public var iqIsFindInteractionEnabled: Bool { false }
@available(iOS 16.0, *)
public var iqFindInteraction: UIFindInteraction? { nil }
#endif
public var iqIsEnabled: Bool {
#if compiler(>=5.8) // Xcode 14.4
if #available(iOS 16.4, *) {
return isEnabled
} else {
return searchTextField.isEnabled
}
#else
return searchTextField.isEnabled
#endif
}
}

View File

@ -0,0 +1,180 @@
//
// UIView+Hierarchy.swift
// https://github.com/hackiftekhar/IQKeyboardCore
// 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
/**
UIView hierarchy category.
*/
@available(iOSApplicationExtension, unavailable)
@MainActor
public extension IQKeyboardExtension where Base: UIView {
// MARK: viewControllers
/**
Returns the UIViewController object that manages the receiver.
*/
func viewContainingController() -> UIViewController? {
var nextResponder: UIResponder? = base
repeat {
nextResponder = nextResponder?.next
if let viewController: UIViewController = nextResponder as? UIViewController {
return viewController
}
} while nextResponder != nil
return nil
}
@available(*, unavailable, message: "This has been removed because it no longer needed")
func topMostController() -> UIViewController? { nil }
}
@available(iOSApplicationExtension, unavailable)
@MainActor
public extension IQKeyboardExtension where Base: UIView {
// MARK: Superviews
/**
Returns the superView of provided class type.
@param classType class type of the object which is to be search in above hierarchy and return
@param belowView view object in upper hierarchy where method should stop searching and return nil
*/
func superviewOf<T: UIView>(type classType: T.Type, belowView: UIView? = nil) -> T? {
var superView: UIView? = base?.superview
while let aSuperview: UIView = superView {
if aSuperview.isKind(of: classType) {
// If it's UIScrollView, then validating for special cases
if aSuperview is UIScrollView {
let classNameString: String = "\(type(of: aSuperview.self))"
// If it's not UITableViewWrapperView class,
// this is internal class which is actually manage in UITableview.
// The speciality of this class is that it's superview is UITableView.
// If it's not UITableViewCellScrollView class,
// this is internal class which is actually manage in UITableviewCell.
// The speciality of this class is that it's superview is UITableViewCell.
// If it's not _UIQueuingScrollView class,
// actually we validate for _ prefix which usually used by Apple internal classes
if !(aSuperview.superview is UITableView),
!(aSuperview.superview is UITableViewCell),
!classNameString.hasPrefix("_") {
return superView as? T
}
} else {
return superView as? T
}
} else if aSuperview == belowView {
return nil
}
superView = aSuperview.superview
}
return nil
}
// MARK: Special TextFields
/**
Returns searchBar if receiver object is UISearchBarTextField, otherwise return nil.
*/
func textFieldSearchBar() -> UISearchBar? {
if base is UISearchTextField,
var textInputViewController = base?.iq.viewContainingController() {
if let navController: UINavigationController = textInputViewController as? UINavigationController,
let topController: UIViewController = navController.topViewController {
textInputViewController = topController
}
// Not adjusting for searchTextField inside searchController.
if textInputViewController.navigationItem.searchController?.searchBar.searchTextField == base {
return textInputViewController.navigationItem.searchController?.searchBar
}
} else {
var responder: UIResponder? = base?.next
while let bar: UIResponder = responder {
if let searchBar: UISearchBar = bar as? UISearchBar {
return searchBar
} else if bar is UIViewController {
break
}
responder = bar.next
}
}
return nil
}
/**
Returns YES if the receiver object is UIAlertSheetTextField, otherwise return NO.
*/
func isAlertViewTextField() -> Bool {
var alertViewController: UIResponder? = viewContainingController()
var isAlertViewTextField: Bool = false
while let controller: UIResponder = alertViewController, !isAlertViewTextField {
if controller is UIAlertController {
isAlertViewTextField = true
break
}
alertViewController = controller.next
}
return isAlertViewTextField
}
}
@available(iOSApplicationExtension, unavailable)
@MainActor
@objc public extension UIView {
@available(*, unavailable, renamed: "iq.viewContainingController()")
func viewContainingController() -> UIViewController? { nil }
@available(*, unavailable, message: "This has been removed because it no longer needed")
func topMostController() -> UIViewController? { nil }
@available(*, unavailable, renamed: "iq.superviewOf(type:belowView:)")
func superviewOfClassType(_ classType: UIView.Type, belowView: UIView? = nil) -> UIView? { nil }
}