Initial commit

This commit is contained in:
lianxiang
2018-08-22 11:15:52 +08:00
parent d98e20881f
commit 249bf6864e
491 changed files with 68665 additions and 7 deletions
@@ -0,0 +1,47 @@
//
// IQNSArray+Sort.h
// 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/NSArray.h>
@class UIView;
/**
UIView.subviews sorting category.
*/
@interface NSArray (IQ_NSArray_Sort)
///--------------
/// @name Sorting
///--------------
/**
Returns the array by sorting the UIView's by their tag property.
*/
@property (nonatomic, readonly, copy) NSArray<__kindof UIView*> * _Nonnull sortedArrayByTag;
/**
Returns the array by sorting the UIView's by their tag property.
*/
@property (nonatomic, readonly, copy) NSArray<__kindof UIView*> * _Nonnull sortedArrayByPosition;
@end
@@ -0,0 +1,71 @@
//
// IQNSArray+Sort.m
// 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 "IQNSArray+Sort.h"
#import "IQUIView+Hierarchy.h"
#import <UIKit/UIView.h>
@implementation NSArray (IQ_NSArray_Sort)
- (NSArray<UIView*>*)sortedArrayByTag
{
return [self sortedArrayUsingComparator:^NSComparisonResult(UIView *view1, UIView *view2) {
if ([view1 respondsToSelector:@selector(tag)] && [view2 respondsToSelector:@selector(tag)])
{
if ([view1 tag] < [view2 tag]) return NSOrderedAscending;
else if ([view1 tag] > [view2 tag]) return NSOrderedDescending;
else return NSOrderedSame;
}
else
return NSOrderedSame;
}];
}
- (NSArray<UIView*>*)sortedArrayByPosition
{
return [self sortedArrayUsingComparator:^NSComparisonResult(UIView *view1, UIView *view2) {
CGFloat x1 = CGRectGetMinX(view1.frame);
CGFloat y1 = CGRectGetMinY(view1.frame);
CGFloat x2 = CGRectGetMinX(view2.frame);
CGFloat y2 = CGRectGetMinY(view2.frame);
if (y1 < y2) return NSOrderedAscending;
else if (y1 > y2) return NSOrderedDescending;
//Else both y are same so checking for x positions
else if (x1 < x2) return NSOrderedAscending;
else if (x1 > x2) return NSOrderedDescending;
else return NSOrderedSame;
}];
}
@end
@@ -0,0 +1,40 @@
//
// IQUIScrollView+Additions.h
// 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/UIScrollView.h>
@interface UIScrollView (Additions)
/**
If YES, then scrollview will ignore scrolling (simply not scroll it) for adjusting textfield position. Default is NO.
*/
@property(nonatomic, assign) BOOL shouldIgnoreScrollingAdjustment;
/**
Restore scrollViewContentOffset when resigning from scrollView. Default is NO.
*/
@property(nonatomic, assign) BOOL shouldRestoreScrollViewContentOffset;
@end
@@ -0,0 +1,53 @@
//
// IQUIScrollView+Additions.m
// 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 "IQUIScrollView+Additions.h"
#import <objc/runtime.h>
@implementation UIScrollView (Additions)
-(void)setShouldIgnoreScrollingAdjustment:(BOOL)shouldIgnoreScrollingAdjustment
{
objc_setAssociatedObject(self, @selector(shouldIgnoreScrollingAdjustment), @(shouldIgnoreScrollingAdjustment), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(BOOL)shouldIgnoreScrollingAdjustment
{
NSNumber *shouldIgnoreScrollingAdjustment = objc_getAssociatedObject(self, @selector(shouldIgnoreScrollingAdjustment));
return [shouldIgnoreScrollingAdjustment boolValue];
}
-(void)setShouldRestoreScrollViewContentOffset:(BOOL)shouldRestoreScrollViewContentOffset
{
objc_setAssociatedObject(self, @selector(shouldRestoreScrollViewContentOffset), @(shouldRestoreScrollViewContentOffset), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(BOOL)shouldRestoreScrollViewContentOffset
{
NSNumber *shouldRestoreScrollViewContentOffset = objc_getAssociatedObject(self, @selector(shouldRestoreScrollViewContentOffset));
return [shouldRestoreScrollViewContentOffset boolValue];
}
@end
@@ -0,0 +1,62 @@
//
// IQUITextFieldView+Additions.h
// 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/UIView.h>
#import "IQKeyboardManagerConstants.h"
/**
UIView category for managing UITextField/UITextView
*/
@interface UIView (Additions)
/**
To set customized distance from keyboard for textField/textView. Can't be less than zero
*/
@property(nonatomic, assign) CGFloat keyboardDistanceFromTextField;
/**
If shouldIgnoreSwitchingByNextPrevious is YES then library will ignore this textField/textView while moving to other textField/textView using keyboard toolbar next previous buttons. Default is NO
*/
@property(nonatomic, assign) BOOL ignoreSwitchingByNextPrevious;
///**
// Override Enable/disable managing distance between keyboard and textField behaviour for this particular textField.
// */
//@property(nonatomic, assign) IQEnableMode enableMode;
/**
Override resigns Keyboard on touching outside of UITextField/View behaviour for this particular textField.
*/
@property(nonatomic, assign) IQEnableMode shouldResignOnTouchOutsideMode;
@end
///-------------------------------------------
/// @name Custom KeyboardDistanceFromTextField
///-------------------------------------------
/**
Uses default keyboard distance for textField.
*/
extern CGFloat const kIQUseDefaultKeyboardDistance;
@@ -0,0 +1,90 @@
//
// IQUITextFieldView+Additions.m
// 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 "IQUITextFieldView+Additions.h"
#import <objc/runtime.h>
@implementation UIView (Additions)
-(void)setKeyboardDistanceFromTextField:(CGFloat)keyboardDistanceFromTextField
{
//Can't be less than zero. Minimum is zero.
keyboardDistanceFromTextField = MAX(keyboardDistanceFromTextField, 0);
objc_setAssociatedObject(self, @selector(keyboardDistanceFromTextField), @(keyboardDistanceFromTextField), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(CGFloat)keyboardDistanceFromTextField
{
NSNumber *keyboardDistanceFromTextField = objc_getAssociatedObject(self, @selector(keyboardDistanceFromTextField));
return (keyboardDistanceFromTextField)?[keyboardDistanceFromTextField floatValue]:kIQUseDefaultKeyboardDistance;
}
-(void)setIgnoreSwitchingByNextPrevious:(BOOL)ignoreSwitchingByNextPrevious
{
objc_setAssociatedObject(self, @selector(ignoreSwitchingByNextPrevious), @(ignoreSwitchingByNextPrevious), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(BOOL)ignoreSwitchingByNextPrevious
{
NSNumber *ignoreSwitchingByNextPrevious = objc_getAssociatedObject(self, @selector(ignoreSwitchingByNextPrevious));
return [ignoreSwitchingByNextPrevious boolValue];
}
//-(void)setEnableMode:(IQEnableMode)enableMode
//{
// objc_setAssociatedObject(self, @selector(enableMode), @(enableMode), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
//}
//
//-(IQEnableMode)enableMode
//{
// NSNumber *enableMode = objc_getAssociatedObject(self, @selector(enableMode));
//
// return [enableMode unsignedIntegerValue];
//}
-(void)setShouldResignOnTouchOutsideMode:(IQEnableMode)shouldResignOnTouchOutsideMode
{
objc_setAssociatedObject(self, @selector(shouldResignOnTouchOutsideMode), @(shouldResignOnTouchOutsideMode), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(IQEnableMode)shouldResignOnTouchOutsideMode
{
NSNumber *shouldResignOnTouchOutsideMode = objc_getAssociatedObject(self, @selector(shouldResignOnTouchOutsideMode));
return [shouldResignOnTouchOutsideMode unsignedIntegerValue];
}
@end
///------------------------------------
/// @name keyboardDistanceFromTextField
///------------------------------------
/**
Uses default keyboard distance for textField.
*/
CGFloat const kIQUseDefaultKeyboardDistance = CGFLOAT_MAX;
@@ -0,0 +1,134 @@
//
// IQUIView+Hierarchy.h
// 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/UIView.h>
#import <UIKit/UIViewController.h>
#import "IQKeyboardManagerConstants.h"
@class UICollectionView, UIScrollView, UITableView, UISearchBar, NSArray;
/**
UIView hierarchy category.
*/
@interface UIView (IQ_UIView_Hierarchy)
///----------------------
/// @name viewControllers
///----------------------
/**
Returns the UIViewController object that manages the receiver.
*/
@property (nullable, nonatomic, readonly, strong) UIViewController *viewContainingController;
/**
Returns the topMost UIViewController object in hierarchy.
*/
@property (nullable, nonatomic, readonly, strong) UIViewController *topMostController;
/**
Returns the UIViewController object that is actually the parent of this object. Most of the time it's the viewController object which actually contains it, but result may be different if it's viewController is added as childViewController of another viewController.
*/
@property (nullable, nonatomic, readonly, strong) UIViewController *parentContainerViewController;
///-----------------------------------
/// @name Superviews/Subviews/Siglings
///-----------------------------------
/**
Returns the superView of provided class type.
*/
-(nullable UIView*)superviewOfClassType:(nonnull Class)classType;
/**
Returns all siblings of the receiver which canBecomeFirstResponder.
*/
@property (nonnull, nonatomic, readonly, copy) NSArray<__kindof UIView*> *responderSiblings;
/**
Returns all deep subViews of the receiver which canBecomeFirstResponder.
*/
@property (nonnull, nonatomic, readonly, copy) NSArray<__kindof UIView*> *deepResponderViews;
///-------------------------
/// @name Special TextFields
///-------------------------
/**
Returns searchBar if receiver object is UISearchBarTextField, otherwise return nil.
*/
@property (nullable, nonatomic, readonly) UISearchBar *searchBar;
/**
Returns YES if the receiver object is UIAlertSheetTextField, otherwise return NO.
*/
@property (nonatomic, getter=isAlertViewTextField, readonly) BOOL alertViewTextField;
///----------------
/// @name Transform
///----------------
/**
Returns current view transform with respect to the 'toView'.
*/
-(CGAffineTransform)convertTransformToView:(nullable UIView*)toView;
///-----------------
/// @name Hierarchy
///-----------------
/**
Returns a string that represent the information about it's subview's hierarchy. You can use this method to debug the subview's positions.
*/
@property (nonnull, nonatomic, readonly, copy) NSString *subHierarchy;
/**
Returns an string that represent the information about it's upper hierarchy. You can use this method to debug the superview's positions.
*/
@property (nonnull, nonatomic, readonly, copy) NSString *superHierarchy;
/**
Returns an string that represent the information about it's frame positions. You can use this method to debug self positions.
*/
@property (nonnull, nonatomic, readonly, copy) NSString *debugHierarchy;
@end
@interface UIViewController (IQ_UIView_Hierarchy)
-(nullable UIViewController*)parentIQContainerViewController;
@end
/**
NSObject category to used for logging purposes
*/
@interface NSObject (IQ_Logging)
/**
Short description for logging purpose.
*/
@property (nonnull, nonatomic, readonly, copy) NSString *_IQDescription;
@end
@@ -0,0 +1,437 @@
//
// IQUIView+Hierarchy.m
// 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 "IQUIView+Hierarchy.h"
#import "IQUITextFieldView+Additions.h"
#import <UIKit/UICollectionView.h>
#import <UIKit/UIAlertController.h>
#import <UIKit/UITableView.h>
#import <UIKit/UITextView.h>
#import <UIKit/UITextField.h>
#import <UIKit/UISearchBar.h>
#import <UIKit/UINavigationController.h>
#import <UIKit/UITabBarController.h>
#import <UIKit/UISplitViewController.h>
#import <UIKit/UIWindow.h>
#import <objc/runtime.h>
#import "IQNSArray+Sort.h"
@implementation UIView (IQ_UIView_Hierarchy)
-(UIViewController*)viewContainingController
{
UIResponder *nextResponder = self;
do
{
nextResponder = [nextResponder nextResponder];
if ([nextResponder isKindOfClass:[UIViewController class]])
return (UIViewController*)nextResponder;
} while (nextResponder);
return nil;
}
-(UIViewController *)topMostController
{
NSMutableArray<UIViewController*> *controllersHierarchy = [[NSMutableArray alloc] init];
UIViewController *topController = self.window.rootViewController;
if (topController)
{
[controllersHierarchy addObject:topController];
}
while ([topController presentedViewController]) {
topController = [topController presentedViewController];
[controllersHierarchy addObject:topController];
}
UIViewController *matchController = [self viewContainingController];
while (matchController && [controllersHierarchy containsObject:matchController] == NO)
{
do
{
matchController = (UIViewController*)[matchController nextResponder];
} while (matchController && [matchController isKindOfClass:[UIViewController class]] == NO);
}
return matchController;
}
-(UIViewController *)parentContainerViewController
{
UIViewController *matchController = [self viewContainingController];
UIViewController *parentContainerViewController = nil;
if (matchController.navigationController)
{
UINavigationController *navController = matchController.navigationController;
while (navController.navigationController) {
navController = navController.navigationController;
}
UIViewController *parentController = navController;
UIViewController *parentParentController = parentController.parentViewController;
while (parentParentController &&
([parentParentController isKindOfClass:[UINavigationController class]] == NO &&
[parentParentController isKindOfClass:[UITabBarController class]] == NO &&
[parentParentController isKindOfClass:[UISplitViewController class]] == NO))
{
parentController = parentParentController;
parentParentController = parentController.parentViewController;
}
if (navController == parentController)
{
parentContainerViewController = navController.topViewController;
}
else
{
parentContainerViewController = parentController;
}
}
else if (matchController.tabBarController)
{
if ([matchController.tabBarController.selectedViewController isKindOfClass:[UINavigationController class]])
{
parentContainerViewController = [(UINavigationController*)matchController.tabBarController.selectedViewController topViewController];
}
else
{
parentContainerViewController = matchController.tabBarController.selectedViewController;
}
}
else
{
UIViewController *matchParentController = matchController.parentViewController;
while (matchParentController &&
([matchParentController isKindOfClass:[UINavigationController class]] == NO &&
[matchParentController isKindOfClass:[UITabBarController class]] == NO &&
[matchParentController isKindOfClass:[UISplitViewController class]] == NO))
{
matchController = matchParentController;
matchParentController = matchController.parentViewController;
}
parentContainerViewController = matchController;
}
UIViewController *finalController = [parentContainerViewController parentIQContainerViewController] ?: parentContainerViewController;
return finalController;
}
-(UIView*)superviewOfClassType:(Class)classType
{
UIView *superview = self.superview;
while (superview)
{
if ([superview isKindOfClass:classType])
{
//If it's UIScrollView, then validating for special cases
if ([superview isKindOfClass:[UIScrollView class]])
{
NSString *classNameString = NSStringFromClass([superview class]);
// 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 ([superview.superview isKindOfClass:[UITableView class]] == NO &&
[superview.superview isKindOfClass:[UITableViewCell class]] == NO &&
[classNameString hasPrefix:@"_"] == NO)
{
return superview;
}
}
else
{
return superview;
}
}
superview = superview.superview;
}
return nil;
}
-(BOOL)_IQcanBecomeFirstResponder
{
BOOL _IQcanBecomeFirstResponder = NO;
if ([self isKindOfClass:[UITextField class]])
{
_IQcanBecomeFirstResponder = [(UITextField*)self isEnabled];
}
else if ([self isKindOfClass:[UITextView class]])
{
_IQcanBecomeFirstResponder = [(UITextView*)self isEditable];
}
if (_IQcanBecomeFirstResponder == YES)
{
_IQcanBecomeFirstResponder = ([self isUserInteractionEnabled] && ![self isHidden] && [self alpha]!=0.0 && ![self isAlertViewTextField] && !self.searchBar);
}
return _IQcanBecomeFirstResponder;
}
- (NSArray<UIView*>*)responderSiblings
{
// Getting all siblings
NSArray<UIView*> *siblings = self.superview.subviews;
//Array of (UITextField/UITextView's).
NSMutableArray<UIView*> *tempTextFields = [[NSMutableArray alloc] init];
for (UIView *textField in siblings)
if ((textField == self || textField.ignoreSwitchingByNextPrevious == NO) && [textField _IQcanBecomeFirstResponder])
[tempTextFields addObject:textField];
return tempTextFields;
}
- (NSArray<UIView*>*)deepResponderViews
{
NSMutableArray<UIView*> *textFields = [[NSMutableArray alloc] init];
for (UIView *textField in self.subviews)
{
if ((textField == self || textField.ignoreSwitchingByNextPrevious == NO) && [textField _IQcanBecomeFirstResponder])
{
[textFields addObject:textField];
}
//Sometimes there are hidden or disabled views and textField inside them still recorded, so we added some more validations here (Bug ID: #458)
//Uncommented else (Bug ID: #625)
if (textField.subviews.count && [textField isUserInteractionEnabled] && ![textField isHidden] && [textField alpha]!=0.0)
{
[textFields addObjectsFromArray:[textField deepResponderViews]];
}
}
//subviews are returning in incorrect order. Sorting according the frames 'y'.
return [textFields sortedArrayUsingComparator:^NSComparisonResult(UIView *view1, UIView *view2) {
CGRect frame1 = [view1 convertRect:view1.bounds toView:self];
CGRect frame2 = [view2 convertRect:view2.bounds toView:self];
CGFloat x1 = CGRectGetMinX(frame1);
CGFloat y1 = CGRectGetMinY(frame1);
CGFloat x2 = CGRectGetMinX(frame2);
CGFloat y2 = CGRectGetMinY(frame2);
if (y1 < y2) return NSOrderedAscending;
else if (y1 > y2) return NSOrderedDescending;
//Else both y are same so checking for x positions
else if (x1 < x2) return NSOrderedAscending;
else if (x1 > x2) return NSOrderedDescending;
else return NSOrderedSame;
}];
return textFields;
}
-(CGAffineTransform)convertTransformToView:(UIView*)toView
{
if (toView == nil)
{
toView = self.window;
}
CGAffineTransform myTransform = CGAffineTransformIdentity;
//My Transform
{
UIView *superView = [self superview];
if (superView) myTransform = CGAffineTransformConcat(self.transform, [superView convertTransformToView:nil]);
else myTransform = self.transform;
}
CGAffineTransform viewTransform = CGAffineTransformIdentity;
//view Transform
{
UIView *superView = [toView superview];
if (superView) viewTransform = CGAffineTransformConcat(toView.transform, [superView convertTransformToView:nil]);
else if (toView) viewTransform = toView.transform;
}
return CGAffineTransformConcat(myTransform, CGAffineTransformInvert(viewTransform));
}
- (NSInteger)depth
{
NSInteger depth = 0;
if ([self superview])
{
depth = [[self superview] depth] + 1;
}
return depth;
}
- (NSString *)subHierarchy
{
NSMutableString *debugInfo = [[NSMutableString alloc] initWithString:@"\n"];
NSInteger depth = [self depth];
for (int counter = 0; counter < depth; counter ++) [debugInfo appendString:@"| "];
[debugInfo appendString:[self debugHierarchy]];
for (UIView *subview in self.subviews)
{
[debugInfo appendString:[subview subHierarchy]];
}
return debugInfo;
}
- (NSString *)superHierarchy
{
NSMutableString *debugInfo = [[NSMutableString alloc] init];
if (self.superview)
{
[debugInfo appendString:[self.superview superHierarchy]];
}
else
{
[debugInfo appendString:@"\n"];
}
NSInteger depth = [self depth];
for (int counter = 0; counter < depth; counter ++) [debugInfo appendString:@"| "];
[debugInfo appendString:[self debugHierarchy]];
[debugInfo appendString:@"\n"];
return debugInfo;
}
-(NSString *)debugHierarchy
{
NSMutableString *debugInfo = [[NSMutableString alloc] init];
[debugInfo appendFormat:@"%@: ( %.0f, %.0f, %.0f, %.0f )",NSStringFromClass([self class]), CGRectGetMinX(self.frame), CGRectGetMinY(self.frame), CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)];
if ([self isKindOfClass:[UIScrollView class]])
{
UIScrollView *scrollView = (UIScrollView*)self;
[debugInfo appendFormat:@"%@: ( %.0f, %.0f )",NSStringFromSelector(@selector(contentSize)),scrollView.contentSize.width,scrollView.contentSize.height];
}
if (CGAffineTransformEqualToTransform(self.transform, CGAffineTransformIdentity) == false)
{
[debugInfo appendFormat:@"%@: %@",NSStringFromSelector(@selector(transform)),NSStringFromCGAffineTransform(self.transform)];
}
return debugInfo;
}
-(UISearchBar *)searchBar
{
UIResponder *searchBar = [self nextResponder];
while (searchBar)
{
if ([searchBar isKindOfClass:[UISearchBar class]])
{
return (UISearchBar*)searchBar;
}
else if ([searchBar isKindOfClass:[UIViewController class]]) //If found viewcontroller but still not found UISearchBar then it's not the search bar textfield
{
break;
}
searchBar = [searchBar nextResponder];
}
return nil;
}
-(BOOL)isAlertViewTextField
{
UIResponder *alertViewController = [self viewContainingController];
BOOL isAlertViewTextField = NO;
while (alertViewController && isAlertViewTextField == NO)
{
if ([alertViewController isKindOfClass:[UIAlertController class]])
{
isAlertViewTextField = YES;
break;
}
alertViewController = [alertViewController nextResponder];
}
return isAlertViewTextField;
}
@end
@implementation UIViewController (IQ_UIView_Hierarchy)
-(nullable UIViewController*)parentIQContainerViewController
{
return self;
}
@end
@implementation NSObject (IQ_Logging)
-(NSString *)_IQDescription
{
return [NSString stringWithFormat:@"<%@ %p>",NSStringFromClass([self class]),self];
}
@end
@@ -0,0 +1,39 @@
//
// IQUIViewController+Additions.h
// 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/UIViewController.h>
@class NSLayoutConstraint;
@interface UIViewController (Additions)
/**
Top/Bottom Layout constraint which help library to manage keyboardTextField distance
@message Library is internally handle Safe Area in iOS11 if `canAdjustAdditionalSafeAreaInsets = YES` and there is no need to do any tweak if you already migrated to use Safe Area
@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.
*/
@property(nullable, nonatomic, strong) IBOutlet NSLayoutConstraint *IQLayoutGuideConstraint __attribute__((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.")));
@end
@@ -0,0 +1,40 @@
//
// IQUIViewController+Additions.m
// 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 "IQUIViewController+Additions.h"
#import <UIKit/NSLayoutConstraint.h>
#import <objc/runtime.h>
@implementation UIViewController (Additions)
-(void)setIQLayoutGuideConstraint:(NSLayoutConstraint *)IQLayoutGuideConstraint
{
objc_setAssociatedObject(self, @selector(IQLayoutGuideConstraint), IQLayoutGuideConstraint, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSLayoutConstraint *)IQLayoutGuideConstraint
{
return objc_getAssociatedObject(self, @selector(IQLayoutGuideConstraint));
}
@end
@@ -0,0 +1,156 @@
//
// IQKeyboardManagerConstants.h
// 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.
#ifndef IQKeyboardManagerConstants_h
#define IQKeyboardManagerConstants_h
#import <Foundation/NSObjCRuntime.h>
///-----------------------------------
/// @name 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.
*/
typedef NS_ENUM(NSInteger, IQAutoToolbarManageBehaviour) {
IQAutoToolbarBySubviews,
IQAutoToolbarByTag,
IQAutoToolbarByPosition,
};
/**
`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.
*/
typedef NS_ENUM(NSUInteger, IQPreviousNextDisplayMode) {
IQPreviousNextDisplayModeDefault,
IQPreviousNextDisplayModeAlwaysHide,
IQPreviousNextDisplayModeAlwaysShow,
};
/**
`IQEnableModeDefault`
Pick default settings.
`IQEnableModeEnabled`
setting is enabled.
`IQEnableModeDisabled`
setting is disabled.
*/
typedef NS_ENUM(NSUInteger, IQEnableMode) {
IQEnableModeDefault,
IQEnableModeEnabled,
IQEnableModeDisabled,
};
#endif
/*
/---------------------------------------------------------------------------------------------------\
\---------------------------------------------------------------------------------------------------/
| iOS NSNotification 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
*/
@@ -0,0 +1,30 @@
//
// IQKeyboardManagerConstantsInternal.h
// 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.
#ifndef IQKeyboardManagerConstantsInternal_h
#define IQKeyboardManagerConstantsInternal_h
#define IQ_IS_IOS10_OR_GREATER ([[NSProcessInfo processInfo] operatingSystemVersion].majorVersion >= 10)
#endif
+368
View File
@@ -0,0 +1,368 @@
//
// IQKeyboardManager.h
// 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 "IQKeyboardManagerConstants.h"
#import "IQUIView+IQKeyboardToolbar.h"
#import "IQPreviousNextView.h"
#import "IQUIViewController+Additions.h"
#import "IQKeyboardReturnKeyHandler.h"
#import "IQTextView.h"
#import "IQToolbar.h"
#import "IQUIScrollView+Additions.h"
#import "IQUITextFieldView+Additions.h"
#import "IQBarButtonItem.h"
#import "IQTitleBarButtonItem.h"
#import "IQUIView+Hierarchy.h"
#import <CoreGraphics/CGBase.h>
#import <Foundation/NSObject.h>
#import <Foundation/NSObjCRuntime.h>
#import <Foundation/NSSet.h>
#import <UIKit/UITextInputTraits.h>
@class UIFont, UIColor, UITapGestureRecognizer, UIView, UIImage;
@class NSString;
///---------------------
/// @name IQToolbar tags
///---------------------
/**
Default tag for toolbar with Done button -1002.
*/
extern NSInteger const kIQDoneButtonToolbarTag;
/**
Default tag for toolbar with Previous/Next buttons -1005.
*/
extern NSInteger const kIQPreviousNextButtonToolbarTag;
/**
Codeless drop-in universal library allows to prevent issues of keyboard sliding up and cover UITextField/UITextView. Neither need to write any code nor any setup required and much more. A generic version of KeyboardManagement. https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html
*/
@interface IQKeyboardManager : NSObject
///--------------------------
/// @name UIKeyboard handling
///--------------------------
/**
Returns the default singleton instance. You are not allowed to create your own instances of this class.
*/
+ (nonnull instancetype)sharedManager;
/**
Enable/disable managing distance between keyboard and textField. Default is YES(Enabled when class loads in `+(void)load` method).
*/
@property(nonatomic, assign, getter = isEnabled) BOOL enable;
/**
To set keyboard distance from textField. can't be less than zero. Default is 10.0.
*/
@property(nonatomic, assign) CGFloat keyboardDistanceFromTextField;
/**
Prevent keyboard manager to slide up the rootView to more than keyboard height. Default is YES.
Due to change in core-logic of handling distance between textField and keyboard distance, this tweak is no longer needed and things will just work out of the box for most of the cases.
*/
@property(nonatomic, assign) BOOL preventShowingBottomBlankSpace __attribute__((deprecated("Due to change in core-logic of handling distance between textField and keyboard distance, this tweak is no longer needed and things will just work out of the box for most of the cases. This property will be removed in future release.")));
/**
Refreshes textField/textView position if any external changes is explicitly made by user.
*/
- (void)reloadLayoutIfNeeded;
/**
Boolean to know if keyboard is showing.
*/
@property(nonatomic, assign, readonly, getter = isKeyboardShowing) BOOL keyboardShowing;
/**
moved distance to the top used to maintain distance between keyboard and textField. Most of the time this will be a positive value.
*/
@property(nonatomic, assign, readonly) CGFloat movedDistance;
///-------------------------
/// @name IQToolbar handling
///-------------------------
/**
Automatic add IQToolbar functionality. Default is YES.
*/
@property(nonatomic, assign, getter = isEnableAutoToolbar) BOOL enableAutoToolbar;
/**
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.
Default is IQAutoToolbarBySubviews.
*/
@property(nonatomic, assign) IQAutoToolbarManageBehaviour toolbarManageBehaviour;
/**
If YES, then uses textField's tintColor property for IQToolbar, otherwise tint color is black. Default is NO.
*/
@property(nonatomic, assign) BOOL shouldToolbarUsesTextFieldTintColor;
/**
This is used for toolbar.tintColor when textfield.keyboardAppearance is UIKeyboardAppearanceDefault. If shouldToolbarUsesTextFieldTintColor is YES then this property is ignored. Default is nil and uses black color.
*/
@property(nullable, nonatomic, strong) UIColor *toolbarTintColor;
/**
This is used for toolbar.barTintColor. Default is nil and uses white color.
*/
@property(nullable, nonatomic, strong) UIColor *toolbarBarTintColor;
/**
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.
*/
@property(nonatomic, assign) IQPreviousNextDisplayMode previousNextDisplayMode;
/**
Toolbar previous/next/done button icon, If nothing is provided then check toolbarDoneBarButtonItemText to draw done button.
*/
@property(nullable, nonatomic, strong) UIImage *toolbarPreviousBarButtonItemImage;
@property(nullable, nonatomic, strong) UIImage *toolbarNextBarButtonItemImage;
@property(nullable, nonatomic, strong) UIImage *toolbarDoneBarButtonItemImage;
/**
Toolbar previous/next/done button text, If nothing is provided then system default 'UIBarButtonSystemItemDone' will be used.
*/
@property(nullable, nonatomic, strong) NSString *toolbarPreviousBarButtonItemText;
@property(nullable, nonatomic, strong) NSString *toolbarNextBarButtonItemText;
@property(nullable, nonatomic, strong) NSString *toolbarDoneBarButtonItemText;
/**
If YES, then it add the textField's placeholder text on IQToolbar. Default is YES.
*/
@property(nonatomic, assign) BOOL shouldShowTextFieldPlaceholder __attribute__((deprecated("This is renamed to `shouldShowToolbarPlaceholder` for more clear naming.")));
@property(nonatomic, assign) BOOL shouldShowToolbarPlaceholder;
/**
Placeholder Font. Default is nil.
*/
@property(nullable, nonatomic, strong) UIFont *placeholderFont;
/**
Placeholder Color. Default is nil. Which means lightGray
*/
@property(nullable, nonatomic, strong) UIColor *placeholderColor;
/**
Placeholder Button Color when it's treated as button. Default is nil. Which means iOS Blue for light toolbar and Yellow for dark toolbar
*/
@property(nullable, nonatomic, strong) UIColor *placeholderButtonColor;
/**
Reload all toolbar buttons on the fly.
*/
- (void)reloadInputViews;
///---------------------------------------
/// @name UIKeyboard appearance overriding
///---------------------------------------
/**
Override the keyboardAppearance for all textField/textView. Default is NO.
*/
@property(nonatomic, assign) BOOL overrideKeyboardAppearance;
/**
If overrideKeyboardAppearance is YES, then all the textField keyboardAppearance is set using this property.
*/
@property(nonatomic, assign) UIKeyboardAppearance keyboardAppearance;
///-----------------------------------------------------------
/// @name UITextField/UITextView Next/Previous/Resign handling
///-----------------------------------------------------------
/**
Resigns Keyboard on touching outside of UITextField/View. Default is NO.
*/
@property(nonatomic, assign) BOOL shouldResignOnTouchOutside;
/** TapGesture to resign keyboard on view's touch. It's a readonly property and exposed only for adding/removing dependencies if your added gesture does have collision with this one */
@property(nonnull, nonatomic, strong, readonly) UITapGestureRecognizer *resignFirstResponderGesture;
/**
Resigns currently first responder field.
*/
- (BOOL)resignFirstResponder;
/**
Returns YES if can navigate to previous responder textField/textView, otherwise NO.
*/
@property (nonatomic, readonly) BOOL canGoPrevious;
/**
Returns YES if can navigate to next responder textField/textView, otherwise NO.
*/
@property (nonatomic, readonly) BOOL canGoNext;
/**
Navigate to previous responder textField/textView.
*/
- (BOOL)goPrevious;
/**
Navigate to next responder textField/textView.
*/
- (BOOL)goNext;
///-----------------------
/// @name UISound handling
///-----------------------
/**
If YES, then it plays inputClick sound on next/previous/done click. Default is YES.
*/
@property(nonatomic, assign) BOOL shouldPlayInputClicks;
///---------------------------
/// @name UIAnimation handling
///---------------------------
/**
If YES, then calls 'setNeedsLayout' and 'layoutIfNeeded' on any frame update of to viewController's view.
*/
@property(nonatomic, assign) BOOL layoutIfNeededOnUpdate;
///-----------------------------------------------
/// @name InteractivePopGestureRecognizer handling
///-----------------------------------------------
/**
If YES, then always consider UINavigationController.view begin point as {0,0}, this is a workaround to fix a bug #464 because there are no notification mechanism exist when UINavigationController.view.frame gets changed internally.
*/
@property(nonatomic, assign) BOOL shouldFixInteractivePopGestureRecognizer __attribute__((deprecated("Due to change in core-logic of handling distance between textField and keyboard distance, this tweak is no longer needed and things will just work out of the box for most of the cases. This property will be removed in future release.")));
#ifdef __IPHONE_11_0
///---------------------------
/// @name Safe Area
///---------------------------
/**
If YES, then library will try to adjust viewController.additionalSafeAreaInsets to automatically handle layout guide. Default is NO.
*/
@property(nonatomic, assign) BOOL canAdjustAdditionalSafeAreaInsets __attribute__((deprecated("Due to change in core-logic of handling distance between textField and keyboard distance, this safe area tweak is no longer needed and things will just work out of the box regardless of constraint pinned with safeArea/layoutGuide/superview. This property will be removed in future release.")));
#endif
///---------------------------------------------
/// @name Class Level enabling/disabling methods
///---------------------------------------------
/**
Disable distance handling within the scope of disabled distance handling viewControllers classes. Within this scope, 'enabled' property is ignored. Class should be kind of UIViewController. Default is [UITableViewController, UIAlertController, _UIAlertControllerTextFieldViewController].
*/
@property(nonatomic, strong, nonnull, readonly) NSMutableSet<Class> *disabledDistanceHandlingClasses;
/**
Enable distance handling within the scope of enabled distance handling viewControllers classes. Within this scope, 'enabled' property is ignored. Class should be kind of UIViewController. Default is [].
*/
@property(nonatomic, strong, nonnull, readonly) NSMutableSet<Class> *enabledDistanceHandlingClasses;
/**
Disable automatic toolbar creation within the scope of disabled toolbar viewControllers classes. Within this scope, 'enableAutoToolbar' property is ignored. Class should be kind of UIViewController. Default is [UIAlertController, _UIAlertControllerTextFieldViewController].
*/
@property(nonatomic, strong, nonnull, readonly) NSMutableSet<Class> *disabledToolbarClasses;
/**
Enable automatic toolbar creation within the scope of enabled toolbar viewControllers classes. Within this scope, 'enableAutoToolbar' property is ignored. Class should be kind of UIViewController. Default is [].
*/
@property(nonatomic, strong, nonnull, readonly) NSMutableSet<Class> *enabledToolbarClasses;
/**
Allowed subclasses of UIView to add all inner textField, this will allow to navigate between textField contains in different superview. Class should be kind of UIView. Default is [UITableView, UICollectionView, IQPreviousNextView].
*/
@property(nonatomic, strong, nonnull, readonly) NSMutableSet<Class> *toolbarPreviousNextAllowedClasses;
/**
Disabled classes to ignore 'shouldResignOnTouchOutside' property, Class should be kind of UIViewController. Default is [UIAlertController, UIAlertControllerTextFieldViewController]
*/
@property(nonatomic, strong, nonnull, readonly) NSMutableSet<Class> *disabledTouchResignedClasses;
/**
Enabled classes to forcefully enable 'shouldResignOnTouchOutsite' property. Class should be kind of UIViewController. Default is [].
*/
@property(nonatomic, strong, nonnull, readonly) NSMutableSet<Class> *enabledTouchResignedClasses;
/**
if shouldResignOnTouchOutside is enabled then you can customise the behaviour to not recognise gesture touches on some specific view subclasses. Class should be kind of UIView. Default is [UIControl, UINavigationBar]
*/
@property(nonatomic, strong, nonnull, readonly) NSMutableSet<Class> *touchResignedGestureIgnoreClasses;
///-------------------------------------------
/// @name Third Party Library support
/// Add TextField/TextView Notifications customised NSNotifications. For example while using YYTextView https://github.com/ibireme/YYText
///-------------------------------------------
/**
Add/Remove customised Notification for third party customised TextField/TextView. Please be aware that the NSNotification object must be idential to UITextField/UITextView NSNotification objects and customised TextField/TextView support must be idential to UITextField/UITextView.
@param didBeginEditingNotificationName This should be identical to UITextViewTextDidBeginEditingNotification
@param didEndEditingNotificationName This should be identical to UITextViewTextDidEndEditingNotification
*/
-(void)registerTextFieldViewClass:(nonnull Class)aClass
didBeginEditingNotificationName:(nonnull NSString *)didBeginEditingNotificationName
didEndEditingNotificationName:(nonnull NSString *)didEndEditingNotificationName;
-(void)unregisterTextFieldViewClass:(nonnull Class)aClass
didBeginEditingNotificationName:(nonnull NSString *)didBeginEditingNotificationName
didEndEditingNotificationName:(nonnull NSString *)didEndEditingNotificationName;
///----------------------------------------
/// @name Debugging & Developer options
///----------------------------------------
@property(nonatomic, assign) BOOL enableDebugging;
/**
@warning Use these methods to completely enable/disable notifications registered by library internally. Please keep in mind that library is totally dependent on NSNotification of UITextField, UITextField, Keyboard etc. If you do unregisterAllNotifications then library will not work at all. You should only use below methods if you want to completedly disable all library functions. You should use below methods at your own risk.
*/
-(void)registerAllNotifications;
-(void)unregisterAllNotifications;
///----------------------------------------
/// @name Must not be used for subclassing.
///----------------------------------------
/**
Unavailable. Please use sharedManager method
*/
-(nonnull instancetype)init NS_UNAVAILABLE;
/**
Unavailable. Please use sharedManager method
*/
+ (nonnull instancetype)new NS_UNAVAILABLE;
@end
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,99 @@
//
// IQKeyboardReturnKeyHandler.h
// 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 "IQKeyboardManagerConstants.h"
#import <Foundation/NSObject.h>
#import <Foundation/NSObjCRuntime.h>
#import <UIKit/UITextInputTraits.h>
@class UITextField, UIView, UIViewController;
@protocol UITextFieldDelegate, UITextViewDelegate;
/**
Manages the return key to work like next/done in a view hierarchy.
*/
@interface IQKeyboardReturnKeyHandler : NSObject
///----------------------
/// @name Initializations
///----------------------
/**
Add all the textFields available in UIViewController's view.
*/
-(nonnull instancetype)initWithViewController:(nullable UIViewController*)controller NS_DESIGNATED_INITIALIZER;
/**
Unavailable. Please use initWithViewController: or init method
*/
-(nonnull instancetype)initWithCoder:(nullable NSCoder *)aDecoder NS_UNAVAILABLE;
///---------------
/// @name Settings
///---------------
/**
Delegate of textField/textView.
*/
@property(nullable, nonatomic, weak) id<UITextFieldDelegate,UITextViewDelegate> delegate;
/**
Set the last textfield return key type. Default is UIReturnKeyDefault.
*/
@property(nonatomic, assign) UIReturnKeyType lastTextFieldReturnKeyType;
///----------------------------------------------
/// @name Registering/Unregistering textFieldView
///----------------------------------------------
/**
Should pass UITextField/UITextView instance. Assign textFieldView delegate to self, change it's returnKeyType.
@param textFieldView UITextField/UITextView object to register.
*/
-(void)addTextFieldView:(nonnull UIView*)textFieldView;
/**
Should pass UITextField/UITextView instance. Restore it's textFieldView delegate and it's returnKeyType.
@param textFieldView UITextField/UITextView object to unregister.
*/
-(void)removeTextFieldView:(nonnull UIView*)textFieldView;
/**
Add all the UITextField/UITextView responderView's.
@param view object to register all it's responder subviews.
*/
-(void)addResponderFromView:(nonnull UIView*)view;
/**
Remove all the UITextField/UITextView responderView's.
@param view object to unregister all it's responder subviews.
*/
-(void)removeResponderFromView:(nonnull UIView*)view;
@end
@@ -0,0 +1,637 @@
//
// IQKeyboardReturnKeyHandler.m
// 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 "IQKeyboardReturnKeyHandler.h"
#import "IQKeyboardManager.h"
#import "IQUIView+Hierarchy.h"
#import "IQNSArray+Sort.h"
#import <UIKit/UITextField.h>
#import <UIKit/UITextView.h>
#import <UIKit/UIViewController.h>
@interface IQTextFieldViewInfoModal : NSObject
@property(nullable, nonatomic, weak) UIView *textFieldView;
@property(nullable, nonatomic, weak) id<UITextFieldDelegate> textFieldDelegate;
@property(nullable, nonatomic, weak) id<UITextViewDelegate> textViewDelegate;
@property(nonatomic) UIReturnKeyType originalReturnKeyType;
@end
@implementation IQTextFieldViewInfoModal
-(instancetype)initWithTextFieldView:(UIView*)textFieldView textFieldDelegate:(id<UITextFieldDelegate>)textFieldDelegate textViewDelegate:(id<UITextViewDelegate>)textViewDelegate originalReturnKey:(UIReturnKeyType)returnKeyType
{
self = [super init];
if (self)
{
_textFieldView = textFieldView;
_textFieldDelegate = textFieldDelegate;
_textViewDelegate = textViewDelegate;
_originalReturnKeyType = returnKeyType;
}
return self;
}
@end
@interface IQKeyboardReturnKeyHandler ()<UITextFieldDelegate,UITextViewDelegate>
-(void)updateReturnKeyTypeOnTextField:(UIView*)textField;
@end
@implementation IQKeyboardReturnKeyHandler
{
NSMutableSet<IQTextFieldViewInfoModal*> *textFieldInfoCache;
}
@synthesize lastTextFieldReturnKeyType = _lastTextFieldReturnKeyType;
@synthesize delegate = _delegate;
- (instancetype)init
{
self = [self initWithViewController:nil];
return self;
}
-(instancetype)initWithViewController:(nullable UIViewController*)controller
{
self = [super init];
if (self)
{
textFieldInfoCache = [[NSMutableSet alloc] init];
if (controller.view)
{
[self addResponderFromView:controller.view];
}
}
return self;
}
-(IQTextFieldViewInfoModal*)textFieldViewCachedInfo:(UIView*)textField
{
for (IQTextFieldViewInfoModal *modal in textFieldInfoCache)
if (modal.textFieldView == textField) return modal;
return nil;
}
#pragma mark - Add/Remove TextFields
-(void)addResponderFromView:(UIView*)view
{
NSArray<UIView*> *textFields = [view deepResponderViews];
for (UIView *textField in textFields) [self addTextFieldView:textField];
}
-(void)removeResponderFromView:(UIView*)view
{
NSArray<UIView*> *textFields = [view deepResponderViews];
for (UIView *textField in textFields) [self removeTextFieldView:textField];
}
-(void)removeTextFieldView:(UIView*)view
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:view];
if (modal)
{
if ([view isKindOfClass:[UITextField class]])
{
UITextField *textField = (UITextField*)view;
textField.returnKeyType = modal.originalReturnKeyType;
textField.delegate = modal.textFieldDelegate;
}
else if ([view isKindOfClass:[UITextView class]])
{
UITextView *textView = (UITextView*)view;
textView.returnKeyType = modal.originalReturnKeyType;
textView.delegate = modal.textViewDelegate;
}
[textFieldInfoCache removeObject:modal];
}
}
-(void)addTextFieldView:(UIView*)view
{
IQTextFieldViewInfoModal *modal = [[IQTextFieldViewInfoModal alloc] initWithTextFieldView:view textFieldDelegate:nil textViewDelegate:nil originalReturnKey:UIReturnKeyDefault];
if ([view isKindOfClass:[UITextField class]])
{
UITextField *textField = (UITextField*)view;
modal.originalReturnKeyType = textField.returnKeyType;
modal.textFieldDelegate = textField.delegate;
[textField setDelegate:self];
}
else if ([view isKindOfClass:[UITextView class]])
{
UITextView *textView = (UITextView*)view;
modal.originalReturnKeyType = textView.returnKeyType;
modal.textViewDelegate = textView.delegate;
[textView setDelegate:self];
}
[textFieldInfoCache addObject:modal];
}
-(void)updateReturnKeyTypeOnTextField:(UIView*)textField
{
UIView *superConsideredView;
//If find any consider responderView in it's upper hierarchy then will get deepResponderView. (Bug ID: #347)
for (Class consideredClass in [[IQKeyboardManager sharedManager] toolbarPreviousNextAllowedClasses])
{
superConsideredView = [textField superviewOfClassType:consideredClass];
if (superConsideredView)
break;
}
NSArray<UIView*> *textFields = nil;
//If there is a tableView in view's hierarchy, then fetching all it's subview that responds. No sorting for tableView, it's by subView position.
if (superConsideredView) // // (Enhancement ID: #22)
{
textFields = [superConsideredView deepResponderViews];
}
//Otherwise fetching all the siblings
else
{
textFields = [textField responderSiblings];
//Sorting textFields according to behaviour
switch ([[IQKeyboardManager sharedManager] toolbarManageBehaviour])
{
//If needs to sort it by tag
case IQAutoToolbarByTag:
textFields = [textFields sortedArrayByTag];
break;
//If needs to sort it by Position
case IQAutoToolbarByPosition:
textFields = [textFields sortedArrayByPosition];
break;
default:
break;
}
}
//If it's the last textField in responder view, else next
[(UITextField*)textField setReturnKeyType:(([textFields lastObject] == textField) ? self.lastTextFieldReturnKeyType : UIReturnKeyNext)];
}
#pragma mark - Goto next or Resign.
-(BOOL)goToNextResponderOrResign:(UIView*)textField
{
UIView *superConsideredView;
//If find any consider responderView in it's upper hierarchy then will get deepResponderView. (Bug ID: #347)
for (Class consideredClass in [[IQKeyboardManager sharedManager] toolbarPreviousNextAllowedClasses])
{
superConsideredView = [textField superviewOfClassType:consideredClass];
if (superConsideredView)
break;
}
NSArray<UIView*> *textFields = nil;
//If there is a tableView in view's hierarchy, then fetching all it's subview that responds. No sorting for tableView, it's by subView position.
if (superConsideredView) // // (Enhancement ID: #22)
{
textFields = [superConsideredView deepResponderViews];
}
//Otherwise fetching all the siblings
else
{
textFields = [textField responderSiblings];
//Sorting textFields according to behaviour
switch ([[IQKeyboardManager sharedManager] toolbarManageBehaviour])
{
//If needs to sort it by tag
case IQAutoToolbarByTag:
textFields = [textFields sortedArrayByTag];
break;
//If needs to sort it by Position
case IQAutoToolbarByPosition:
textFields = [textFields sortedArrayByPosition];
break;
default:
break;
}
}
//Getting index of current textField.
NSUInteger index = [textFields indexOfObject:textField];
//If it is not last textField. then it's next object becomeFirstResponder.
if (index != NSNotFound && index < textFields.count-1)
{
[textFields[index+1] becomeFirstResponder];
return NO;
}
else
{
[textField resignFirstResponder];
return YES;
}
}
#pragma mark - TextField delegate
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
id<UITextFieldDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
delegate = modal.textFieldDelegate;
}
if ([delegate respondsToSelector:@selector(textFieldShouldBeginEditing:)])
return [delegate textFieldShouldBeginEditing:textField];
else
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[self updateReturnKeyTypeOnTextField:textField];
id<UITextFieldDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
delegate = modal.textFieldDelegate;
}
if ([delegate respondsToSelector:@selector(textFieldDidBeginEditing:)])
[delegate textFieldDidBeginEditing:textField];
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
id<UITextFieldDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
delegate = modal.textFieldDelegate;
}
if ([delegate respondsToSelector:@selector(textFieldShouldEndEditing:)])
return [delegate textFieldShouldEndEditing:textField];
else
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
id<UITextFieldDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
delegate = modal.textFieldDelegate;
}
if ([delegate respondsToSelector:@selector(textFieldDidEndEditing:)])
[delegate textFieldDidEndEditing:textField];
}
- (void)textFieldDidEndEditing:(UITextField *)textField reason:(UITextFieldDidEndEditingReason)reason NS_AVAILABLE_IOS(10_0);
{
id<UITextFieldDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
delegate = modal.textFieldDelegate;
}
#ifdef __IPHONE_11_0
if (@available(iOS 10.0, *)) {
#endif
if ([delegate respondsToSelector:@selector(textFieldDidEndEditing:reason:)])
[delegate textFieldDidEndEditing:textField reason:reason];
#ifdef __IPHONE_11_0
}
#endif
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
id<UITextFieldDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
delegate = modal.textFieldDelegate;
}
if ([delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)])
return [delegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
else
return YES;
}
- (BOOL)textFieldShouldClear:(UITextField *)textField
{
id<UITextFieldDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
delegate = modal.textFieldDelegate;
}
if ([delegate respondsToSelector:@selector(textFieldShouldClear:)])
return [delegate textFieldShouldClear:textField];
else
return YES;
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
id<UITextFieldDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textField];
delegate = modal.textFieldDelegate;
}
if ([delegate respondsToSelector:@selector(textFieldShouldReturn:)])
{
BOOL shouldReturn = [delegate textFieldShouldReturn:textField];
if (shouldReturn)
{
shouldReturn = [self goToNextResponderOrResign:textField];
}
return shouldReturn;
}
else
{
return [self goToNextResponderOrResign:textField];
}
}
#pragma mark - TextView delegate
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
id<UITextViewDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
delegate = modal.textViewDelegate;
}
if ([delegate respondsToSelector:@selector(textViewShouldBeginEditing:)])
return [delegate textViewShouldBeginEditing:textView];
else
return YES;
}
- (BOOL)textViewShouldEndEditing:(UITextView *)textView
{
id<UITextViewDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
delegate = modal.textViewDelegate;
}
if ([delegate respondsToSelector:@selector(textViewShouldEndEditing:)])
return [delegate textViewShouldEndEditing:textView];
else
return YES;
}
- (void)textViewDidBeginEditing:(UITextView *)textView
{
[self updateReturnKeyTypeOnTextField:textView];
id<UITextViewDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
delegate = modal.textViewDelegate;
}
if ([delegate respondsToSelector:@selector(textViewDidBeginEditing:)])
[delegate textViewDidBeginEditing:textView];
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
id<UITextViewDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
delegate = modal.textViewDelegate;
}
if ([delegate respondsToSelector:@selector(textViewDidEndEditing:)])
[delegate textViewDidEndEditing:textView];
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
id<UITextViewDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
delegate = modal.textViewDelegate;
}
BOOL shouldReturn = YES;
if ([delegate respondsToSelector:@selector(textView:shouldChangeTextInRange:replacementText:)])
shouldReturn = [delegate textView:textView shouldChangeTextInRange:range replacementText:text];
if (shouldReturn && [text isEqualToString:@"\n"])
{
shouldReturn = [self goToNextResponderOrResign:textView];
}
return shouldReturn;
}
- (void)textViewDidChange:(UITextView *)textView
{
id<UITextViewDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
delegate = modal.textViewDelegate;
}
if ([delegate respondsToSelector:@selector(textViewDidChange:)])
[delegate textViewDidChange:textView];
}
- (void)textViewDidChangeSelection:(UITextView *)textView
{
id<UITextViewDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
delegate = modal.textViewDelegate;
}
if ([delegate respondsToSelector:@selector(textViewDidChangeSelection:)])
[delegate textViewDidChangeSelection:textView];
}
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction NS_AVAILABLE_IOS(10_0);
{
id<UITextViewDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
delegate = modal.textViewDelegate;
}
#ifdef __IPHONE_11_0
if (@available(iOS 10.0, *)) {
#endif
if ([delegate respondsToSelector:@selector(textView:shouldInteractWithURL:inRange:interaction:)])
return [delegate textView:textView shouldInteractWithURL:URL inRange:characterRange interaction:interaction];
#ifdef __IPHONE_11_0
}
#endif
return YES;
}
- (BOOL)textView:(UITextView *)textView shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction NS_AVAILABLE_IOS(10_0);
{
id<UITextViewDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
delegate = modal.textViewDelegate;
}
#ifdef __IPHONE_11_0
if (@available(iOS 10.0, *)) {
#endif
if ([delegate respondsToSelector:@selector(textView:shouldInteractWithTextAttachment:inRange:interaction:)])
return [delegate textView:textView shouldInteractWithTextAttachment:textAttachment inRange:characterRange interaction:interaction];
#ifdef __IPHONE_11_0
}
#endif
return YES;
}
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
{
id<UITextViewDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
delegate = modal.textViewDelegate;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
if ([delegate respondsToSelector:@selector(textView:shouldInteractWithURL:inRange:)])
return [delegate textView:textView shouldInteractWithURL:URL inRange:characterRange];
#pragma clang diagnostic pop
else
return YES;
}
- (BOOL)textView:(UITextView *)textView shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment inRange:(NSRange)characterRange
{
id<UITextViewDelegate> delegate = self.delegate;
if (delegate == nil)
{
IQTextFieldViewInfoModal *modal = [self textFieldViewCachedInfo:textView];
delegate = modal.textViewDelegate;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
if ([delegate respondsToSelector:@selector(textView:shouldInteractWithTextAttachment:inRange:)])
return [delegate textView:textView shouldInteractWithTextAttachment:textAttachment inRange:characterRange];
#pragma clang diagnostic pop
else
return YES;
}
-(void)dealloc
{
for (IQTextFieldViewInfoModal *modal in textFieldInfoCache)
{
UIView *textFieldView = modal.textFieldView;
if ([textFieldView isKindOfClass:[UITextField class]])
{
UITextField *textField = (UITextField*)textFieldView;
textField.returnKeyType = modal.originalReturnKeyType;
textField.delegate = modal.textFieldDelegate
;
}
else if ([textFieldView isKindOfClass:[UITextView class]])
{
UITextView *textView = (UITextView*)textFieldView;
textView.returnKeyType = modal.originalReturnKeyType;
textView.delegate = modal.textViewDelegate;
}
}
[textFieldInfoCache removeAllObjects];
}
@end
@@ -0,0 +1,47 @@
//
// IQTextView.h
// 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 "IQKeyboardManagerConstants.h"
#import <UIKit/UITextView.h>
/**
UITextView with placeholder support
*/
@interface IQTextView : UITextView
/**
Set textView's placeholder text. Default is nil.
*/
@property(nullable, nonatomic,copy) IBInspectable NSString *placeholder;
/**
To set textView's placeholder text color. Default is nil.
*/
@property(nullable, nonatomic,copy) IBInspectable UIColor *placeholderTextColor;
@end
@@ -0,0 +1,165 @@
//
// IQTextView.m
// 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 "IQTextView.h"
#import <UIKit/NSTextContainer.h>
#import <UIKit/UILabel.h>
#import <UIKit/UINibLoading.h>
@interface IQTextView ()
@property(nonatomic, strong) UILabel *placeholderLabel;
@end
@implementation IQTextView
@synthesize placeholder = _placeholder;
@synthesize placeholderLabel = _placeholderLabel;
@synthesize placeholderTextColor = _placeholderTextColor;
-(void)initialize
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshPlaceholder) name:UITextViewTextDidChangeNotification object:self];
}
-(void)dealloc
{
[_placeholderLabel removeFromSuperview];
_placeholderLabel = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (instancetype)init
{
self = [super init];
if (self) {
[self initialize];
}
return self;
}
-(void)awakeFromNib
{
[super awakeFromNib];
[self initialize];
}
-(void)refreshPlaceholder
{
if([[self text] length])
{
[_placeholderLabel setAlpha:0];
}
else
{
[_placeholderLabel setAlpha:1];
}
[self setNeedsLayout];
[self layoutIfNeeded];
}
- (void)setText:(NSString *)text
{
[super setText:text];
[self refreshPlaceholder];
}
-(void)setFont:(UIFont *)font
{
[super setFont:font];
self.placeholderLabel.font = self.font;
[self setNeedsLayout];
[self layoutIfNeeded];
}
-(void)setTextAlignment:(NSTextAlignment)textAlignment
{
[super setTextAlignment:textAlignment];
self.placeholderLabel.textAlignment = textAlignment;
[self setNeedsLayout];
[self layoutIfNeeded];
}
-(void)layoutSubviews
{
[super layoutSubviews];
UIEdgeInsets placeholderInsets = [self placeholderInsets];
CGFloat maxWidth = CGRectGetWidth(self.frame)-placeholderInsets.left-placeholderInsets.right;
CGSize expectedSize = [self.placeholderLabel sizeThatFits:CGSizeMake(maxWidth, CGRectGetHeight(self.frame)-placeholderInsets.top-placeholderInsets.bottom)];
self.placeholderLabel.frame = CGRectMake(placeholderInsets.left, placeholderInsets.top, maxWidth, expectedSize.height);
}
-(void)setPlaceholder:(NSString *)placeholder
{
_placeholder = placeholder;
self.placeholderLabel.text = placeholder;
[self refreshPlaceholder];
}
-(void)setPlaceholderTextColor:(UIColor*)placeholderTextColor
{
_placeholderTextColor = placeholderTextColor;
self.placeholderLabel.textColor = placeholderTextColor;
}
-(UIEdgeInsets)placeholderInsets
{
return UIEdgeInsetsMake(self.textContainerInset.top, self.textContainerInset.left + self.textContainer.lineFragmentPadding, self.textContainerInset.bottom, self.textContainerInset.right + self.textContainer.lineFragmentPadding);
}
-(UILabel*)placeholderLabel
{
if (_placeholderLabel == nil)
{
_placeholderLabel = [[UILabel alloc] init];
_placeholderLabel.autoresizingMask = (UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight);
_placeholderLabel.lineBreakMode = NSLineBreakByWordWrapping;
_placeholderLabel.numberOfLines = 0;
_placeholderLabel.font = self.font;
_placeholderLabel.textAlignment = self.textAlignment;
_placeholderLabel.backgroundColor = [UIColor clearColor];
_placeholderLabel.textColor = [UIColor colorWithWhite:0.7 alpha:1.0];
_placeholderLabel.alpha = 0;
[self addSubview:_placeholderLabel];
}
return _placeholderLabel;
}
//When any text changes on textField, the delegate getter is called. At this time we refresh the textView's placeholder
-(id<UITextViewDelegate>)delegate
{
[self refreshPlaceholder];
return [super delegate];
}
@end
@@ -0,0 +1,51 @@
//
// IQBarButtonItem.h
// 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/UIBarButtonItem.h>
@class NSInvocation;
/**
IQBarButtonItem used for IQToolbar.
*/
@interface IQBarButtonItem : UIBarButtonItem
/**
Boolean to know if it's a system item or custom item
*/
@property (nonatomic, readonly) BOOL isSystemItem;
/**
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.
*/
-(void)setTarget:(nullable id)target action:(nullable SEL)action;
/**
Customized Invocation to be called when button is pressed. invocation is internally created using setTarget:action: method.
*/
@property (nullable, strong, nonatomic) NSInvocation *invocation;
@end
@@ -0,0 +1,99 @@
//
// IQBarButtonItem.m
// 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 "IQBarButtonItem.h"
#import "IQKeyboardManagerConstantsInternal.h"
#import <UIKit/NSAttributedString.h>
@implementation IQBarButtonItem
+(void)initialize
{
[super initialize];
IQBarButtonItem *appearanceProxy = [self appearance];
NSArray <NSNumber*> *states = @[@(UIControlStateNormal),@(UIControlStateHighlighted),@(UIControlStateDisabled),@(UIControlStateSelected),@(UIControlStateApplication),@(UIControlStateReserved)];
for (NSNumber *state in states)
{
UIControlState controlState = [state unsignedIntegerValue];
[appearanceProxy setBackgroundImage:nil forState:controlState barMetrics:UIBarMetricsDefault];
[appearanceProxy setBackgroundImage:nil forState:controlState style:UIBarButtonItemStyleDone barMetrics:UIBarMetricsDefault];
[appearanceProxy setBackgroundImage:nil forState:controlState style:UIBarButtonItemStylePlain barMetrics:UIBarMetricsDefault];
[appearanceProxy setBackButtonBackgroundImage:nil forState:controlState barMetrics:UIBarMetricsDefault];
}
[appearanceProxy setTitlePositionAdjustment:UIOffsetZero forBarMetrics:UIBarMetricsDefault];
[appearanceProxy setBackgroundVerticalPositionAdjustment:0 forBarMetrics:UIBarMetricsDefault];
[appearanceProxy setBackButtonBackgroundVerticalPositionAdjustment:0 forBarMetrics:UIBarMetricsDefault];
}
-(void)setTintColor:(UIColor *)tintColor
{
[super setTintColor:tintColor];
//titleTextAttributes tweak is to overcome an issue comes with iOS11 where appearanceProxy set for NSForegroundColorAttributeName and bar button texts start appearing in appearance proxy color
NSMutableDictionary *textAttributes = [[self titleTextAttributesForState:UIControlStateNormal] mutableCopy]?:[NSMutableDictionary new];
textAttributes[NSForegroundColorAttributeName] = tintColor;
[self setTitleTextAttributes:textAttributes forState:UIControlStateNormal];
}
- (instancetype)initWithBarButtonSystemItem:(UIBarButtonSystemItem)systemItem target:(nullable id)target action:(nullable SEL)action
{
self = [super initWithBarButtonSystemItem:systemItem target:target action:action];
if (self)
{
_isSystemItem = YES;
}
return self;
}
-(void)setTarget:(nullable id)target action:(nullable SEL)action
{
NSInvocation *invocation = nil;
if (target && action)
{
invocation = [NSInvocation invocationWithMethodSignature:[target methodSignatureForSelector:action]];
invocation.target = target;
invocation.selector = action;
}
self.invocation = invocation;
}
-(void)dealloc
{
self.target = nil;
self.invocation.target = nil;
self.invocation = nil;
}
@end
@@ -0,0 +1,30 @@
//
// IQPreviousNextView.h
// 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/UIView.h>
/**
If you need to enable previous/next toolbar button with some complex hierarchy where your textFields are not in same view, then make the top view as IQPreviousNextView.
*/
@interface IQPreviousNextView : UIView
@end
@@ -0,0 +1,28 @@
//
// IQPreviousNextView.m
// 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 "IQPreviousNextView.h"
@implementation IQPreviousNextView
@end
@@ -0,0 +1,71 @@
//
// IQTitleBarButtonItem.h
// 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 "IQKeyboardManagerConstants.h"
#import "IQBarButtonItem.h"
#import <Foundation/NSObjCRuntime.h>
/**
BarButtonItem with title text.
*/
@interface IQTitleBarButtonItem : IQBarButtonItem
/**
Font to be used in bar button. Default is (system font 12.0 bold).
*/
@property(nullable, nonatomic, strong) UIFont *titleFont;
/**
titleColor to be used for displaying button text when displaying title (disabled state).
*/
@property(nullable, nonatomic, strong) UIColor *titleColor;
/**
selectableTitleColor to be used for displaying button text when button is enabled.
*/
@property(nullable, nonatomic, strong) UIColor *selectableTitleColor;
/**
Initialize with frame and title.
@param title Title of barButtonItem.
*/
-(nonnull instancetype)initWithTitle:(nullable NSString *)title NS_DESIGNATED_INITIALIZER;
/**
Unavailable. Please use initWithFrame:title: method
*/
-(nonnull instancetype)init NS_UNAVAILABLE;
/**
Unavailable. Please use initWithFrame:title: method
*/
-(nonnull instancetype)initWithCoder:(nullable NSCoder *)aDecoder NS_UNAVAILABLE;
/**
Unavailable. Please use initWithFrame:title: method
*/
+ (nonnull instancetype)new NS_UNAVAILABLE;
@end
@@ -0,0 +1,153 @@
//
// IQTitleBarButtonItem.m
// 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 "IQTitleBarButtonItem.h"
#import "IQKeyboardManagerConstants.h"
#import "IQKeyboardManagerConstantsInternal.h"
#import <UIKit/UILabel.h>
#import <UIKit/UIButton.h>
@interface IQTitleBarButtonItem ()
@property(nonatomic, strong) UIView *titleView;
@property(nonatomic, strong) UIButton *titleButton;
@end
@implementation IQTitleBarButtonItem
-(nonnull instancetype)initWithTitle:(nullable NSString *)title
{
self = [super init];
if (self)
{
_titleView = [[UIView alloc] init];
_titleView.backgroundColor = [UIColor clearColor];
_titleButton = [UIButton buttonWithType:UIButtonTypeSystem];
_titleButton.enabled = NO;
_titleButton.titleLabel.numberOfLines = 3;
[_titleButton setTitleColor:[UIColor colorWithRed:0.0 green:0.5 blue:1.0 alpha:1.0] forState:UIControlStateNormal];
[_titleButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled];
[_titleButton setBackgroundColor:[UIColor clearColor]];
[_titleButton.titleLabel setTextAlignment:NSTextAlignmentCenter];
[self setTitle:title];
[self setTitleFont:[UIFont systemFontOfSize:13.0]];
[_titleView addSubview:_titleButton];
#ifdef __IPHONE_11_0
if (@available(iOS 11.0, *))
{
CGFloat layoutDefaultLowPriority = UILayoutPriorityDefaultLow-1;
CGFloat layoutDefaultHighPriority = UILayoutPriorityDefaultHigh-1;
_titleView.translatesAutoresizingMaskIntoConstraints = NO;
[_titleView setContentHuggingPriority:layoutDefaultLowPriority forAxis:UILayoutConstraintAxisVertical];
[_titleView setContentHuggingPriority:layoutDefaultLowPriority forAxis:UILayoutConstraintAxisHorizontal];
[_titleView setContentCompressionResistancePriority:layoutDefaultHighPriority forAxis:UILayoutConstraintAxisVertical];
[_titleView setContentCompressionResistancePriority:layoutDefaultHighPriority forAxis:UILayoutConstraintAxisHorizontal];
_titleButton.translatesAutoresizingMaskIntoConstraints = NO;
[_titleButton setContentHuggingPriority:layoutDefaultLowPriority forAxis:UILayoutConstraintAxisVertical];
[_titleButton setContentHuggingPriority:layoutDefaultLowPriority forAxis:UILayoutConstraintAxisHorizontal];
[_titleButton setContentCompressionResistancePriority:layoutDefaultHighPriority forAxis:UILayoutConstraintAxisVertical];
[_titleButton setContentCompressionResistancePriority:layoutDefaultHighPriority forAxis:UILayoutConstraintAxisHorizontal];
NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:_titleButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_titleView attribute:NSLayoutAttributeTop multiplier:1 constant:0];
NSLayoutConstraint *bottom = [NSLayoutConstraint constraintWithItem:_titleButton attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:_titleView attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
NSLayoutConstraint *leading = [NSLayoutConstraint constraintWithItem:_titleButton attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:_titleView attribute:NSLayoutAttributeLeading multiplier:1 constant:0];
NSLayoutConstraint *trailing = [NSLayoutConstraint constraintWithItem:_titleButton attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:_titleView attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
[_titleView addConstraints:@[top,bottom,leading,trailing]];
}
else
#endif
{
_titleView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
_titleButton.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
}
self.customView = _titleView;
}
return self;
}
-(void)setTitleFont:(UIFont *)titleFont
{
_titleFont = titleFont;
if (titleFont)
{
_titleButton.titleLabel.font = titleFont;
}
else
{
_titleButton.titleLabel.font = [UIFont systemFontOfSize:13];
}
}
-(void)setTitle:(NSString *)title
{
[super setTitle:title];
[_titleButton setTitle:title forState:UIControlStateNormal];
}
-(void)setTitleColor:(UIColor*)titleColor
{
_titleColor = titleColor;
[_titleButton setTitleColor:_titleColor?:[UIColor lightGrayColor] forState:UIControlStateDisabled];
}
-(void)setSelectableTitleColor:(UIColor*)selectableTitleColor
{
_selectableTitleColor = selectableTitleColor;
[_titleButton setTitleColor:_selectableTitleColor?:[UIColor colorWithRed:0.0 green:0.5 blue:1.0 alpha:1.0] forState:UIControlStateNormal];
}
-(void)setInvocation:(NSInvocation *)invocation
{
[super setInvocation:invocation];
if (invocation.target == nil || invocation.selector == NULL)
{
self.enabled = NO;
_titleButton.enabled = NO;
[_titleButton removeTarget:nil action:NULL forControlEvents:UIControlEventTouchUpInside];
}
else
{
self.enabled = YES;
_titleButton.enabled = YES;
[_titleButton addTarget:invocation.target action:invocation.selector forControlEvents:UIControlEventTouchUpInside];
}
}
-(void)dealloc
{
self.customView = nil;
[_titleButton removeTarget:nil action:NULL forControlEvents:UIControlEventTouchUpInside];
_titleView = nil;
_titleButton = nil;
}
@end
@@ -0,0 +1,60 @@
//
// IQToolbar.h
// 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 "IQTitleBarButtonItem.h"
#import <UIKit/UIToolbar.h>
#import <UIKit/UIDevice.h>
/**
IQToolbar for IQKeyboardManager.
*/
@interface IQToolbar : UIToolbar <UIInputViewAudioFeedback>
/**
Previous bar button of toolbar.
*/
@property(nonnull, nonatomic, strong) IQBarButtonItem *previousBarButton;
/**
Next bar button of toolbar.
*/
@property(nonnull, nonatomic, strong) IQBarButtonItem *nextBarButton;
/**
Title bar button of toolbar.
*/
@property(nonnull, nonatomic, strong, readonly) IQTitleBarButtonItem *titleBarButton;
/**
Done bar button of toolbar.
*/
@property(nonnull, nonatomic, strong) IQBarButtonItem *doneBarButton;
/**
Fixed space bar button of toolbar.
*/
@property(nonnull, nonatomic, strong) IQBarButtonItem *fixedSpaceBarButton;
@end
@@ -0,0 +1,300 @@
//
// IQToolbar.m
// 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 "IQToolbar.h"
#import "IQKeyboardManagerConstantsInternal.h"
#import "IQUIView+Hierarchy.h"
#import <UIKit/UIButton.h>
#import <UIKit/UIAccessibility.h>
#import <UIKit/UIViewController.h>
@interface IQTitleBarButtonItem (PrivateAccessor)
@property(nonatomic, strong) UIButton *titleButton;
@end
@implementation IQToolbar
@synthesize previousBarButton = _previousBarButton;
@synthesize nextBarButton = _nextBarButton;
@synthesize titleBarButton = _titleBarButton;
@synthesize doneBarButton = _doneBarButton;
@synthesize fixedSpaceBarButton = _fixedSpaceBarButton;
+(void)initialize
{
[super initialize];
IQToolbar *appearanceProxy = [self appearance];
NSArray <NSNumber*> *positions = @[@(UIBarPositionAny),@(UIBarPositionBottom),@(UIBarPositionTop),@(UIBarPositionTopAttached)];
for (NSNumber *position in positions)
{
UIToolbarPosition toolbarPosition = [position unsignedIntegerValue];
[appearanceProxy setBackgroundImage:nil forToolbarPosition:toolbarPosition barMetrics:UIBarMetricsDefault];
[appearanceProxy setShadowImage:nil forToolbarPosition:toolbarPosition];
}
}
-(void)initialize
{
[self sizeToFit];
self.autoresizingMask = UIViewAutoresizingFlexibleWidth;// | UIViewAutoresizingFlexibleHeight;
self.translucent = YES;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self initialize];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self)
{
[self initialize];
}
return self;
}
-(void)dealloc
{
self.items = nil;
_previousBarButton = nil;
_nextBarButton = nil;
_titleBarButton = nil;
_doneBarButton = nil;
_fixedSpaceBarButton = nil;
}
-(IQBarButtonItem *)previousBarButton
{
if (_previousBarButton == nil)
{
_previousBarButton = [[IQBarButtonItem alloc] initWithImage:nil style:UIBarButtonItemStylePlain target:nil action:nil];
_previousBarButton.accessibilityLabel = @"Toolbar Previous Button";
}
return _previousBarButton;
}
-(IQBarButtonItem *)nextBarButton
{
if (_nextBarButton == nil)
{
_nextBarButton = [[IQBarButtonItem alloc] initWithImage:nil style:UIBarButtonItemStylePlain target:nil action:nil];
_nextBarButton.accessibilityLabel = @"Toolbar Next Button";
}
return _nextBarButton;
}
-(IQTitleBarButtonItem *)titleBarButton
{
if (_titleBarButton == nil)
{
_titleBarButton = [[IQTitleBarButtonItem alloc] initWithTitle:nil];
_titleBarButton.accessibilityLabel = @"Toolbar Title Button";
}
return _titleBarButton;
}
-(IQBarButtonItem *)doneBarButton
{
if (_doneBarButton == nil)
{
_doneBarButton = [[IQBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:nil action:nil];
_doneBarButton.accessibilityLabel = @"Toolbar Done Button";
}
return _doneBarButton;
}
-(IQBarButtonItem *)fixedSpaceBarButton
{
if (_fixedSpaceBarButton == nil)
{
_fixedSpaceBarButton = [[IQBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
#ifdef __IPHONE_11_0
if (@available(iOS 10.0, *))
#else
if (IQ_IS_IOS10_OR_GREATER)
#endif
{
[_fixedSpaceBarButton setWidth:6];
}
else
{
[_fixedSpaceBarButton setWidth:20];
}
}
return _fixedSpaceBarButton;
}
-(CGSize)sizeThatFits:(CGSize)size
{
CGSize sizeThatFit = [super sizeThatFits:size];
sizeThatFit.height = 44;
return sizeThatFit;
}
-(void)setBarStyle:(UIBarStyle)barStyle
{
[super setBarStyle:barStyle];
if (self.titleBarButton.selectableTitleColor == nil)
{
if (barStyle == UIBarStyleDefault)
{
[self.titleBarButton.titleButton setTitleColor:[UIColor colorWithRed:0.0 green:0.5 blue:1.0 alpha:1.0] forState:UIControlStateNormal];
}
else
{
[self.titleBarButton.titleButton setTitleColor:[UIColor yellowColor] forState:UIControlStateNormal];
}
}
}
-(void)setTintColor:(UIColor *)tintColor
{
[super setTintColor:tintColor];
for (UIBarButtonItem *item in self.items)
{
[item setTintColor:tintColor];
}
}
-(void)layoutSubviews
{
[super layoutSubviews];
//If running on Xcode9 (iOS11) only then we'll validate for iOS version, otherwise for older versions of Xcode (iOS10 and below) we'll just execute the tweak
#ifdef __IPHONE_11_0
if (@available(iOS 11.0, *)) {}
else
#endif
{
CGRect leftRect = CGRectNull;
CGRect rightRect = CGRectNull;
BOOL isTitleBarButtonFound = NO;
NSArray<UIView*> *subviews = [self.subviews sortedArrayUsingComparator:^NSComparisonResult(UIView *view1, UIView *view2) {
CGFloat x1 = CGRectGetMinX(view1.frame);
CGFloat y1 = CGRectGetMinY(view1.frame);
CGFloat x2 = CGRectGetMinX(view2.frame);
CGFloat y2 = CGRectGetMinY(view2.frame);
if (x1 < x2) return NSOrderedAscending;
else if (x1 > x2) return NSOrderedDescending;
//Else both y are same so checking for x positions
else if (y1 < y2) return NSOrderedAscending;
else if (y1 > y2) return NSOrderedDescending;
else return NSOrderedSame;
}];
for (UIView *barButtonItemView in subviews)
{
if (isTitleBarButtonFound == YES)
{
rightRect = barButtonItemView.frame;
break;
}
else if (barButtonItemView == self.titleBarButton.customView)
{
isTitleBarButtonFound = YES;
}
//If it's UIToolbarButton or UIToolbarTextButton (which actually UIBarButtonItem)
else if ([barButtonItemView isKindOfClass:[UIControl class]])
{
leftRect = barButtonItemView.frame;
}
}
CGFloat titleMargin = 16;
CGFloat maxWidth = CGRectGetWidth(self.frame) - titleMargin*2 - (CGRectIsNull(leftRect)?0:CGRectGetMaxX(leftRect)) - (CGRectIsNull(rightRect)?0:CGRectGetWidth(self.frame)-CGRectGetMinX(rightRect));
CGFloat maxHeight = self.frame.size.height;
CGSize sizeThatFits = [self.titleBarButton.customView sizeThatFits:CGSizeMake(maxWidth, maxHeight)];
CGRect titleRect = CGRectZero;
CGFloat x = titleMargin;
if (sizeThatFits.width > 0 && sizeThatFits.height > 0)
{
CGFloat width = MIN(sizeThatFits.width, maxWidth);
CGFloat height = MIN(sizeThatFits.height, maxHeight);
if (CGRectIsNull(leftRect) == false)
{
x = titleMargin + CGRectGetMaxX(leftRect) + ((maxWidth - width)/2);
}
CGFloat y = (maxHeight - height)/2;
titleRect = CGRectMake(x, y, width, height);
}
else
{
if (CGRectIsNull(leftRect) == false)
{
x = titleMargin + CGRectGetMaxX(leftRect);
}
CGFloat width = CGRectGetWidth(self.frame) - titleMargin*2 - (CGRectIsNull(leftRect)?0:CGRectGetMaxX(leftRect)) - (CGRectIsNull(rightRect)?0:CGRectGetWidth(self.frame)-CGRectGetMinX(rightRect));
titleRect = CGRectMake(x, 0, width, maxHeight);
}
self.titleBarButton.customView.frame = titleRect;
}
}
#pragma mark - UIInputViewAudioFeedback delegate
- (BOOL) enableInputClicksWhenVisible
{
return YES;
}
@end
@@ -0,0 +1,150 @@
//
// IQUIView+IQKeyboardToolbar.h
// 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 "IQToolbar.h"
#import <UIKit/UIView.h>
#import <UIKit/UIImage.h>
@interface IQBarButtonItemConfiguration : NSObject
-(instancetype)initWithBarButtonSystemItem:(UIBarButtonSystemItem)barButtonSystemItem action:(nullable SEL)action;
-(instancetype)initWithImage:(nonnull UIImage*)image action:(nullable SEL)action;
-(instancetype)initWithTitle:(nonnull NSString*)title action:(nullable SEL)action;
@property (readonly, nonatomic) UIBarButtonSystemItem barButtonSystemItem; //System Item to be used to instantiate bar button
@property (readonly, nonatomic, nullable) UIImage *image; //Image to show on bar button item if it's not a system item.
@property (readonly, nonatomic, nullable) NSString *title; //Title to show on bar button item if it's not a system item.
@property (readonly, nonatomic, nullable) SEL action; //action for bar button item. Usually 'doneAction:(IQBarButtonItem*)item'.
@end
@interface UIImage (IQKeyboardToolbarNextPreviousImage)
+(UIImage*)keyboardPreviousiOS9Image;
+(UIImage*)keyboardNextiOS9Image;
+(UIImage*)keyboardPreviousiOS10Image;
+(UIImage*)keyboardNextiOS10Image;
+(UIImage*)keyboardPreviousImage;
+(UIImage*)keyboardNextImage;
@end
/**
UIView category methods to add IQToolbar on UIKeyboard.
*/
@interface UIView (IQToolbarAddition)
///-------------------------
/// @name Toolbar Title
///-------------------------
/**
IQToolbar references for better customization control.
*/
@property (readonly, nonatomic, nonnull) IQToolbar *keyboardToolbar;
/**
If `shouldHideToolbarPlaceholder` is YES, then title will not be added to the toolbar. Default to NO.
*/
@property (assign, nonatomic) BOOL shouldHideToolbarPlaceholder;
@property (assign, nonatomic) BOOL shouldHidePlaceholderText __attribute__((deprecated("This is renamed to `shouldHideToolbarPlaceholder` for more clear naming.")));
/**
`toolbarPlaceholder` to override default `placeholder` text when drawing text on toolbar.
*/
@property (nullable, strong, nonatomic) NSString* toolbarPlaceholder;
@property (nullable, strong, nonatomic) NSString* placeholderText __attribute__((deprecated("This is renamed to `toolbarPlaceholder` for more clear naming.")));
/**
`drawingToolbarPlaceholder` will be actual text used to draw on toolbar. This would either `placeholder` or `toolbarPlaceholder`.
*/
@property (nullable, strong, nonatomic, readonly) NSString* drawingToolbarPlaceholder;
@property (nullable, strong, nonatomic, readonly) NSString* drawingPlaceholderText __attribute__((deprecated("This is renamed to `drawingToolbarPlaceholder` for more clear naming.")));
///-------------
/// MARK: Common
///-------------
- (void)addKeyboardToolbarWithTarget:(nullable id)target titleText:(nullable NSString*)titleText rightBarButtonConfiguration:(nullable IQBarButtonItemConfiguration*)rightBarButtonConfiguration previousBarButtonConfiguration:(nullable IQBarButtonItemConfiguration*)previousBarButtonConfiguration nextBarButtonConfiguration:(nullable IQBarButtonItemConfiguration*)nextBarButtonConfiguration;
///------------
/// @name Done
///------------
- (void)addDoneOnKeyboardWithTarget:(nullable id)target action:(nullable SEL)action;
- (void)addDoneOnKeyboardWithTarget:(nullable id)target action:(nullable SEL)action shouldShowPlaceholder:(BOOL)shouldShowPlaceholder;
- (void)addDoneOnKeyboardWithTarget:(nullable id)target action:(nullable SEL)action titleText:(nullable NSString*)titleText;
///------------
/// @name Right
///------------
- (void)addRightButtonOnKeyboardWithText:(nullable NSString*)text target:(nullable id)target action:(nullable SEL)action;
- (void)addRightButtonOnKeyboardWithText:(nullable NSString*)text target:(nullable id)target action:(nullable SEL)action shouldShowPlaceholder:(BOOL)shouldShowPlaceholder;
- (void)addRightButtonOnKeyboardWithText:(nullable NSString*)text target:(nullable id)target action:(nullable SEL)action titleText:(nullable NSString*)titleText;
- (void)addRightButtonOnKeyboardWithImage:(nullable UIImage*)image target:(nullable id)target action:(nullable SEL)action;
- (void)addRightButtonOnKeyboardWithImage:(nullable UIImage*)image target:(nullable id)target action:(nullable SEL)action shouldShowPlaceholder:(BOOL)shouldShowPlaceholder;
- (void)addRightButtonOnKeyboardWithImage:(nullable UIImage*)image target:(nullable id)target action:(nullable SEL)action titleText:(nullable NSString*)titleText;
///------------------
/// @name Cancel/Done
///------------------
- (void)addCancelDoneOnKeyboardWithTarget:(nullable id)target cancelAction:(nullable SEL)cancelAction doneAction:(nullable SEL)doneAction;
- (void)addCancelDoneOnKeyboardWithTarget:(nullable id)target cancelAction:(nullable SEL)cancelAction doneAction:(nullable SEL)doneAction shouldShowPlaceholder:(BOOL)shouldShowPlaceholder;
- (void)addCancelDoneOnKeyboardWithTarget:(nullable id)target cancelAction:(nullable SEL)cancelAction doneAction:(nullable SEL)doneAction titleText:(nullable NSString*)titleText;
///-----------------
/// @name Right/Left
///-----------------
- (void)addLeftRightOnKeyboardWithTarget:(nullable id)target leftButtonTitle:(nullable NSString*)leftButtonTitle rightButtonTitle:(nullable NSString*)rightButtonTitle leftButtonAction:(nullable SEL)leftButtonAction rightButtonAction:(nullable SEL)rightButtonAction;
- (void)addLeftRightOnKeyboardWithTarget:(nullable id)target leftButtonTitle:(nullable NSString*)leftButtonTitle rightButtonTitle:(nullable NSString*)rightButtonTitle leftButtonAction:(nullable SEL)leftButtonAction rightButtonAction:(nullable SEL)rightButtonAction shouldShowPlaceholder:(BOOL)shouldShowPlaceholder;
- (void)addLeftRightOnKeyboardWithTarget:(nullable id)target leftButtonTitle:(nullable NSString*)leftButtonTitle rightButtonTitle:(nullable NSString*)rightButtonTitle leftButtonAction:(nullable SEL)leftButtonAction rightButtonAction:(nullable SEL)rightButtonAction titleText:(nullable NSString*)titleText;
///-------------------------
/// @name Previous/Next/Done
///-------------------------
- (void)addPreviousNextDoneOnKeyboardWithTarget:(nullable id)target previousAction:(nullable SEL)previousAction nextAction:(nullable SEL)nextAction doneAction:(nullable SEL)doneAction;
- (void)addPreviousNextDoneOnKeyboardWithTarget:(nullable id)target previousAction:(nullable SEL)previousAction nextAction:(nullable SEL)nextAction doneAction:(nullable SEL)doneAction shouldShowPlaceholder:(BOOL)shouldShowPlaceholder;
- (void)addPreviousNextDoneOnKeyboardWithTarget:(nullable id)target previousAction:(nullable SEL)previousAction nextAction:(nullable SEL)nextAction doneAction:(nullable SEL)doneAction titleText:(nullable NSString*)titleText;
///--------------------------
/// @name Previous/Next/Right
///--------------------------
- (void)addPreviousNextRightOnKeyboardWithTarget:(nullable id)target rightButtonTitle:(nullable NSString*)rightButtonTitle previousAction:(nullable SEL)previousAction nextAction:(nullable SEL)nextAction rightButtonAction:(nullable SEL)rightButtonAction;
- (void)addPreviousNextRightOnKeyboardWithTarget:(nullable id)target rightButtonTitle:(nullable NSString*)rightButtonTitle previousAction:(nullable SEL)previousAction nextAction:(nullable SEL)nextAction rightButtonAction:(nullable SEL)rightButtonAction shouldShowPlaceholder:(BOOL)shouldShowPlaceholder;
- (void)addPreviousNextRightOnKeyboardWithTarget:(nullable id)target rightButtonTitle:(nullable NSString*)rightButtonTitle previousAction:(nullable SEL)previousAction nextAction:(nullable SEL)nextAction rightButtonAction:(nullable SEL)rightButtonAction titleText:(nullable NSString*)titleText;
- (void)addPreviousNextRightOnKeyboardWithTarget:(nullable id)target rightButtonImage:(nullable UIImage*)rightButtonImage previousAction:(nullable SEL)previousAction nextAction:(nullable SEL)nextAction rightButtonAction:(nullable SEL)rightButtonAction;
- (void)addPreviousNextRightOnKeyboardWithTarget:(nullable id)target rightButtonImage:(nullable UIImage*)rightButtonImage previousAction:(nullable SEL)previousAction nextAction:(nullable SEL)nextAction rightButtonAction:(nullable SEL)rightButtonAction shouldShowPlaceholder:(BOOL)shouldShowPlaceholder;
- (void)addPreviousNextRightOnKeyboardWithTarget:(nullable id)target rightButtonImage:(nullable UIImage*)rightButtonImage previousAction:(nullable SEL)previousAction nextAction:(nullable SEL)nextAction rightButtonAction:(nullable SEL)rightButtonAction titleText:(nullable NSString*)titleText;
@end
@@ -0,0 +1,676 @@
//
// IQUIView+IQKeyboardToolbar.m
// 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 "IQUIView+IQKeyboardToolbar.h"
#import "IQKeyboardManagerConstantsInternal.h"
#import "IQKeyboardManager.h"
#import <objc/runtime.h>
#import <UIKit/UIImage.h>
#import <UIKit/UILabel.h>
#import <UIKit/UIAccessibility.h>
@implementation IQBarButtonItemConfiguration
-(instancetype)initWithBarButtonSystemItem:(UIBarButtonSystemItem)barButtonSystemItem action:(SEL)action
{
self = [super init];
if (self) {
_barButtonSystemItem = barButtonSystemItem;
_action = action;
}
return self;
}
-(instancetype)initWithImage:(UIImage *)image action:(SEL)action
{
self = [super init];
if (self) {
_image = image;
_action = action;
}
return self;
}
-(instancetype)initWithTitle:(NSString *)title action:(SEL)action
{
self = [super init];
if (self) {
_title = title;
_action = action;
}
return self;
}
@end
@implementation UIImage (IQKeyboardToolbarNextPreviousImage)
+(UIImage*)keyboardPreviousiOS9Image
{
static UIImage *keyboardPreviousiOS9Image = nil;
if (keyboardPreviousiOS9Image == nil)
{
// Get the top level "bundle" which may actually be the framework
NSBundle *mainBundle = [NSBundle bundleForClass:[IQKeyboardManager class]];
// Check to see if the resource bundle exists inside the top level bundle
NSBundle *resourcesBundle = [NSBundle bundleWithPath:[mainBundle pathForResource:@"IQKeyboardManager" ofType:@"bundle"]];
if (resourcesBundle == nil) {
resourcesBundle = mainBundle;
}
keyboardPreviousiOS9Image = [UIImage imageNamed:@"IQButtonBarArrowLeft" inBundle:resourcesBundle compatibleWithTraitCollection:nil];;
//Support for RTL languages like Arabic, Persia etc... (Bug ID: #448)
#ifdef __IPHONE_11_0
if (@available(iOS 9.0, *)) {
#endif
if ([UIImage instancesRespondToSelector:@selector(imageFlippedForRightToLeftLayoutDirection)])
{
keyboardPreviousiOS9Image = [keyboardPreviousiOS9Image imageFlippedForRightToLeftLayoutDirection];
}
#ifdef __IPHONE_11_0
}
#endif
}
return keyboardPreviousiOS9Image;
}
+(UIImage*)keyboardNextiOS9Image
{
static UIImage *keyboardNextiOS9Image = nil;
if (keyboardNextiOS9Image == nil)
{
// Get the top level "bundle" which may actually be the framework
NSBundle *mainBundle = [NSBundle bundleForClass:[IQKeyboardManager class]];
// Check to see if the resource bundle exists inside the top level bundle
NSBundle *resourcesBundle = [NSBundle bundleWithPath:[mainBundle pathForResource:@"IQKeyboardManager" ofType:@"bundle"]];
if (resourcesBundle == nil) {
resourcesBundle = mainBundle;
}
keyboardNextiOS9Image = [UIImage imageNamed:@"IQButtonBarArrowRight" inBundle:resourcesBundle compatibleWithTraitCollection:nil];
//Support for RTL languages like Arabic, Persia etc... (Bug ID: #448)
#ifdef __IPHONE_11_0
if (@available(iOS 9.0, *)) {
#endif
if ([UIImage instancesRespondToSelector:@selector(imageFlippedForRightToLeftLayoutDirection)])
{
keyboardNextiOS9Image = [keyboardNextiOS9Image imageFlippedForRightToLeftLayoutDirection];
}
#ifdef __IPHONE_11_0
}
#endif
}
return keyboardNextiOS9Image;
}
+(UIImage*)keyboardPreviousiOS10Image
{
static UIImage *keyboardPreviousiOS10Image = nil;
if (keyboardPreviousiOS10Image == nil)
{
// Get the top level "bundle" which may actually be the framework
NSBundle *mainBundle = [NSBundle bundleForClass:[IQKeyboardManager class]];
// Check to see if the resource bundle exists inside the top level bundle
NSBundle *resourcesBundle = [NSBundle bundleWithPath:[mainBundle pathForResource:@"IQKeyboardManager" ofType:@"bundle"]];
if (resourcesBundle == nil) {
resourcesBundle = mainBundle;
}
keyboardPreviousiOS10Image = [UIImage imageNamed:@"IQButtonBarArrowUp" inBundle:resourcesBundle compatibleWithTraitCollection:nil];
//Support for RTL languages like Arabic, Persia etc... (Bug ID: #448)
#ifdef __IPHONE_11_0
if (@available(iOS 9.0, *)) {
#endif
if ([UIImage instancesRespondToSelector:@selector(imageFlippedForRightToLeftLayoutDirection)])
{
keyboardPreviousiOS10Image = [keyboardPreviousiOS10Image imageFlippedForRightToLeftLayoutDirection];
}
#ifdef __IPHONE_11_0
}
#endif
}
return keyboardPreviousiOS10Image;
}
+(UIImage*)keyboardNextiOS10Image
{
static UIImage *keyboardNextiOS10Image = nil;
if (keyboardNextiOS10Image == nil)
{
// Get the top level "bundle" which may actually be the framework
NSBundle *mainBundle = [NSBundle bundleForClass:[IQKeyboardManager class]];
// Check to see if the resource bundle exists inside the top level bundle
NSBundle *resourcesBundle = [NSBundle bundleWithPath:[mainBundle pathForResource:@"IQKeyboardManager" ofType:@"bundle"]];
if (resourcesBundle == nil) {
resourcesBundle = mainBundle;
}
keyboardNextiOS10Image = [UIImage imageNamed:@"IQButtonBarArrowDown" inBundle:resourcesBundle compatibleWithTraitCollection:nil];
//Support for RTL languages like Arabic, Persia etc... (Bug ID: #448)
#ifdef __IPHONE_11_0
if (@available(iOS 9.0, *)) {
#endif
if ([UIImage instancesRespondToSelector:@selector(imageFlippedForRightToLeftLayoutDirection)])
{
keyboardNextiOS10Image = [keyboardNextiOS10Image imageFlippedForRightToLeftLayoutDirection];
}
#ifdef __IPHONE_11_0
}
#endif
}
return keyboardNextiOS10Image;
}
+(UIImage*)keyboardPreviousImage
{
#ifdef __IPHONE_11_0
if (@available(iOS 10.0, *))
#else
if (IQ_IS_IOS10_OR_GREATER)
#endif
{
return [UIImage keyboardPreviousiOS10Image];
}
else
{
return [UIImage keyboardPreviousiOS9Image];
}
}
+(UIImage*)keyboardNextImage
{
#ifdef __IPHONE_11_0
if (@available(iOS 10.0, *))
#else
if (IQ_IS_IOS10_OR_GREATER)
#endif
{
return [UIImage keyboardNextiOS9Image];
}
else
{
return [UIImage keyboardPreviousiOS9Image];
}
}
@end
/*UIKeyboardToolbar Category implementation*/
@implementation UIView (IQToolbarAddition)
-(IQToolbar *)keyboardToolbar
{
IQToolbar *keyboardToolbar = nil;
if ([[self inputAccessoryView] isKindOfClass:[IQToolbar class]])
{
keyboardToolbar = [self inputAccessoryView];
}
else
{
keyboardToolbar = objc_getAssociatedObject(self, @selector(keyboardToolbar));
if (keyboardToolbar == nil)
{
keyboardToolbar = [[IQToolbar alloc] init];
objc_setAssociatedObject(self, @selector(keyboardToolbar), keyboardToolbar, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
}
return keyboardToolbar;
}
-(void)setShouldHideToolbarPlaceholder:(BOOL)shouldHideToolbarPlaceholder
{
objc_setAssociatedObject(self, @selector(shouldHideToolbarPlaceholder), @(shouldHideToolbarPlaceholder), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
self.keyboardToolbar.titleBarButton.title = self.drawingToolbarPlaceholder;
}
-(BOOL)shouldHideToolbarPlaceholder
{
NSNumber *shouldHideToolbarPlaceholder = objc_getAssociatedObject(self, @selector(shouldHideToolbarPlaceholder));
return [shouldHideToolbarPlaceholder boolValue];
}
-(void)setShouldHidePlaceholderText:(BOOL)shouldHidePlaceholderText
{
[self setShouldHideToolbarPlaceholder:shouldHidePlaceholderText];
}
-(BOOL)shouldHidePlaceholderText
{
return [self shouldHideToolbarPlaceholder];
}
-(void)setToolbarPlaceholder:(NSString *)toolbarPlaceholder
{
objc_setAssociatedObject(self, @selector(toolbarPlaceholder), toolbarPlaceholder, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
self.keyboardToolbar.titleBarButton.title = self.drawingToolbarPlaceholder;
}
-(NSString *)toolbarPlaceholder
{
NSString *toolbarPlaceholder = objc_getAssociatedObject(self, @selector(toolbarPlaceholder));
return toolbarPlaceholder;
}
-(void)setPlaceholderText:(NSString*)placeholderText
{
[self setToolbarPlaceholder:placeholderText];
}
-(NSString*)placeholderText
{
return [self toolbarPlaceholder];
}
-(NSString *)drawingToolbarPlaceholder
{
if (self.shouldHideToolbarPlaceholder)
{
return nil;
}
else if (self.toolbarPlaceholder.length != 0)
{
return self.toolbarPlaceholder;
}
else if ([self respondsToSelector:@selector(placeholder)])
{
return [(UITextField*)self placeholder];
}
else
{
return nil;
}
}
-(NSString*)drawingPlaceholderText
{
return [self drawingToolbarPlaceholder];
}
#pragma mark - Private helper
+(IQBarButtonItem*)flexibleBarButtonItem
{
static IQBarButtonItem *nilButton = nil;
if (nilButton == nil)
{
nilButton = [[IQBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
}
return nilButton;
}
#pragma mark - Common
- (void)addKeyboardToolbarWithTarget:(id)target titleText:(NSString*)titleText rightBarButtonConfiguration:(IQBarButtonItemConfiguration*)rightBarButtonConfiguration previousBarButtonConfiguration:(IQBarButtonItemConfiguration*)previousBarButtonConfiguration nextBarButtonConfiguration:(IQBarButtonItemConfiguration*)nextBarButtonConfiguration
{
//If can't set InputAccessoryView. Then return
if (![self respondsToSelector:@selector(setInputAccessoryView:)]) return;
// Creating a toolBar for phoneNumber keyboard
IQToolbar *toolbar = self.keyboardToolbar;
NSMutableArray<UIBarButtonItem*> *items = [[NSMutableArray alloc] init];
if(previousBarButtonConfiguration)
{
IQBarButtonItem *prev = toolbar.previousBarButton;
if (prev.isSystemItem == NO && (previousBarButtonConfiguration.image || previousBarButtonConfiguration.title))
{
prev.title = previousBarButtonConfiguration.title;
prev.image = previousBarButtonConfiguration.image;
prev.target = target;
prev.action = previousBarButtonConfiguration.action;
}
else if (previousBarButtonConfiguration.image)
{
prev = [[IQBarButtonItem alloc] initWithImage:previousBarButtonConfiguration.image style:UIBarButtonItemStylePlain target:target action:previousBarButtonConfiguration.action];
prev.invocation = toolbar.previousBarButton.invocation;
prev.accessibilityLabel = toolbar.previousBarButton.accessibilityLabel;
toolbar.previousBarButton = prev;
}
else if (previousBarButtonConfiguration.title)
{
prev = [[IQBarButtonItem alloc] initWithTitle:previousBarButtonConfiguration.title style:UIBarButtonItemStylePlain target:target action:previousBarButtonConfiguration.action];
prev.invocation = toolbar.previousBarButton.invocation;
prev.accessibilityLabel = toolbar.previousBarButton.accessibilityLabel;
toolbar.previousBarButton = prev;
}
else
{
prev = [[IQBarButtonItem alloc] initWithBarButtonSystemItem:previousBarButtonConfiguration.barButtonSystemItem target:target action:previousBarButtonConfiguration.action];
prev.invocation = toolbar.previousBarButton.invocation;
prev.accessibilityLabel = toolbar.previousBarButton.accessibilityLabel;
toolbar.previousBarButton = prev;
}
[items addObject:prev];
}
if (previousBarButtonConfiguration != nil && nextBarButtonConfiguration != nil)
{
[items addObject:toolbar.fixedSpaceBarButton];
}
if(nextBarButtonConfiguration)
{
IQBarButtonItem *next = toolbar.nextBarButton;
if (next.isSystemItem == NO && (nextBarButtonConfiguration.image || nextBarButtonConfiguration.title))
{
next.title = nextBarButtonConfiguration.title;
next.image = nextBarButtonConfiguration.image;
next.target = target;
next.action = nextBarButtonConfiguration.action;
}
else if (nextBarButtonConfiguration.image)
{
next = [[IQBarButtonItem alloc] initWithImage:nextBarButtonConfiguration.image style:UIBarButtonItemStylePlain target:target action:nextBarButtonConfiguration.action];
next.invocation = toolbar.nextBarButton.invocation;
next.accessibilityLabel = toolbar.nextBarButton.accessibilityLabel;
toolbar.nextBarButton = next;
}
else if (nextBarButtonConfiguration.title)
{
next = [[IQBarButtonItem alloc] initWithTitle:nextBarButtonConfiguration.title style:UIBarButtonItemStylePlain target:target action:nextBarButtonConfiguration.action];
next.invocation = toolbar.nextBarButton.invocation;
next.accessibilityLabel = toolbar.nextBarButton.accessibilityLabel;
toolbar.nextBarButton = next;
}
else
{
next = [[IQBarButtonItem alloc] initWithBarButtonSystemItem:nextBarButtonConfiguration.barButtonSystemItem target:target action:nextBarButtonConfiguration.action];
next.invocation = toolbar.nextBarButton.invocation;
next.accessibilityLabel = toolbar.nextBarButton.accessibilityLabel;
toolbar.nextBarButton = next;
}
[items addObject:next];
}
//Title
{
//Flexible space
[items addObject:[[self class] flexibleBarButtonItem]];
//Title button
toolbar.titleBarButton.title = titleText;
#ifdef __IPHONE_11_0
if (@available(iOS 11.0, *)) {}
else
#endif
{
toolbar.titleBarButton.customView.frame = CGRectZero;
}
[items addObject:toolbar.titleBarButton];
//Flexible space
[items addObject:[[self class] flexibleBarButtonItem]];
}
if(rightBarButtonConfiguration)
{
IQBarButtonItem *done = toolbar.doneBarButton;
if (done.isSystemItem == NO && (rightBarButtonConfiguration.image || rightBarButtonConfiguration.title))
{
done.title = rightBarButtonConfiguration.title;
done.image = rightBarButtonConfiguration.image;
done.target = target;
done.action = rightBarButtonConfiguration.action;
}
else if (rightBarButtonConfiguration.image)
{
done = [[IQBarButtonItem alloc] initWithImage:rightBarButtonConfiguration.image style:UIBarButtonItemStylePlain target:target action:rightBarButtonConfiguration.action];
done.invocation = toolbar.doneBarButton.invocation;
done.accessibilityLabel = toolbar.doneBarButton.accessibilityLabel;
toolbar.doneBarButton = done;
}
else if (rightBarButtonConfiguration.title)
{
done = [[IQBarButtonItem alloc] initWithTitle:rightBarButtonConfiguration.title style:UIBarButtonItemStylePlain target:target action:rightBarButtonConfiguration.action];
done.invocation = toolbar.doneBarButton.invocation;
done.accessibilityLabel = toolbar.doneBarButton.accessibilityLabel;
toolbar.doneBarButton = done;
}
else
{
done = [[IQBarButtonItem alloc] initWithBarButtonSystemItem:rightBarButtonConfiguration.barButtonSystemItem target:target action:rightBarButtonConfiguration.action];
done.invocation = toolbar.doneBarButton.invocation;
done.accessibilityLabel = toolbar.doneBarButton.accessibilityLabel;
toolbar.doneBarButton = done;
}
[items addObject:done];
}
// Adding button to toolBar.
[toolbar setItems:items];
// Setting toolbar to keyboard.
[(UITextField*)self setInputAccessoryView:toolbar];
if ([self respondsToSelector:@selector(keyboardAppearance)])
{
switch ([(UITextField*)self keyboardAppearance])
{
case UIKeyboardAppearanceDark: toolbar.barStyle = UIBarStyleBlack; break;
default: toolbar.barStyle = UIBarStyleDefault; break;
}
}
}
#pragma mark - Right
- (void)addRightButtonOnKeyboardWithText:(NSString*)text target:(id)target action:(SEL)action
{
[self addRightButtonOnKeyboardWithText:text target:target action:action titleText:nil];
}
- (void)addRightButtonOnKeyboardWithText:(NSString*)text target:(id)target action:(SEL)action shouldShowPlaceholder:(BOOL)shouldShowPlaceholder
{
[self addRightButtonOnKeyboardWithText:text target:target action:action titleText:(shouldShowPlaceholder?[self drawingToolbarPlaceholder]:nil)];
}
- (void)addRightButtonOnKeyboardWithText:(NSString*)text target:(id)target action:(SEL)action titleText:(NSString*)titleText
{
IQBarButtonItemConfiguration *rightConfiguration = [[IQBarButtonItemConfiguration alloc] initWithTitle:text action:action];
[self addKeyboardToolbarWithTarget:target titleText:titleText rightBarButtonConfiguration:rightConfiguration previousBarButtonConfiguration:nil nextBarButtonConfiguration:nil];
}
- (void)addRightButtonOnKeyboardWithImage:(UIImage*)image target:(id)target action:(SEL)action
{
[self addRightButtonOnKeyboardWithImage:image target:target action:action titleText:nil];
}
- (void)addRightButtonOnKeyboardWithImage:(UIImage*)image target:(id)target action:(SEL)action shouldShowPlaceholder:(BOOL)shouldShowPlaceholder
{
[self addRightButtonOnKeyboardWithImage:image target:target action:action titleText:(shouldShowPlaceholder?[self drawingToolbarPlaceholder]:nil)];
}
- (void)addRightButtonOnKeyboardWithImage:(UIImage*)image target:(id)target action:(SEL)action titleText:(NSString*)titleText
{
IQBarButtonItemConfiguration *rightConfiguration = [[IQBarButtonItemConfiguration alloc] initWithImage:image action:action];
[self addKeyboardToolbarWithTarget:target titleText:titleText rightBarButtonConfiguration:rightConfiguration previousBarButtonConfiguration:nil nextBarButtonConfiguration:nil];
}
-(void)addDoneOnKeyboardWithTarget:(id)target action:(SEL)action
{
[self addDoneOnKeyboardWithTarget:target action:action titleText:nil];
}
-(void)addDoneOnKeyboardWithTarget:(id)target action:(SEL)action shouldShowPlaceholder:(BOOL)shouldShowPlaceholder
{
[self addDoneOnKeyboardWithTarget:target action:action titleText:(shouldShowPlaceholder?[self drawingToolbarPlaceholder]:nil)];
}
- (void)addDoneOnKeyboardWithTarget:(id)target action:(SEL)action titleText:(NSString*)titleText
{
IQBarButtonItemConfiguration *rightConfiguration = [[IQBarButtonItemConfiguration alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone action:action];
[self addKeyboardToolbarWithTarget:target titleText:titleText rightBarButtonConfiguration:rightConfiguration previousBarButtonConfiguration:nil nextBarButtonConfiguration:nil];
}
- (void)addLeftRightOnKeyboardWithTarget:(id)target leftButtonTitle:(NSString*)leftTitle rightButtonTitle:(NSString*)rightTitle leftButtonAction:(SEL)leftAction rightButtonAction:(SEL)rightAction
{
[self addLeftRightOnKeyboardWithTarget:target leftButtonTitle:leftTitle rightButtonTitle:rightTitle leftButtonAction:leftAction rightButtonAction:rightAction titleText:nil];
}
- (void)addLeftRightOnKeyboardWithTarget:(id)target leftButtonTitle:(NSString*)leftTitle rightButtonTitle:(NSString*)rightTitle leftButtonAction:(SEL)leftAction rightButtonAction:(SEL)rightAction shouldShowPlaceholder:(BOOL)shouldShowPlaceholder
{
[self addLeftRightOnKeyboardWithTarget:target leftButtonTitle:leftTitle rightButtonTitle:rightTitle leftButtonAction:leftAction rightButtonAction:rightAction titleText:(shouldShowPlaceholder?[self drawingToolbarPlaceholder]:nil)];
}
- (void)addLeftRightOnKeyboardWithTarget:(id)target leftButtonTitle:(NSString*)leftTitle rightButtonTitle:(NSString*)rightTitle leftButtonAction:(SEL)leftAction rightButtonAction:(SEL)rightAction titleText:(NSString*)titleText
{
IQBarButtonItemConfiguration *leftConfiguration = [[IQBarButtonItemConfiguration alloc] initWithTitle:leftTitle action:leftAction];
IQBarButtonItemConfiguration *rightConfiguration = [[IQBarButtonItemConfiguration alloc] initWithTitle:rightTitle action:rightAction];
[self addKeyboardToolbarWithTarget:target titleText:titleText rightBarButtonConfiguration:rightConfiguration previousBarButtonConfiguration:leftConfiguration nextBarButtonConfiguration:nil];
}
-(void)addCancelDoneOnKeyboardWithTarget:(id)target cancelAction:(SEL)cancelAction doneAction:(SEL)doneAction
{
[self addCancelDoneOnKeyboardWithTarget:target cancelAction:cancelAction doneAction:doneAction titleText:nil];
}
-(void)addCancelDoneOnKeyboardWithTarget:(id)target cancelAction:(SEL)cancelAction doneAction:(SEL)doneAction shouldShowPlaceholder:(BOOL)shouldShowPlaceholder
{
[self addCancelDoneOnKeyboardWithTarget:target cancelAction:cancelAction doneAction:doneAction titleText:(shouldShowPlaceholder?[self drawingToolbarPlaceholder]:nil)];
}
- (void)addCancelDoneOnKeyboardWithTarget:(id)target cancelAction:(SEL)cancelAction doneAction:(SEL)doneAction titleText:(NSString*)titleText
{
IQBarButtonItemConfiguration *leftConfiguration = [[IQBarButtonItemConfiguration alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel action:cancelAction];
IQBarButtonItemConfiguration *rightConfiguration = [[IQBarButtonItemConfiguration alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone action:doneAction];
[self addKeyboardToolbarWithTarget:target titleText:titleText rightBarButtonConfiguration:rightConfiguration previousBarButtonConfiguration:leftConfiguration nextBarButtonConfiguration:nil];
}
-(void)addPreviousNextDoneOnKeyboardWithTarget:(id)target previousAction:(SEL)previousAction nextAction:(SEL)nextAction doneAction:(SEL)doneAction
{
[self addPreviousNextDoneOnKeyboardWithTarget:target previousAction:previousAction nextAction:nextAction doneAction:doneAction titleText:nil];
}
-(void)addPreviousNextDoneOnKeyboardWithTarget:(id)target previousAction:(SEL)previousAction nextAction:(SEL)nextAction doneAction:(SEL)doneAction shouldShowPlaceholder:(BOOL)shouldShowPlaceholder
{
[self addPreviousNextDoneOnKeyboardWithTarget:target previousAction:previousAction nextAction:nextAction doneAction:doneAction titleText:(shouldShowPlaceholder?[self drawingToolbarPlaceholder]:nil)];
}
- (void)addPreviousNextDoneOnKeyboardWithTarget:(id)target previousAction:(SEL)previousAction nextAction:(SEL)nextAction doneAction:(SEL)doneAction titleText:(NSString*)titleText
{
IQBarButtonItemConfiguration *previousConfiguration = [[IQBarButtonItemConfiguration alloc] initWithImage:[UIImage keyboardPreviousImage] action:previousAction];
IQBarButtonItemConfiguration *nextConfiguration = [[IQBarButtonItemConfiguration alloc] initWithImage:[UIImage keyboardNextImage] action:nextAction];
IQBarButtonItemConfiguration *rightConfiguration = [[IQBarButtonItemConfiguration alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone action:doneAction];
[self addKeyboardToolbarWithTarget:target titleText:titleText rightBarButtonConfiguration:rightConfiguration previousBarButtonConfiguration:previousConfiguration nextBarButtonConfiguration:nextConfiguration];
}
- (void)addPreviousNextRightOnKeyboardWithTarget:(nullable id)target rightButtonImage:(nullable UIImage*)rightButtonImage previousAction:(nullable SEL)previousAction nextAction:(nullable SEL)nextAction rightButtonAction:(nullable SEL)rightButtonAction
{
[self addPreviousNextRightOnKeyboardWithTarget:target rightButtonImage:rightButtonImage previousAction:previousAction nextAction:nextAction rightButtonAction:rightButtonAction titleText:nil];
}
- (void)addPreviousNextRightOnKeyboardWithTarget:(nullable id)target rightButtonImage:(nullable UIImage*)rightButtonImage previousAction:(nullable SEL)previousAction nextAction:(nullable SEL)nextAction rightButtonAction:(nullable SEL)rightButtonAction shouldShowPlaceholder:(BOOL)shouldShowPlaceholder
{
[self addPreviousNextRightOnKeyboardWithTarget:target rightButtonImage:rightButtonImage previousAction:previousAction nextAction:nextAction rightButtonAction:rightButtonAction titleText:(shouldShowPlaceholder?[self drawingToolbarPlaceholder]:nil)];
}
- (void)addPreviousNextRightOnKeyboardWithTarget:(id)target rightButtonImage:(UIImage*)rightButtonImage previousAction:(SEL)previousAction nextAction:(SEL)nextAction rightButtonAction:(SEL)rightButtonAction titleText:(NSString*)titleText
{
IQBarButtonItemConfiguration *previousConfiguration = [[IQBarButtonItemConfiguration alloc] initWithImage:[UIImage keyboardPreviousImage] action:previousAction];
IQBarButtonItemConfiguration *nextConfiguration = [[IQBarButtonItemConfiguration alloc] initWithImage:[UIImage keyboardNextImage] action:nextAction];
IQBarButtonItemConfiguration *rightConfiguration = [[IQBarButtonItemConfiguration alloc] initWithImage:rightButtonImage action:rightButtonAction];
[self addKeyboardToolbarWithTarget:target titleText:titleText rightBarButtonConfiguration:rightConfiguration previousBarButtonConfiguration:previousConfiguration nextBarButtonConfiguration:nextConfiguration];
}
- (void)addPreviousNextRightOnKeyboardWithTarget:(id)target rightButtonTitle:(NSString*)rightButtonTitle previousAction:(SEL)previousAction nextAction:(SEL)nextAction rightButtonAction:(SEL)rightButtonAction
{
[self addPreviousNextRightOnKeyboardWithTarget:target rightButtonTitle:rightButtonTitle previousAction:previousAction nextAction:nextAction rightButtonAction:rightButtonAction titleText:nil];
}
- (void)addPreviousNextRightOnKeyboardWithTarget:(id)target rightButtonTitle:(NSString*)rightButtonTitle previousAction:(SEL)previousAction nextAction:(SEL)nextAction rightButtonAction:(SEL)rightButtonAction shouldShowPlaceholder:(BOOL)shouldShowPlaceholder
{
[self addPreviousNextRightOnKeyboardWithTarget:target rightButtonTitle:rightButtonTitle previousAction:previousAction nextAction:nextAction rightButtonAction:rightButtonAction titleText:(shouldShowPlaceholder?[self drawingToolbarPlaceholder]:nil)];
}
- (void)addPreviousNextRightOnKeyboardWithTarget:(id)target rightButtonTitle:(NSString*)rightButtonTitle previousAction:(SEL)previousAction nextAction:(SEL)nextAction rightButtonAction:(SEL)rightButtonAction titleText:(NSString*)titleText
{
IQBarButtonItemConfiguration *previousConfiguration = [[IQBarButtonItemConfiguration alloc] initWithImage:[UIImage keyboardPreviousImage] action:previousAction];
IQBarButtonItemConfiguration *nextConfiguration = [[IQBarButtonItemConfiguration alloc] initWithImage:[UIImage keyboardNextImage] action:nextAction];
IQBarButtonItemConfiguration *rightConfiguration = [[IQBarButtonItemConfiguration alloc] initWithTitle:rightButtonTitle action:rightButtonAction];
[self addKeyboardToolbarWithTarget:target titleText:titleText rightBarButtonConfiguration:rightConfiguration previousBarButtonConfiguration:previousConfiguration nextBarButtonConfiguration:nextConfiguration];
}
@end
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

+21
View File
@@ -0,0 +1,21 @@
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.
+210
View File
@@ -0,0 +1,210 @@
<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)
Often while developing an app, We ran into an issues where the iPhone keyboard slide up and cover the `UITextField/UITextView`. `IQKeyboardManager` allows you to prevent issues of the keyboard sliding up and cover `UITextField/UITextView` without needing you to enter any code and no additional setup required. 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. There are also nice optional features allowing you to customize the distance from the text field, add the next/previous done button as a keyboard UIToolbar, play sounds when the user navigations 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 wants to handle UITextField/UITextView with IQKeyboardManager then you're totally going on 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 implemented their custom solution to handle UITextField/UITextView thought 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 8.2.1 |
| IQKeyboardManagerSwift | Swift | iOS 8.0 | Xcode 8.2.1 |
| Demo Project | | | Xcode 9.3 |
**Note**
- 3.3.7 is the last iOS 7 supported version.
#### Swift versions support
| Swift | Xcode | IQKeyboardManagerSwift |
|-------------------|-------|------------------------|
| 4.2, 4.0, 3.2, 3.0| 10.0 | >= 6.0.4 |
| 4.0, 3.2, 3.0 | 9.0 | 5.0.0 |
| 3.1 | 8.3 | 4.0.10 |
| 3.0 (3.0.2) | 8.2 | 4.0.8 |
| 2.2 or 2.3 | 7.3 | 4.0.5 |
| 2.1.1 | 7.2 | 4.0.0 |
| 2.1 | 7.2 | 3.3.7 |
| 2.0 | 7.0 | 3.3.3.1 |
| 1.2 | 6.3 | 3.3.1 |
| 1.0 | 6.0 | 3.3.2 |
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
pod 'IQKeyboardManager', '3.3.7' #iOS7
```
***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 4.2, 4.0, 3.2, 3.0 (Xcode 9)*
```ruby
pod 'IQKeyboardManagerSwift'
```
*Or you can choose version you need based on Swift support table from [Requirements](README.md#requirements)*
```ruby
pod 'IQKeyboardManagerSwift', '5.0.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: [NSObject: AnyObject]?) -> 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, specify it in 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 according to 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: [NSObject: AnyObject]?) -> Bool {
IQKeyboardManager.shared.enable = true
return true
}
}
```
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 see [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