New file |
| | |
| | | // |
| | | // 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 |