//
|
// UIViewController+CYLTabBarControllerExtention.m
|
// CYLTabBarController
|
//
|
// v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 16/2/26.
|
// Copyright © 2016年 https://github.com/ChenYilong .All rights reserved.
|
//
|
|
#import "UIViewController+CYLTabBarControllerExtention.h"
|
#import "CYLTabBarController.h"
|
#import <objc/runtime.h>
|
|
@implementation UIViewController (CYLTabBarControllerExtention)
|
|
#pragma mark -
|
#pragma mark - public Methods
|
|
- (UIViewController *)cyl_popSelectTabBarChildViewControllerAtIndex:(NSUInteger)index {
|
UIViewController *viewController = [self cyl_getViewControllerInsteadOfNavigationController];
|
[viewController checkTabBarChildControllerValidityAtIndex:index];
|
[viewController.navigationController popToRootViewControllerAnimated:NO];
|
CYLTabBarController *tabBarController = [viewController cyl_tabBarController];
|
tabBarController.selectedIndex = index;
|
UIViewController *selectedTabBarChildViewController = tabBarController.selectedViewController;
|
return [selectedTabBarChildViewController cyl_getViewControllerInsteadOfNavigationController];
|
}
|
|
- (void)cyl_popSelectTabBarChildViewControllerAtIndex:(NSUInteger)index
|
completion:(CYLPopSelectTabBarChildViewControllerCompletion)completion {
|
UIViewController *selectedTabBarChildViewController = [self cyl_popSelectTabBarChildViewControllerAtIndex:index];
|
dispatch_async(dispatch_get_main_queue(), ^{
|
!completion ?: completion(selectedTabBarChildViewController);
|
});
|
}
|
|
- (UIViewController *)cyl_popSelectTabBarChildViewControllerForClassType:(Class)classType {
|
CYLTabBarController *tabBarController = [[self cyl_getViewControllerInsteadOfNavigationController] cyl_tabBarController];
|
NSArray *viewControllers = tabBarController.viewControllers;
|
NSInteger atIndex = [self cyl_indexForClassType:classType inViewControllers:viewControllers];
|
return [self cyl_popSelectTabBarChildViewControllerAtIndex:atIndex];
|
}
|
|
- (void)cyl_popSelectTabBarChildViewControllerForClassType:(Class)classType
|
completion:(CYLPopSelectTabBarChildViewControllerCompletion)completion {
|
UIViewController *selectedTabBarChildViewController = [self cyl_popSelectTabBarChildViewControllerForClassType:classType];
|
dispatch_async(dispatch_get_main_queue(), ^{
|
!completion ?: completion(selectedTabBarChildViewController);
|
});
|
}
|
|
- (void)cyl_pushOrPopToViewController:(UIViewController *)viewController
|
animated:(BOOL)animated
|
callback:(CYLPushOrPopCallback)callback {
|
if (!callback) {
|
[self.navigationController pushViewController:viewController animated:animated];
|
return;
|
}
|
|
void (^popSelectTabBarChildViewControllerCallback)(BOOL shouldPopSelectTabBarChildViewController, NSUInteger index) = ^(BOOL shouldPopSelectTabBarChildViewController, NSUInteger index) {
|
if (shouldPopSelectTabBarChildViewController) {
|
[self cyl_popSelectTabBarChildViewControllerAtIndex:index completion:^(__kindof UIViewController *selectedTabBarChildViewController) {
|
[selectedTabBarChildViewController.navigationController pushViewController:viewController animated:animated];
|
}];
|
} else {
|
[self.navigationController pushViewController:viewController animated:animated];
|
}
|
};
|
NSArray<__kindof UIViewController *> *otherSameClassTypeViewControllersInCurrentNavigationControllerStack = [self cyl_getOtherSameClassTypeViewControllersInCurrentNavigationControllerStack:viewController];
|
|
CYLPushOrPopCompletionHandler completionHandler = ^(BOOL shouldPop,
|
__kindof UIViewController *viewControllerPopTo,
|
BOOL shouldPopSelectTabBarChildViewController,
|
NSUInteger index
|
) {
|
if (!otherSameClassTypeViewControllersInCurrentNavigationControllerStack || otherSameClassTypeViewControllersInCurrentNavigationControllerStack.count == 0) {
|
shouldPop = NO;
|
}
|
dispatch_async(dispatch_get_main_queue(),^{
|
if (shouldPop) {
|
[self.navigationController popToViewController:viewControllerPopTo animated:animated];
|
return;
|
}
|
popSelectTabBarChildViewControllerCallback(shouldPopSelectTabBarChildViewController, index);
|
});
|
};
|
callback(otherSameClassTypeViewControllersInCurrentNavigationControllerStack, completionHandler);
|
}
|
|
- (void)cyl_pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
|
UIViewController *fromViewController = [self cyl_getViewControllerInsteadOfNavigationController];
|
NSArray *childViewControllers = fromViewController.navigationController.childViewControllers;
|
if (childViewControllers.count > 0) {
|
if ([[childViewControllers lastObject] isKindOfClass:[viewController class]]) {
|
return;
|
}
|
}
|
[fromViewController.navigationController pushViewController:viewController animated:animated];
|
}
|
|
- (UIViewController *)cyl_getViewControllerInsteadOfNavigationController {
|
BOOL isNavigationController = [[self class] isSubclassOfClass:[UINavigationController class]];
|
if (isNavigationController && ((UINavigationController *)self).viewControllers.count > 0) {
|
return ((UINavigationController *)self).viewControllers[0];
|
}
|
return self;
|
}
|
|
#pragma mark - public method
|
|
- (BOOL)cyl_isPlusChildViewController {
|
if (!CYLPlusChildViewController) {
|
return NO;
|
}
|
return (self == CYLPlusChildViewController);
|
}
|
|
- (void)cyl_showTabBadgePoint {
|
if (self.cyl_isPlusChildViewController) {
|
return;
|
}
|
[self.cyl_tabButton cyl_showTabBadgePoint];
|
[[[self cyl_getViewControllerInsteadOfNavigationController] cyl_tabBarController].tabBar layoutIfNeeded];
|
}
|
|
- (void)cyl_removeTabBadgePoint {
|
if (self.cyl_isPlusChildViewController) {
|
return;
|
}
|
[self.cyl_tabButton cyl_removeTabBadgePoint];
|
[[[self cyl_getViewControllerInsteadOfNavigationController] cyl_tabBarController].tabBar layoutIfNeeded];
|
}
|
|
- (BOOL)cyl_isShowTabBadgePoint {
|
if (self.cyl_isPlusChildViewController) {
|
return NO;
|
}
|
return [self.cyl_tabButton cyl_isShowTabBadgePoint];
|
}
|
|
- (void)cyl_setTabBadgePointView:(UIView *)tabBadgePointView {
|
if (self.cyl_isPlusChildViewController) {
|
return;
|
}
|
[self.cyl_tabButton cyl_setTabBadgePointView:tabBadgePointView];
|
}
|
|
- (UIView *)cyl_tabBadgePointView {
|
if (self.cyl_isPlusChildViewController) {
|
return nil;
|
}
|
return [self.cyl_tabButton cyl_tabBadgePointView];;
|
}
|
|
- (void)cyl_setTabBadgePointViewOffset:(UIOffset)tabBadgePointViewOffset {
|
if (self.cyl_isPlusChildViewController) {
|
return;
|
}
|
return [self.cyl_tabButton cyl_setTabBadgePointViewOffset:tabBadgePointViewOffset];
|
}
|
|
//offset如果都是整数,则往右下偏移
|
- (UIOffset)cyl_tabBadgePointViewOffset {
|
if (self.cyl_isPlusChildViewController) {
|
return UIOffsetZero;
|
}
|
return [self.cyl_tabButton cyl_tabBadgePointViewOffset];
|
}
|
|
- (BOOL)cyl_isEmbedInTabBarController {
|
if (self.cyl_tabBarController == nil) {
|
return NO;
|
}
|
if (self.cyl_isPlusChildViewController) {
|
return NO;
|
}
|
BOOL isEmbedInTabBarController = NO;
|
UIViewController *viewControllerInsteadIOfNavigationController = [self cyl_getViewControllerInsteadOfNavigationController];
|
for (NSInteger i = 0; i < self.cyl_tabBarController.viewControllers.count; i++) {
|
UIViewController * vc = self.cyl_tabBarController.viewControllers[i];
|
if ([vc cyl_getViewControllerInsteadOfNavigationController] == viewControllerInsteadIOfNavigationController) {
|
isEmbedInTabBarController = YES;
|
[self cyl_setTabIndex:i];
|
break;
|
}
|
}
|
return isEmbedInTabBarController;
|
}
|
|
- (void)cyl_setTabIndex:(NSInteger)tabIndex {
|
objc_setAssociatedObject(self, @selector(cyl_tabIndex), @(tabIndex), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
}
|
|
- (NSInteger)cyl_tabIndex {
|
if (!self.cyl_isEmbedInTabBarController) {
|
return NSNotFound;
|
}
|
|
id tabIndexObject = objc_getAssociatedObject(self, @selector(cyl_tabIndex));
|
NSInteger tabIndex = [tabIndexObject integerValue];
|
return tabIndex;
|
}
|
|
- (UIControl *)cyl_tabButton {
|
if (!self.cyl_isEmbedInTabBarController) {
|
return nil;
|
}
|
UITabBarItem *tabBarItem;
|
UIControl *control;
|
@try {
|
tabBarItem = self.cyl_tabBarController.tabBar.items[self.cyl_tabIndex];
|
control = [tabBarItem cyl_tabButton];
|
} @catch (NSException *exception) {}
|
return control;
|
}
|
|
- (NSString *)cyl_context {
|
return objc_getAssociatedObject(self, @selector(cyl_context));
|
}
|
|
- (void)cyl_setContext:(NSString *)cyl_context {
|
objc_setAssociatedObject(self, @selector(cyl_context), cyl_context, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
}
|
|
- (BOOL)cyl_plusViewControllerEverAdded {
|
NSNumber *cyl_plusViewControllerEverAddedObject = objc_getAssociatedObject(self, @selector(cyl_plusViewControllerEverAdded));
|
return [cyl_plusViewControllerEverAddedObject boolValue];
|
}
|
|
- (void)cyl_setPlusViewControllerEverAdded:(BOOL)cyl_plusViewControllerEverAdded {
|
NSNumber *cyl_plusViewControllerEverAddedObject = [NSNumber numberWithBool:cyl_plusViewControllerEverAdded];
|
objc_setAssociatedObject(self, @selector(cyl_plusViewControllerEverAdded), cyl_plusViewControllerEverAddedObject, OBJC_ASSOCIATION_ASSIGN);
|
}
|
|
#pragma mark -
|
#pragma mark - Private Methods
|
|
- (NSArray<__kindof UIViewController *> *)cyl_getOtherSameClassTypeViewControllersInCurrentNavigationControllerStack:(UIViewController *)viewController {
|
NSArray *currentNavigationControllerStack = [self.navigationController childViewControllers];
|
if (currentNavigationControllerStack.count < 2) {
|
return nil;
|
}
|
NSMutableArray *mutableArray = [currentNavigationControllerStack mutableCopy];
|
[mutableArray removeObject:self];
|
currentNavigationControllerStack = [mutableArray copy];
|
|
__block NSMutableArray *mutableOtherViewControllersInNavigationControllerStack = [NSMutableArray arrayWithCapacity:currentNavigationControllerStack.count];
|
|
[currentNavigationControllerStack enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
UIViewController *otherViewController = obj;
|
if ([otherViewController isKindOfClass:[viewController class]]) {
|
[mutableOtherViewControllersInNavigationControllerStack addObject:otherViewController];
|
}
|
}];
|
return [mutableOtherViewControllersInNavigationControllerStack copy];
|
}
|
|
- (void)checkTabBarChildControllerValidityAtIndex:(NSUInteger)index {
|
CYLTabBarController *tabBarController = [[self cyl_getViewControllerInsteadOfNavigationController] cyl_tabBarController];
|
@try {
|
UIViewController *viewController;
|
viewController = tabBarController.viewControllers[index];
|
UIButton *plusButton = CYLExternPlusButton;
|
BOOL shouldConfigureSelectionStatus = (CYLPlusChildViewController) && ((index != CYLPlusButtonIndex) && (viewController != CYLPlusChildViewController));
|
if (shouldConfigureSelectionStatus) {
|
plusButton.selected = NO;
|
}
|
} @catch (NSException *exception) {
|
NSString *formatString = @"\n\n\
|
------ BEGIN NSException Log ---------------------------------------------------------------------\n \
|
class name: %@ \n \
|
------line: %@ \n \
|
----reason: The Class Type or the index or its NavigationController you pass in method `-cyl_popSelectTabBarChildViewControllerAtIndex` or `-cyl_popSelectTabBarChildViewControllerForClassType` is not the item of CYLTabBarViewController \n \
|
------ END ---------------------------------------------------------------------------------------\n\n";
|
NSString *reason = [NSString stringWithFormat:formatString,
|
@(__PRETTY_FUNCTION__),
|
@(__LINE__)];
|
@throw [NSException exceptionWithName:NSGenericException
|
reason:reason
|
userInfo:nil];
|
}
|
}
|
|
- (NSInteger)cyl_indexForClassType:(Class)classType inViewControllers:(NSArray *)viewControllers {
|
__block NSInteger atIndex = NSNotFound;
|
[viewControllers enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
UIViewController *obj_ = [obj cyl_getViewControllerInsteadOfNavigationController];
|
if ([obj_ isKindOfClass:classType]) {
|
atIndex = idx;
|
*stop = YES;
|
return;
|
}
|
}];
|
return atIndex;
|
}
|
|
@end
|