// // 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 @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