Commit 970a015a authored by lmj_521aiau@163.com's avatar lmj_521aiau@163.com

no message

parent 147b1501
......@@ -11,7 +11,8 @@ target 'ShorthandMaster' do
pod 'SnapKit' # 布局
pod 'SwiftyStoreKit'
pod 'MBProgressHUD'
pod 'IQKeyboardManagerSwift'
pod 'PDFGenerator', '~> 3.1'
pod 'Masonry'
......
//
// IQNSArray+Sort.swift
// https://github.com/hackiftekhar/IQKeyboardManager
// Copyright (c) 2013-16 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
import UIKit
/**
UIView.subviews sorting category.
*/
internal extension Array where Element: UIView {
///--------------
/// MARK: Sorting
///--------------
/**
Returns the array by sorting the UIView's by their tag property.
*/
func sortedArrayByTag() -> [Element] {
return sorted(by: { (obj1: Element, obj2: Element) -> Bool in
return (obj1.tag < obj2.tag)
})
}
/**
Returns the array by sorting the UIView's by their tag property.
*/
func sortedArrayByPosition() -> [Element] {
return sorted(by: { (obj1: Element, obj2: Element) -> Bool in
if obj1.frame.minY != obj2.frame.minY {
return obj1.frame.minY < obj2.frame.minY
} else {
return obj1.frame.minX < obj2.frame.minX
}
})
}
}
//
// IQUIScrollView+Additions.swift
// https://github.com/hackiftekhar/IQKeyboardManager
// Copyright (c) 2013-16 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
import UIKit
private var kIQShouldIgnoreScrollingAdjustment = "kIQShouldIgnoreScrollingAdjustment"
private var kIQShouldIgnoreContentInsetAdjustment = "kIQShouldIgnoreContentInsetAdjustment"
private var kIQShouldRestoreScrollViewContentOffset = "kIQShouldRestoreScrollViewContentOffset"
@objc public extension UIScrollView {
/**
If YES, then scrollview will ignore scrolling (simply not scroll it) for adjusting textfield position. Default is NO.
*/
@objc var shouldIgnoreScrollingAdjustment: Bool {
get {
if let aValue = objc_getAssociatedObject(self, &kIQShouldIgnoreScrollingAdjustment) as? Bool {
return aValue
} else {
return false
}
}
set(newValue) {
objc_setAssociatedObject(self, &kIQShouldIgnoreScrollingAdjustment, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
/**
If YES, then scrollview will ignore content inset adjustment (simply not updating it) when keyboard is shown. Default is NO.
*/
@objc var shouldIgnoreContentInsetAdjustment: Bool {
get {
if let aValue = objc_getAssociatedObject(self, &kIQShouldIgnoreContentInsetAdjustment) as? Bool {
return aValue
} else {
return false
}
}
set(newValue) {
objc_setAssociatedObject(self, &kIQShouldIgnoreContentInsetAdjustment, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
/**
To set customized distance from keyboard for textField/textView. Can't be less than zero
*/
@objc var shouldRestoreScrollViewContentOffset: Bool {
get {
if let aValue = objc_getAssociatedObject(self, &kIQShouldRestoreScrollViewContentOffset) as? Bool {
return aValue
} else {
return false
}
}
set(newValue) {
objc_setAssociatedObject(self, &kIQShouldRestoreScrollViewContentOffset, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
internal extension UITableView {
func previousIndexPath(of indexPath: IndexPath) -> IndexPath? {
var previousRow = indexPath.row - 1
var previousSection = indexPath.section
//Fixing indexPath
if previousRow < 0 {
previousSection -= 1
if previousSection >= 0 {
previousRow = self.numberOfRows(inSection: previousSection) - 1
}
}
if previousRow >= 0 && previousSection >= 0 {
return IndexPath(row: previousRow, section: previousSection)
} else {
return nil
}
}
}
internal extension UICollectionView {
func previousIndexPath(of indexPath: IndexPath) -> IndexPath? {
var previousRow = indexPath.row - 1
var previousSection = indexPath.section
//Fixing indexPath
if previousRow < 0 {
previousSection -= 1
if previousSection >= 0 {
previousRow = self.numberOfItems(inSection: previousSection) - 1
}
}
if previousRow >= 0 && previousSection >= 0 {
return IndexPath(item: previousRow, section: previousSection)
} else {
return nil
}
}
}
//
// IQUITextFieldView+Additions.swift
// https://github.com/hackiftekhar/IQKeyboardManager
// Copyright (c) 2013-16 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
import UIKit
/**
Uses default keyboard distance for textField.
*/
public let kIQUseDefaultKeyboardDistance = CGFloat.greatestFiniteMagnitude
private var kIQKeyboardDistanceFromTextField = "kIQKeyboardDistanceFromTextField"
private var kIQKeyboardEnableMode = "kIQKeyboardEnableMode"
private var kIQShouldResignOnTouchOutsideMode = "kIQShouldResignOnTouchOutsideMode"
private var kIQIgnoreSwitchingByNextPrevious = "kIQIgnoreSwitchingByNextPrevious"
/**
UIView category for managing UITextField/UITextView
*/
@objc public extension UIView {
/**
To set customized distance from keyboard for textField/textView. Can't be less than zero
*/
@objc var keyboardDistanceFromTextField: CGFloat {
get {
if let aValue = objc_getAssociatedObject(self, &kIQKeyboardDistanceFromTextField) as? CGFloat {
return aValue
} else {
return kIQUseDefaultKeyboardDistance
}
}
set(newValue) {
objc_setAssociatedObject(self, &kIQKeyboardDistanceFromTextField, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
/**
If shouldIgnoreSwitchingByNextPrevious is true then library will ignore this textField/textView while moving to other textField/textView using keyboard toolbar next previous buttons. Default is false
*/
@objc var ignoreSwitchingByNextPrevious: Bool {
get {
if let aValue = objc_getAssociatedObject(self, &kIQIgnoreSwitchingByNextPrevious) as? Bool {
return aValue
} else {
return false
}
}
set(newValue) {
objc_setAssociatedObject(self, &kIQIgnoreSwitchingByNextPrevious, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
// /**
// Override Enable/disable managing distance between keyboard and textField behaviour for this particular textField.
// */
@objc var enableMode: IQEnableMode {
get {
if let savedMode = objc_getAssociatedObject(self, &kIQKeyboardEnableMode) as? IQEnableMode {
return savedMode
} else {
return .default
}
}
set(newValue) {
objc_setAssociatedObject(self, &kIQKeyboardEnableMode, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
/**
Override resigns Keyboard on touching outside of UITextField/View behaviour for this particular textField.
*/
@objc var shouldResignOnTouchOutsideMode: IQEnableMode {
get {
if let savedMode = objc_getAssociatedObject(self, &kIQShouldResignOnTouchOutsideMode) as? IQEnableMode {
return savedMode
} else {
return .default
}
}
set(newValue) {
objc_setAssociatedObject(self, &kIQShouldResignOnTouchOutsideMode, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
//
// IQUIViewController+Additions.swift
// https://github.com/hackiftekhar/IQKeyboardManager
// Copyright (c) 2013-16 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
private var kIQLayoutGuideConstraint = "kIQLayoutGuideConstraint"
@objc public extension UIViewController {
/**
This method is provided to override by viewController's if the library lifts a viewController which you doesn't want to lift . This may happen if you have implemented side menu feature in your app and the library try to lift the side menu controller. Overriding this method in side menu class to return correct controller should fix the problem.
*/
func parentIQContainerViewController() -> UIViewController? {
return self
}
/**
To set customized distance from keyboard for textField/textView. Can't be less than zero
@deprecated Due to change in core-logic of handling distance between textField and keyboard distance, this layout contraint tweak is no longer needed and things will just work out of the box regardless of constraint pinned with safeArea/layoutGuide/superview
*/
@available(*, deprecated, message: "Due to change in core-logic of handling distance between textField and keyboard distance, this layout contraint tweak is no longer needed and things will just work out of the box regardless of constraint pinned with safeArea/layoutGuide/superview.")
@IBOutlet @objc var IQLayoutGuideConstraint: NSLayoutConstraint? {
get {
return objc_getAssociatedObject(self, &kIQLayoutGuideConstraint) as? NSLayoutConstraint
}
set(newValue) {
objc_setAssociatedObject(self, &kIQLayoutGuideConstraint, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
//
// IQKeyboardManagerConstants.swift
// https://github.com/hackiftekhar/IQKeyboardManager
// Copyright (c) 2013-16 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
///-----------------------------------
/// MARK: IQAutoToolbarManageBehaviour
///-----------------------------------
/**
`IQAutoToolbarBySubviews`
Creates Toolbar according to subview's hirarchy of Textfield's in view.
`IQAutoToolbarByTag`
Creates Toolbar according to tag property of TextField's.
`IQAutoToolbarByPosition`
Creates Toolbar according to the y,x position of textField in it's superview coordinate.
*/
@objc public enum IQAutoToolbarManageBehaviour: Int {
case bySubviews
case byTag
case byPosition
}
/**
`IQPreviousNextDisplayModeDefault`
Show NextPrevious when there are more than 1 textField otherwise hide.
`IQPreviousNextDisplayModeAlwaysHide`
Do not show NextPrevious buttons in any case.
`IQPreviousNextDisplayModeAlwaysShow`
Always show nextPrevious buttons, if there are more than 1 textField then both buttons will be visible but will be shown as disabled.
*/
@objc public enum IQPreviousNextDisplayMode: Int {
case `default`
case alwaysHide
case alwaysShow
}
/**
`IQEnableModeDefault`
Pick default settings.
`IQEnableModeEnabled`
setting is enabled.
`IQEnableModeDisabled`
setting is disabled.
*/
@objc public enum IQEnableMode: Int {
case `default`
case enabled
case disabled
}
/*
/---------------------------------------------------------------------------------------------------\
\---------------------------------------------------------------------------------------------------/
| iOS Notification Mechanism |
/---------------------------------------------------------------------------------------------------\
\---------------------------------------------------------------------------------------------------/
------------------------------------------------------------
When UITextField become first responder
------------------------------------------------------------
- UITextFieldTextDidBeginEditingNotification (UITextField)
- UIKeyboardWillShowNotification
- UIKeyboardDidShowNotification
------------------------------------------------------------
When UITextView become first responder
------------------------------------------------------------
- UIKeyboardWillShowNotification
- UITextViewTextDidBeginEditingNotification (UITextView)
- UIKeyboardDidShowNotification
------------------------------------------------------------
When switching focus from UITextField to another UITextField
------------------------------------------------------------
- UITextFieldTextDidEndEditingNotification (UITextField1)
- UITextFieldTextDidBeginEditingNotification (UITextField2)
- UIKeyboardWillShowNotification
- UIKeyboardDidShowNotification
------------------------------------------------------------
When switching focus from UITextView to another UITextView
------------------------------------------------------------
- UITextViewTextDidEndEditingNotification: (UITextView1)
- UIKeyboardWillShowNotification
- UITextViewTextDidBeginEditingNotification: (UITextView2)
- UIKeyboardDidShowNotification
------------------------------------------------------------
When switching focus from UITextField to UITextView
------------------------------------------------------------
- UITextFieldTextDidEndEditingNotification (UITextField)
- UIKeyboardWillShowNotification
- UITextViewTextDidBeginEditingNotification (UITextView)
- UIKeyboardDidShowNotification
------------------------------------------------------------
When switching focus from UITextView to UITextField
------------------------------------------------------------
- UITextViewTextDidEndEditingNotification (UITextView)
- UITextFieldTextDidBeginEditingNotification (UITextField)
- UIKeyboardWillShowNotification
- UIKeyboardDidShowNotification
------------------------------------------------------------
When opening/closing UIKeyboard Predictive bar
------------------------------------------------------------
- UIKeyboardWillShowNotification
- UIKeyboardDidShowNotification
------------------------------------------------------------
On orientation change
------------------------------------------------------------
- UIApplicationWillChangeStatusBarOrientationNotification
- UIKeyboardWillHideNotification
- UIKeyboardDidHideNotification
- UIApplicationDidChangeStatusBarOrientationNotification
- UIKeyboardWillShowNotification
- UIKeyboardDidShowNotification
- UIKeyboardWillShowNotification
- UIKeyboardDidShowNotification
*/
//
// IQKeyboardManagerConstantsInternal.swift
// https://github.com/hackiftekhar/IQKeyboardManager
// Copyright (c) 2013-16 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
This source diff could not be displayed because it is too large. You can view the blob instead.
//
// IQTextView.swift
// https://github.com/hackiftekhar/IQKeyboardManager
// Copyright (c) 2013-16 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
/** @abstract UITextView with placeholder support */
open class IQTextView: UITextView {
@objc required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
#if swift(>=4.2)
let UITextViewTextDidChange = UITextView.textDidChangeNotification
#else
let UITextViewTextDidChange = Notification.Name.UITextViewTextDidChange
#endif
NotificationCenter.default.addObserver(self, selector: #selector(self.refreshPlaceholder), name: UITextViewTextDidChange, object: self)
}
@objc override public init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
#if swift(>=4.2)
let notificationName = UITextView.textDidChangeNotification
#else
let notificationName = Notification.Name.UITextViewTextDidChange
#endif
NotificationCenter.default.addObserver(self, selector: #selector(self.refreshPlaceholder), name: notificationName, object: self)
}
@objc override open func awakeFromNib() {
super.awakeFromNib()
#if swift(>=4.2)
let UITextViewTextDidChange = UITextView.textDidChangeNotification
#else
let UITextViewTextDidChange = Notification.Name.UITextViewTextDidChange
#endif
NotificationCenter.default.addObserver(self, selector: #selector(self.refreshPlaceholder), name: UITextViewTextDidChange, object: self)
}
deinit {
IQ_PlaceholderLabel.removeFromSuperview()
NotificationCenter.default.removeObserver(self)
}
private var placeholderInsets: UIEdgeInsets {
return UIEdgeInsets(top: self.textContainerInset.top, left: self.textContainerInset.left + self.textContainer.lineFragmentPadding, bottom: self.textContainerInset.bottom, right: self.textContainerInset.right + self.textContainer.lineFragmentPadding)
}
private var placeholderExpectedFrame: CGRect {
let placeholderInsets = self.placeholderInsets
let maxWidth = self.frame.width-placeholderInsets.left-placeholderInsets.right
let expectedSize = IQ_PlaceholderLabel.sizeThatFits(CGSize(width: maxWidth, height: self.frame.height-placeholderInsets.top-placeholderInsets.bottom))
return CGRect(x: placeholderInsets.left, y: placeholderInsets.top, width: maxWidth, height: expectedSize.height)
}
lazy var IQ_PlaceholderLabel: UILabel = {
let label = UILabel()
label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
label.lineBreakMode = .byWordWrapping
label.numberOfLines = 0
label.font = self.font
label.textAlignment = self.textAlignment
label.backgroundColor = UIColor.clear
#if swift(>=5.1)
label.textColor = UIColor.systemGray
#else
label.textColor = UIColor.lightText
#endif
label.alpha = 0
self.addSubview(label)
return label
}()
/** @abstract To set textView's placeholder text color. */
@IBInspectable open var placeholderTextColor: UIColor? {
get {
return IQ_PlaceholderLabel.textColor
}
set {
IQ_PlaceholderLabel.textColor = newValue
}
}
/** @abstract To set textView's placeholder text. Default is nil. */
@IBInspectable open var placeholder: String? {
get {
return IQ_PlaceholderLabel.text
}
set {
IQ_PlaceholderLabel.text = newValue
refreshPlaceholder()
}
}
/** @abstract To set textView's placeholder attributed text. Default is nil. */
open var attributedPlaceholder: NSAttributedString? {
get {
return IQ_PlaceholderLabel.attributedText
}
set {
IQ_PlaceholderLabel.attributedText = newValue
refreshPlaceholder()
}
}
@objc override open func layoutSubviews() {
super.layoutSubviews()
IQ_PlaceholderLabel.frame = placeholderExpectedFrame
}
@objc internal func refreshPlaceholder() {
if !text.isEmpty || !attributedText.string.isEmpty {
IQ_PlaceholderLabel.alpha = 0
} else {
IQ_PlaceholderLabel.alpha = 1
}
}
@objc override open var text: String! {
didSet {
refreshPlaceholder()
}
}
open override var attributedText: NSAttributedString! {
didSet {
refreshPlaceholder()
}
}
@objc override open var font: UIFont? {
didSet {
if let unwrappedFont = font {
IQ_PlaceholderLabel.font = unwrappedFont
} else {
IQ_PlaceholderLabel.font = UIFont.systemFont(ofSize: 12)
}
}
}
@objc override open var textAlignment: NSTextAlignment {
didSet {
IQ_PlaceholderLabel.textAlignment = textAlignment
}
}
@objc override weak open var delegate: UITextViewDelegate? {
get {
refreshPlaceholder()
return super.delegate
}
set {
super.delegate = newValue
}
}
@objc override open var intrinsicContentSize: CGSize {
guard !hasText else {
return super.intrinsicContentSize
}
var newSize = super.intrinsicContentSize
let placeholderInsets = self.placeholderInsets
newSize.height = placeholderExpectedFrame.height + placeholderInsets.top + placeholderInsets.bottom
return newSize
}
}
//#if swift(>=5.1)
//import SwiftUI
//
//struct IQTextViewSwiftUI: UIViewRepresentable {
// func makeUIView(context: Context) -> IQTextView {
// IQTextView(frame: .zero)
// }
//
// func updateUIView(_ view: IQTextView, context: Context) {
// }
//}
//
//struct IQTextViewSwiftUI_Preview: PreviewProvider {
// static var previews: some View {
// IQTextViewSwiftUI()
// }
//}
//
//#endif
//
//
// IQBarButtonItem.swift
// https://github.com/hackiftekhar/IQKeyboardManager
// Copyright (c) 2013-16 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 Foundation
open class IQBarButtonItem: UIBarButtonItem {
private static var _classInitialize: Void = classInitialize()
@objc public override init() {
_ = IQBarButtonItem._classInitialize
super.init()
}
@objc public required init?(coder aDecoder: NSCoder) {
_ = IQBarButtonItem._classInitialize
super.init(coder: aDecoder)
}
private class func classInitialize() {
let appearanceProxy = self.appearance()
#if swift(>=4.2)
let states: [UIControl.State]
#else
let states: [UIControlState]
#endif
states = [.normal, .highlighted, .disabled, .selected, .application, .reserved]
for state in states {
appearanceProxy.setBackgroundImage(nil, for: state, barMetrics: .default)
appearanceProxy.setBackgroundImage(nil, for: state, style: .done, barMetrics: .default)
appearanceProxy.setBackgroundImage(nil, for: state, style: .plain, barMetrics: .default)
appearanceProxy.setBackButtonBackgroundImage(nil, for: state, barMetrics: .default)
}
appearanceProxy.setTitlePositionAdjustment(UIOffset(), for: .default)
appearanceProxy.setBackgroundVerticalPositionAdjustment(0, for: .default)
appearanceProxy.setBackButtonBackgroundVerticalPositionAdjustment(0, for: .default)
}
@objc override open var tintColor: UIColor? {
didSet {
#if swift(>=4.2)
var textAttributes = [NSAttributedString.Key: Any]()
let foregroundColorKey = NSAttributedString.Key.foregroundColor
#elseif swift(>=4)
var textAttributes = [NSAttributedStringKey: Any]()
let foregroundColorKey = NSAttributedStringKey.foregroundColor
#else
var textAttributes = [String: Any]()
let foregroundColorKey = NSForegroundColorAttributeName
#endif
textAttributes[foregroundColorKey] = tintColor
#if swift(>=4)
if let attributes = titleTextAttributes(for: .normal) {
for (key, value) in attributes {
#if swift(>=4.2)
textAttributes[key] = value
#else
textAttributes[NSAttributedStringKey.init(key)] = value
#endif
}
}
#else
if let attributes = titleTextAttributes(for: .normal) {
textAttributes = attributes
}
#endif
setTitleTextAttributes(textAttributes, for: .normal)
}
}
/**
Boolean to know if it's a system item or custom item, we are having a limitation that we cannot override a designated initializer, so we are manually setting this property once in initialization
*/
@objc internal var isSystemItem = false
/**
Additional target & action to do get callback action. Note that setting custom target & selector doesn't affect native functionality, this is just an additional target to get a callback.
@param target Target object.
@param action Target Selector.
*/
@objc open func setTarget(_ target: AnyObject?, action: Selector?) {
if let target = target, let action = action {
invocation = IQInvocation(target, action)
} else {
invocation = nil
}
}
/**
Customized Invocation to be called when button is pressed. invocation is internally created using setTarget:action: method.
*/
@objc open var invocation: IQInvocation?
deinit {
target = nil
invocation = nil
}
}
//
// IQInvocation.swift
// https://github.com/hackiftekhar/IQKeyboardManager
// Copyright (c) 2013-16 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
@objc public class IQInvocation: NSObject {
@objc public weak var target: AnyObject?
@objc public var action: Selector
@objc public init(_ target: AnyObject, _ action: Selector) {
self.target = target
self.action = action
}
@objc public func invoke(from: Any) {
if let target = target {
UIApplication.shared.sendAction(action, to: target, from: from, for: UIEvent())
}
}
deinit {
target = nil
}
}
//
// IQPreviousNextView.swift
// https://github.com/hackiftekhar/IQKeyboardManager
// Copyright (c) 2013-16 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
@objc public class IQPreviousNextView: UIView {
}
//#if swift(>=5.1)
//import SwiftUI
//
//struct IQPreviousNextViewSwiftUI: UIViewRepresentable {
// func makeUIView(context: Context) -> IQPreviousNextView {
// IQPreviousNextView(frame: .zero)
// }
//
// func updateUIView(_ view: IQPreviousNextView, context: Context) {
// }
//}
//
//struct IQTextViewSwiftUI_Preview: PreviewProvider {
// static var previews: some View {
// IQPreviousNextViewSwiftUI()
// }
//}
//
//#endif
//
// IQTitleBarButtonItem.swift
// https://github.com/hackiftekhar/IQKeyboardManager
// Copyright (c) 2013-16 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
import UIKit
open class IQTitleBarButtonItem: IQBarButtonItem {
@objc open var titleFont: UIFont? {
didSet {
if let unwrappedFont = titleFont {
titleButton?.titleLabel?.font = unwrappedFont
} else {
titleButton?.titleLabel?.font = UIFont.systemFont(ofSize: 13)
}
}
}
@objc override open var title: String? {
didSet {
titleButton?.setTitle(title, for: .normal)
}
}
/**
titleColor to be used for displaying button text when displaying title (disabled state).
*/
@objc open var titleColor: UIColor? {
didSet {
if let color = titleColor {
titleButton?.setTitleColor(color, for: .disabled)
} else {
titleButton?.setTitleColor(UIColor.lightGray, for: .disabled)
}
}
}
/**
selectableTitleColor to be used for displaying button text when button is enabled.
*/
@objc open var selectableTitleColor: UIColor? {
didSet {
if let color = selectableTitleColor {
titleButton?.setTitleColor(color, for: .normal)
} else {
#if swift(>=5.1)
titleButton?.setTitleColor(UIColor.systemBlue, for: .normal)
#else
titleButton?.setTitleColor(UIColor(red: 0.0, green: 0.5, blue: 1.0, alpha: 1), for: .normal)
#endif
}
}
}
/**
Customized Invocation to be called on title button action. titleInvocation is internally created using setTitleTarget:action: method.
*/
@objc override open var invocation: IQInvocation? {
didSet {
if let target = invocation?.target, let action = invocation?.action {
self.isEnabled = true
titleButton?.isEnabled = true
titleButton?.addTarget(target, action: action, for: .touchUpInside)
} else {
self.isEnabled = false
titleButton?.isEnabled = false
titleButton?.removeTarget(nil, action: nil, for: .touchUpInside)
}
}
}
internal var titleButton: UIButton?
private var _titleView: UIView?
override init() {
super.init()
}
@objc public convenience init(title: String?) {
self.init(title: nil, style: .plain, target: nil, action: nil)
_titleView = UIView()
_titleView?.backgroundColor = UIColor.clear
titleButton = UIButton(type: .system)
titleButton?.isEnabled = false
titleButton?.titleLabel?.numberOfLines = 3
titleButton?.setTitleColor(UIColor.lightGray, for: .disabled)
#if swift(>=5.1)
titleButton?.setTitleColor(UIColor.systemBlue, for: .normal)
#else
titleButton?.setTitleColor(UIColor(red: 0.0, green: 0.5, blue: 1.0, alpha: 1), for: .normal)
#endif
titleButton?.backgroundColor = UIColor.clear
titleButton?.titleLabel?.textAlignment = .center
titleButton?.setTitle(title, for: .normal)
titleFont = UIFont.systemFont(ofSize: 13.0)
titleButton?.titleLabel?.font = self.titleFont
_titleView?.addSubview(titleButton!)
if #available(iOS 11, *) {
var layoutDefaultLowPriority: UILayoutPriority
var layoutDefaultHighPriority: UILayoutPriority
#if swift(>=4.0)
let layoutPriorityLowValue = UILayoutPriority.defaultLow.rawValue-1
let layoutPriorityHighValue = UILayoutPriority.defaultHigh.rawValue-1
layoutDefaultLowPriority = UILayoutPriority(rawValue: layoutPriorityLowValue)
layoutDefaultHighPriority = UILayoutPriority(rawValue: layoutPriorityHighValue)
#else
layoutDefaultLowPriority = UILayoutPriorityDefaultLow-1
layoutDefaultHighPriority = UILayoutPriorityDefaultHigh-1
#endif
_titleView?.translatesAutoresizingMaskIntoConstraints = false
_titleView?.setContentHuggingPriority(layoutDefaultLowPriority, for: .vertical)
_titleView?.setContentHuggingPriority(layoutDefaultLowPriority, for: .horizontal)
_titleView?.setContentCompressionResistancePriority(layoutDefaultHighPriority, for: .vertical)
_titleView?.setContentCompressionResistancePriority(layoutDefaultHighPriority, for: .horizontal)
titleButton?.translatesAutoresizingMaskIntoConstraints = false
titleButton?.setContentHuggingPriority(layoutDefaultLowPriority, for: .vertical)
titleButton?.setContentHuggingPriority(layoutDefaultLowPriority, for: .horizontal)
titleButton?.setContentCompressionResistancePriority(layoutDefaultHighPriority, for: .vertical)
titleButton?.setContentCompressionResistancePriority(layoutDefaultHighPriority, for: .horizontal)
let top = NSLayoutConstraint.init(item: titleButton!, attribute: .top, relatedBy: .equal, toItem: _titleView, attribute: .top, multiplier: 1, constant: 0)
let bottom = NSLayoutConstraint.init(item: titleButton!, attribute: .bottom, relatedBy: .equal, toItem: _titleView, attribute: .bottom, multiplier: 1, constant: 0)
let leading = NSLayoutConstraint.init(item: titleButton!, attribute: .leading, relatedBy: .equal, toItem: _titleView, attribute: .leading, multiplier: 1, constant: 0)
let trailing = NSLayoutConstraint.init(item: titleButton!, attribute: .trailing, relatedBy: .equal, toItem: _titleView, attribute: .trailing, multiplier: 1, constant: 0)
_titleView?.addConstraints([top, bottom, leading, trailing])
} else {
_titleView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
titleButton?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
customView = _titleView
}
@objc required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
deinit {
customView = nil
titleButton?.removeTarget(nil, action: nil, for: .touchUpInside)
_titleView = nil
titleButton = nil
}
}
//
// IQToolbar.swift
// https://github.com/hackiftekhar/IQKeyboardManager
// Copyright (c) 2013-16 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
/** @abstract IQToolbar for IQKeyboardManager. */
open class IQToolbar: UIToolbar, UIInputViewAudioFeedback {
private static var _classInitialize: Void = classInitialize()
private class func classInitialize() {
let appearanceProxy = self.appearance()
appearanceProxy.barTintColor = nil
let positions: [UIBarPosition] = [.any, .bottom, .top, .topAttached]
for position in positions {
appearanceProxy.setBackgroundImage(nil, forToolbarPosition: position, barMetrics: .default)
appearanceProxy.setShadowImage(nil, forToolbarPosition: .any)
}
//Background color
appearanceProxy.backgroundColor = nil
}
/**
Previous bar button of toolbar.
*/
private var privatePreviousBarButton: IQBarButtonItem?
@objc open var previousBarButton: IQBarButtonItem {
get {
if privatePreviousBarButton == nil {
privatePreviousBarButton = IQBarButtonItem(image: nil, style: .plain, target: nil, action: nil)
}
return privatePreviousBarButton!
}
set (newValue) {
privatePreviousBarButton = newValue
}
}
/**
Next bar button of toolbar.
*/
private var privateNextBarButton: IQBarButtonItem?
@objc open var nextBarButton: IQBarButtonItem {
get {
if privateNextBarButton == nil {
privateNextBarButton = IQBarButtonItem(image: nil, style: .plain, target: nil, action: nil)
}
return privateNextBarButton!
}
set (newValue) {
privateNextBarButton = newValue
}
}
/**
Title bar button of toolbar.
*/
private var privateTitleBarButton: IQTitleBarButtonItem?
@objc open var titleBarButton: IQTitleBarButtonItem {
get {
if privateTitleBarButton == nil {
privateTitleBarButton = IQTitleBarButtonItem(title: nil)
privateTitleBarButton?.accessibilityLabel = "Title"
}
return privateTitleBarButton!
}
set (newValue) {
privateTitleBarButton = newValue
}
}
/**
Done bar button of toolbar.
*/
private var privateDoneBarButton: IQBarButtonItem?
@objc open var doneBarButton: IQBarButtonItem {
get {
if privateDoneBarButton == nil {
privateDoneBarButton = IQBarButtonItem(title: nil, style: .done, target: nil, action: nil)
}
return privateDoneBarButton!
}
set (newValue) {
privateDoneBarButton = newValue
}
}
/**
Fixed space bar button of toolbar.
*/
private var privateFixedSpaceBarButton: IQBarButtonItem?
@objc open var fixedSpaceBarButton: IQBarButtonItem {
get {
if privateFixedSpaceBarButton == nil {
privateFixedSpaceBarButton = IQBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
}
privateFixedSpaceBarButton!.isSystemItem = true
if #available(iOS 10, *) {
privateFixedSpaceBarButton!.width = 6
} else {
privateFixedSpaceBarButton!.width = 20
}
return privateFixedSpaceBarButton!
}
set (newValue) {
privateFixedSpaceBarButton = newValue
}
}
override init(frame: CGRect) {
_ = IQToolbar._classInitialize
super.init(frame: frame)
sizeToFit()
autoresizingMask = .flexibleWidth
self.isTranslucent = true
}
@objc required public init?(coder aDecoder: NSCoder) {
_ = IQToolbar._classInitialize
super.init(coder: aDecoder)
sizeToFit()
autoresizingMask = .flexibleWidth
self.isTranslucent = true
}
@objc override open func sizeThatFits(_ size: CGSize) -> CGSize {
var sizeThatFit = super.sizeThatFits(size)
sizeThatFit.height = 44
return sizeThatFit
}
@objc override open var tintColor: UIColor! {
didSet {
if let unwrappedItems = items {
for item in unwrappedItems {
item.tintColor = tintColor
}
}
}
}
@objc override open func layoutSubviews() {
super.layoutSubviews()
if #available(iOS 11, *) {
return
} else if let customTitleView = titleBarButton.customView {
var leftRect = CGRect.null
var rightRect = CGRect.null
var isTitleBarButtonFound = false
let sortedSubviews = self.subviews.sorted(by: { (view1: UIView, view2: UIView) -> Bool in
if view1.frame.minX != view2.frame.minX {
return view1.frame.minX < view2.frame.minX
} else {
return view1.frame.minY < view2.frame.minY
}
})
for barButtonItemView in sortedSubviews {
if isTitleBarButtonFound == true {
rightRect = barButtonItemView.frame
break
} else if barButtonItemView === customTitleView {
isTitleBarButtonFound = true
//If it's UIToolbarButton or UIToolbarTextButton (which actually UIBarButtonItem)
} else if barButtonItemView.isKind(of: UIControl.self) == true {
leftRect = barButtonItemView.frame
}
}
let titleMargin: CGFloat = 16
let maxWidth: CGFloat = self.frame.width - titleMargin*2 - (leftRect.isNull ? 0 : leftRect.maxX) - (rightRect.isNull ? 0 : self.frame.width - rightRect.minX)
let maxHeight = self.frame.height
let sizeThatFits = customTitleView.sizeThatFits(CGSize(width: maxWidth, height: maxHeight))
var titleRect: CGRect
if sizeThatFits.width > 0 && sizeThatFits.height > 0 {
let width = min(sizeThatFits.width, maxWidth)
let height = min(sizeThatFits.height, maxHeight)
var xPosition: CGFloat
if leftRect.isNull == false {
xPosition = titleMargin + leftRect.maxX + ((maxWidth - width)/2)
} else {
xPosition = titleMargin
}
let yPosition = (maxHeight - height)/2
titleRect = CGRect(x: xPosition, y: yPosition, width: width, height: height)
} else {
var xPosition: CGFloat
if leftRect.isNull == false {
xPosition = titleMargin + leftRect.maxX
} else {
xPosition = titleMargin
}
let width: CGFloat = self.frame.width - titleMargin*2 - (leftRect.isNull ? 0 : leftRect.maxX) - (rightRect.isNull ? 0 : self.frame.width - rightRect.minX)
titleRect = CGRect(x: xPosition, y: 0, width: width, height: maxHeight)
}
customTitleView.frame = titleRect
}
}
@objc open var enableInputClicksWhenVisible: Bool {
return true
}
deinit {
items = nil
privatePreviousBarButton = nil
privateNextBarButton = nil
privateTitleBarButton = nil
privateDoneBarButton = nil
privateFixedSpaceBarButton = nil
}
}
MIT License
Copyright (c) 2013-2017 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.
<p align="center">
<img src="https://raw.githubusercontent.com/hackiftekhar/IQKeyboardManager/master/Demo/Resources/icon.png" alt="Icon"/>
</p>
<H1 align="center">IQKeyboardManager</H1>
<p align="center">
<img src="https://img.shields.io/github/license/hackiftekhar/IQKeyboardManager.svg"
alt="GitHub license"/>
[![Build Status](https://travis-ci.org/hackiftekhar/IQKeyboardManager.svg)](https://travis-ci.org/hackiftekhar/IQKeyboardManager)
While developing iOS apps, we often run into issues where the iPhone keyboard slides up and covers the `UITextField/UITextView`. `IQKeyboardManager` allows you to prevent this issue of keyboard sliding up and covering `UITextField/UITextView` without needing you to write any code or make any additional setup. To use `IQKeyboardManager` you simply need to add source files to your project.
#### Key Features
1) `**CODELESS**, Zero Lines of Code`
2) `Works Automatically`
3) `No More UIScrollView`
4) `No More Subclasses`
5) `No More Manual Work`
6) `No More #imports`
`IQKeyboardManager` works on all orientations, and with the toolbar. It also has nice optional features allowing you to customize the distance from the text field, behaviour of previous, next and done buttons in the keyboard toolbar, play sound when the user navigates through the form and more.
## Screenshot
[![IQKeyboardManager](https://raw.githubusercontent.com/hackiftekhar/IQKeyboardManager/v3.3.0/Screenshot/IQKeyboardManagerScreenshot.png)](http://youtu.be/6nhLw6hju2A)
[![Settings](https://raw.githubusercontent.com/hackiftekhar/IQKeyboardManager/v3.3.0/Screenshot/IQKeyboardManagerSettings.png)](http://youtu.be/6nhLw6hju2A)
## GIF animation
[![IQKeyboardManager](https://raw.githubusercontent.com/hackiftekhar/IQKeyboardManager/v3.3.0/Screenshot/IQKeyboardManager.gif)](http://youtu.be/6nhLw6hju2A)
## Video
<a href="http://youtu.be/WAYc2Qj-OQg" target="_blank"><img src="http://img.youtube.com/vi/WAYc2Qj-OQg/0.jpg"
alt="IQKeyboardManager Demo Video" width="480" height="360" border="10" /></a>
## Tutorial video by @rebeloper ([#1135](https://github.com/hackiftekhar/IQKeyboardManager/issues/1135))
@rebeloper demonstrated two videos on how to implement **IQKeyboardManager** at it's core:
<a href="https://www.youtube.com/playlist?list=PL_csAAO9PQ8aTL87XnueOXi3RpWE2m_8v" target="_blank"><img src="https://raw.githubusercontent.com/hackiftekhar/IQKeyboardManager/master/Screenshot/ThirdPartyYoutubeTutorial.jpg"
alt="Youtube Tutorial Playlist"/></a>
https://www.youtube.com/playlist?list=PL_csAAO9PQ8aTL87XnueOXi3RpWE2m_8v
## Warning
- **If you're planning to build SDK/library/framework and want to handle UITextField/UITextView with IQKeyboardManager then you're totally going the wrong way.** I would never suggest to add **IQKeyboardManager** as **dependency/adding/shipping** with any third-party library. Instead of adding **IQKeyboardManager** you should implement your own solution to achieve same kind of results. **IQKeyboardManager** is totally designed for projects to help developers for their convenience, it's not designed for **adding/dependency/shipping** with any **third-party library**, because **doing this could block adoption by other developers for their projects as well (who are not using IQKeyboardManager and have implemented their custom solution to handle UITextField/UITextView in the project).**
- If **IQKeyboardManager** conflicts with other **third-party library**, then it's **developer responsibility** to **enable/disable IQKeyboardManager** when **presenting/dismissing** third-party library UI. Third-party libraries are not responsible to handle IQKeyboardManager.
## Requirements
[![Platform iOS](https://img.shields.io/badge/Platform-iOS-blue.svg?style=fla)]()
| | Language | Minimum iOS Target | Minimum Xcode Version |
|------------------------|----------|--------------------|-----------------------|
| IQKeyboardManager | Obj-C | iOS 8.0 | Xcode 9 |
| IQKeyboardManagerSwift | Swift | iOS 8.0 | Xcode 9 |
| Demo Project | | | Xcode 11 |
#### Swift versions support
| Swift | Xcode | IQKeyboardManagerSwift |
|-------------------|-------|------------------------|
| 5.1, 5.0, 4.2, 4.0, 3.2, 3.0| 11 | >= 6.5.0 |
| 5.0,4.2, 4.0, 3.2, 3.0| 10.2 | >= 6.2.1 |
| 4.2, 4.0, 3.2, 3.0| 10.0 | >= 6.0.4 |
| 4.0, 3.2, 3.0 | 9.0 | 5.0.0 |
Installation
==========================
#### Installation with CocoaPods
[![CocoaPods](https://img.shields.io/cocoapods/v/IQKeyboardManager.svg)](http://cocoadocs.org/docsets/IQKeyboardManager)
***IQKeyboardManager (Objective-C):*** IQKeyboardManager is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following line to your Podfile: ([#9](https://github.com/hackiftekhar/IQKeyboardManager/issues/9))
```ruby
pod 'IQKeyboardManager' #iOS8 and later
```
***IQKeyboardManager (Swift):*** IQKeyboardManagerSwift is available through [CocoaPods](http://cocoapods.org). To install
it, simply add the following line to your Podfile: ([#236](https://github.com/hackiftekhar/IQKeyboardManager/issues/236))
*Swift 5.1, 5.0, 4.2, 4.0, 3.2, 3.0 (Xcode 11)*
```ruby
pod 'IQKeyboardManagerSwift'
```
*Or you can choose the version you need based on Swift support table from [Requirements](README.md#requirements)*
```ruby
pod 'IQKeyboardManagerSwift', '6.3.0'
```
In AppDelegate.swift, just import IQKeyboardManagerSwift framework and enable IQKeyboardManager.
```swift
import IQKeyboardManagerSwift
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
IQKeyboardManager.shared.enable = true
return true
}
}
```
#### Installation with Carthage
[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
You can install Carthage with [Homebrew](http://brew.sh/) using the following command:
```bash
$ brew update
$ brew install carthage
```
To integrate `IQKeyboardManger` or `IQKeyboardManagerSwift` into your Xcode project using Carthage, add the following line to your `Cartfile`:
```ogdl
github "hackiftekhar/IQKeyboardManager"
```
Run `carthage` to build the frameworks and drag the appropriate framework (`IQKeyboardManager.framework` or `IQKeyboardManagerSwift.framework`) into your Xcode project based on your need. Make sure to add only one framework and not both.
#### Installation with Source Code
[![Github tag](https://img.shields.io/github/tag/hackiftekhar/iqkeyboardmanager.svg)]()
***IQKeyboardManager (Objective-C):*** Just ***drag and drop*** `IQKeyboardManager` directory from demo project to your project. That's it.
***IQKeyboardManager (Swift):*** ***Drag and drop*** `IQKeyboardManagerSwift` directory from demo project to your project
In AppDelegate.swift, just enable IQKeyboardManager.
```swift
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
IQKeyboardManager.shared.enable = true
return true
}
}
```
#### Installation with Swift Package Manager
[Swift Package Manager(SPM)](https://swift.org/package-manager/) is Apple's dependency manager tool. It is now supported in Xcode 11. So it can be used in all appleOS types of projects. It can be used alongside other tools like CocoaPods and Carthage as well.
To install IQKeyboardManager package into your packages, add a reference to IQKeyboardManager and a targeting release version in the dependencies section in `Package.swift` file:
```swift
import PackageDescription
let package = Package(
name: "YOUR_PROJECT_NAME",
products: [],
dependencies: [
.package(url: "https://github.com/hackiftekhar/IQKeyboardManager.git", from: "6.5.0")
]
)
```
To install IQKeyboardManager package via Xcode
* Go to File -> Swift Packages -> Add Package Dependency...
* Then search for https://github.com/hackiftekhar/IQKeyboardManager.git
* And choose the version you want
Migration Guide
==========================
- [IQKeyboardManager 6.0.0 Migration Guide](https://github.com/hackiftekhar/IQKeyboardManager/wiki/IQKeyboardManager-6.0.0-Migration-Guide)
Other Links
==========================
- [Known Issues](https://github.com/hackiftekhar/IQKeyboardManager/wiki/Known-Issues)
- [Manual Management Tweaks](https://github.com/hackiftekhar/IQKeyboardManager/wiki/Manual-Management)
- [Properties and functions usage](https://github.com/hackiftekhar/IQKeyboardManager/wiki/Properties-&-Functions)
## Flow Diagram
[![IQKeyboardManager CFD](https://raw.githubusercontent.com/hackiftekhar/IQKeyboardManager/master/Screenshot/IQKeyboardManagerFlowDiagram.jpg)](https://raw.githubusercontent.com/hackiftekhar/IQKeyboardManager/master/Screenshot/IQKeyboardManagerFlowDiagram.jpg)
If you would like to see detailed Flow diagram then check [Detailed Flow Diagram](https://raw.githubusercontent.com/hackiftekhar/IQKeyboardManager/v3.3.0/Screenshot/IQKeyboardManagerCFD.jpg).
LICENSE
---
Distributed under the MIT License.
Contributions
---
Any contribution is more than welcome! You can contribute through pull requests and issues on GitHub.
Author
---
If you wish to contact me, email at: hack.iftekhar@gmail.com
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForAnalyzing = "YES"
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B490E7485944099E16C9CBD79119D1D4"
BuildableName = "IQKeyboardManagerSwift.framework"
BlueprintName = "IQKeyboardManagerSwift"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
......@@ -9,6 +9,11 @@
<key>isShown</key>
<false/>
</dict>
<key>IQKeyboardManagerSwift.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
</dict>
<key>MBProgressHUD.xcscheme</key>
<dict>
<key>isShown</key>
......
<?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>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>6.5.6</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
#import <Foundation/Foundation.h>
@interface PodsDummy_IQKeyboardManagerSwift : NSObject
@end
@implementation PodsDummy_IQKeyboardManagerSwift
@end
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
FOUNDATION_EXPORT double IQKeyboardManagerSwiftVersionNumber;
FOUNDATION_EXPORT const unsigned char IQKeyboardManagerSwiftVersionString[];
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
OTHER_LDFLAGS = $(inherited) -framework "CoreGraphics" -framework "Foundation" -framework "QuartzCore" -framework "UIKit"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/IQKeyboardManagerSwift
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
framework module IQKeyboardManagerSwift {
umbrella header "IQKeyboardManagerSwift-umbrella.h"
export *
module * { export * }
}
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
OTHER_LDFLAGS = $(inherited) -framework "CoreGraphics" -framework "Foundation" -framework "QuartzCore" -framework "UIKit"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/IQKeyboardManagerSwift
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
......@@ -24,6 +24,31 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## IQKeyboardManagerSwift
MIT License
Copyright (c) 2013-2017 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.
## MBProgressHUD
Copyright © 2009-2020 Matej Bukovinski
......
......@@ -41,6 +41,37 @@ THE SOFTWARE.
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>MIT License
Copyright (c) 2013-2017 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.
</string>
<key>License</key>
<string>MIT</string>
<key>Title</key>
<string>IQKeyboardManagerSwift</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright © 2009-2020 Matej Bukovinski
......
${PODS_ROOT}/Target Support Files/Pods-ShorthandMaster/Pods-ShorthandMaster-frameworks.sh
${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework
${BUILT_PRODUCTS_DIR}/IQKeyboardManagerSwift/IQKeyboardManagerSwift.framework
${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework
${BUILT_PRODUCTS_DIR}/Masonry/Masonry.framework
${BUILT_PRODUCTS_DIR}/PDFGenerator/PDFGenerator.framework
......
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/IQKeyboardManagerSwift.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MBProgressHUD.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Masonry.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PDFGenerator.framework
......
${PODS_ROOT}/Target Support Files/Pods-ShorthandMaster/Pods-ShorthandMaster-frameworks.sh
${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework
${BUILT_PRODUCTS_DIR}/IQKeyboardManagerSwift/IQKeyboardManagerSwift.framework
${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework
${BUILT_PRODUCTS_DIR}/Masonry/Masonry.framework
${BUILT_PRODUCTS_DIR}/PDFGenerator/PDFGenerator.framework
......
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/IQKeyboardManagerSwift.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MBProgressHUD.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Masonry.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PDFGenerator.framework
......
......@@ -198,6 +198,7 @@ fi
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework"
install_framework "${BUILT_PRODUCTS_DIR}/IQKeyboardManagerSwift/IQKeyboardManagerSwift.framework"
install_framework "${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework"
install_framework "${BUILT_PRODUCTS_DIR}/Masonry/Masonry.framework"
install_framework "${BUILT_PRODUCTS_DIR}/PDFGenerator/PDFGenerator.framework"
......@@ -207,6 +208,7 @@ if [[ "$CONFIGURATION" == "Debug" ]]; then
fi
if [[ "$CONFIGURATION" == "Release" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework"
install_framework "${BUILT_PRODUCTS_DIR}/IQKeyboardManagerSwift/IQKeyboardManagerSwift.framework"
install_framework "${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework"
install_framework "${BUILT_PRODUCTS_DIR}/Masonry/Masonry.framework"
install_framework "${BUILT_PRODUCTS_DIR}/PDFGenerator/PDFGenerator.framework"
......
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/PDFGenerator" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyStoreKit" "${PODS_ROOT}/UMCCommon"
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/PDFGenerator" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyStoreKit" "${PODS_ROOT}/UMCCommon"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PDFGenerator/PDFGenerator.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON/SwiftyJSON.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyStoreKit/SwiftyStoreKit.framework/Headers"
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift/IQKeyboardManagerSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PDFGenerator/PDFGenerator.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON/SwiftyJSON.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyStoreKit/SwiftyStoreKit.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_LDFLAGS = $(inherited) -ObjC -l"sqlite3" -l"z" -framework "Alamofire" -framework "CoreGraphics" -framework "CoreTelephony" -framework "Foundation" -framework "MBProgressHUD" -framework "Masonry" -framework "PDFGenerator" -framework "QuartzCore" -framework "SnapKit" -framework "SwiftyJSON" -framework "SwiftyStoreKit" -framework "SystemConfiguration" -framework "UIKit" -framework "UMCommon" -framework "WebKit"
OTHER_LDFLAGS = $(inherited) -ObjC -l"sqlite3" -l"z" -framework "Alamofire" -framework "CoreGraphics" -framework "CoreTelephony" -framework "Foundation" -framework "IQKeyboardManagerSwift" -framework "MBProgressHUD" -framework "Masonry" -framework "PDFGenerator" -framework "QuartzCore" -framework "SnapKit" -framework "SwiftyJSON" -framework "SwiftyStoreKit" -framework "SystemConfiguration" -framework "UIKit" -framework "UMCommon" -framework "WebKit"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
......
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/PDFGenerator" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyStoreKit" "${PODS_ROOT}/UMCCommon"
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/PDFGenerator" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyStoreKit" "${PODS_ROOT}/UMCCommon"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PDFGenerator/PDFGenerator.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON/SwiftyJSON.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyStoreKit/SwiftyStoreKit.framework/Headers"
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift/IQKeyboardManagerSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PDFGenerator/PDFGenerator.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON/SwiftyJSON.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyStoreKit/SwiftyStoreKit.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_LDFLAGS = $(inherited) -ObjC -l"sqlite3" -l"z" -framework "Alamofire" -framework "CoreGraphics" -framework "CoreTelephony" -framework "Foundation" -framework "MBProgressHUD" -framework "Masonry" -framework "PDFGenerator" -framework "QuartzCore" -framework "SnapKit" -framework "SwiftyJSON" -framework "SwiftyStoreKit" -framework "SystemConfiguration" -framework "UIKit" -framework "UMCommon" -framework "WebKit"
OTHER_LDFLAGS = $(inherited) -ObjC -l"sqlite3" -l"z" -framework "Alamofire" -framework "CoreGraphics" -framework "CoreTelephony" -framework "Foundation" -framework "IQKeyboardManagerSwift" -framework "MBProgressHUD" -framework "Masonry" -framework "PDFGenerator" -framework "QuartzCore" -framework "SnapKit" -framework "SwiftyJSON" -framework "SwiftyStoreKit" -framework "SystemConfiguration" -framework "UIKit" -framework "UMCommon" -framework "WebKit"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
......
This diff is collapsed.
......@@ -7,6 +7,7 @@
//
import UIKit
import IQKeyboardManagerSwift
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
......@@ -26,15 +27,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
MobClick.event("app_start")
SHUserAccountManager.shared.logCollection(with: .appStart)
// SHUserAccountManager.shared.getNovelInfo { (json) in
// }
// IQKeyboardManager.shared.enable = true
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = SHBaseTabBarController()
// window?.rootViewController = UIStoryboard.init(name: "Login", bundle: nil).instantiateViewController(withIdentifier: "SHSmsLoginViewController")
window?.makeKeyAndVisible()
return true
......
......@@ -5,12 +5,12 @@
"scale" : "1x"
},
{
"filename" : "Fill 1@2x.png",
"filename" : "编组 5@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Fill 1@3x.png",
"filename" : "编组 5@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
......
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "矩形备份 2@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "矩形备份 2@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "设置备份@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "设置备份@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
......@@ -5,12 +5,12 @@
"scale" : "1x"
},
{
"filename" : "右上角@2x.png",
"filename" : "笔记@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "右上角@3x.png",
"filename" : "笔记@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
......
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "22) Icons/Line/Search@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "22) Icons/Line/Search@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "文档中心@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "文档中心@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "编组@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "编组@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "编组@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "编组@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "更多@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "更多@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "编组@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "编组@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "编组@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "编组@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "关闭@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "关闭@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "编组@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "编组@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "上传@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "上传@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "椭圆形@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "椭圆形@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "编组@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "编组@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "语音@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "语音@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
......@@ -89,6 +89,16 @@ struct CRUserDefaults {
}
}
// recordList
static var sortType: NSInteger? {
set {
UserDefaults.standard.set(newValue, forKey: "com.app.sortType")
}
get {
return UserDefaults.standard.integer(forKey: "com.app.sortType")
}
}
static var isFirstExportGuide: Bool {
set {
UserDefaults.standard.set(newValue, forKey: "com.app.isFirstExportGuide")
......
......@@ -189,6 +189,29 @@ extension Date {
return result
}
static func getShortTimeByStamp_record(timestamp: Int64) -> String {
let compareDate = NSDate(timeIntervalSince1970: TimeInterval(timestamp))
var timeInterval: Double = compareDate.timeIntervalSinceNow
timeInterval = -timeInterval;
var temp: Double = 0;
var result = ""
if (timeInterval < 60) {
result = "刚刚"
} else if((timeInterval / 60) < 60){
temp = timeInterval / 60
result = "\(Int(temp))分钟前"
} else if((timeInterval / 60 / 60) < 24){
temp = timeInterval / 60 / 60
result = "\(Int(temp))小时前"
} else if((timeInterval / 60 / 60) < 48){
result = "昨天"
} else {
result = Date.getTimeByStamp(timestamp: timestamp, format: "yyyy-MM-dd")
}
return result
}
}
......
//
// NSObject+Extension.swift
// ShorthandMaster
//
// Created by 明津李 on 2020/9/23.
// Copyright © 2020 明津李. All rights reserved.
//
import UIKit
extension NSObject {
func setValuesForKeys(_ keyedValues: [String : Any]) {
for (key, value) in keyedValues {
setCustomValue(value, forKey: key)
}
}
private func setCustomValue(_ value: Any?, forKey key: String) {
if let dict = value as? [String : Any] {
if let objClass = getClassWith(key) as? NSObject.Type {
let model = objClass.init()
model.setValuesForKeys(dict)
setValue(model, forKey: key)
return
}
} else if let array = value as? [[String : Any]] {
if let objClass = getClassWith(key, isArray: true) as? NSObject.Type {
var resultArray = [NSObject]()
for dict in array {
let model = objClass.init()
model.setValuesForKeys(dict)
resultArray.append(model)
}
setValue(resultArray, forKey: key)
return
}
}
setValue(value, forKey: key)
}
private func getClassWith(_ key: String, isArray: Bool = false) -> AnyClass? {
let mirror = Mirror(reflecting: self)
let children = mirror.children.filter { (child) -> Bool in
return child.label == key
}
if let value = children.first?.value {
var valueType = "\(Mirror(reflecting: value).subjectType)"
if isArray {
valueType = valueType.replacingOccurrences(of: "Array<", with: "")
valueType = valueType.replacingOccurrences(of: ">", with: "")
}
if let projectName = Bundle.main.infoDictionary?["CFBundleName"] as? String {
return NSClassFromString(projectName + "." + valueType)
}
}
return nil
}
}
func getDataArrayWith<T: NSObject>(array: [[String : Any]]) -> [T] {
var resultArray = [T]()
for dict in array {
let model = T()
model.setValuesForKeys(dict)
resultArray.append(model)
}
return resultArray
}
func getDataDictWith<T: NSObject>(dict: [String : Any]) -> T {
let model = T()
model.setValuesForKeys(dict)
return model
}
func getDictWith(obj: Any) -> [String : Any] {
var dict = [String : Any]()
let mirror = Mirror(reflecting: obj)
for item in mirror.children {
guard let key = item.label else {
continue
}
let value = item.value
if let array = value as? [Any] {
dict.updateValue(getArrayWith(array: array), forKey: key)
} else if isModelWith(value) {
dict.updateValue(getDictWith(obj: value), forKey: key)
} else {
dict.updateValue(value, forKey: key)
}
}
return dict
}
func getArrayWith(array: [Any]) -> [Any] {
var resultArray = [Any]()
guard let first = array.first else {
return array
}
if isModelWith(first) {
for obj in array {
let dict = getDictWith(obj: obj)
resultArray.append(dict)
}
return resultArray
} else {
return array
}
}
func isModelWith(_ value: Any) -> Bool {
let valueType = "\(Mirror(reflecting: value).subjectType)"
if let projectName = Bundle.main.infoDictionary?["CFBundleName"] as? String {
return NSClassFromString(projectName + "." + valueType) != nil
}
return false
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment