diff --git a/CYLTabBarController.podspec b/CYLTabBarController.podspec index 70ba1311..a5cb2d83 100644 --- a/CYLTabBarController.podspec +++ b/CYLTabBarController.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "CYLTabBarController" - s.version = "1.10.1" + s.version = "1.11.0" s.summary = "Highly customizable tabBar and tabBarController for iOS" s.description = "CYLTabBarController is iPad and iPhone compatible. Supports landscape and portrait orientations and can be used inside UINavigationController." s.homepage = "https://github.com/ChenYilong/CYLTabBarController" diff --git a/CYLTabBarController.xcodeproj/project.pbxproj b/CYLTabBarController.xcodeproj/project.pbxproj index af1dc14f..7d6149dc 100644 --- a/CYLTabBarController.xcodeproj/project.pbxproj +++ b/CYLTabBarController.xcodeproj/project.pbxproj @@ -15,8 +15,6 @@ 9A1559DE1CB6D56500CAB1AF /* CYLDetailsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A1559D51CB6D56500CAB1AF /* CYLDetailsViewController.m */; }; 9A1559DF1CB6D56500CAB1AF /* CYLSameCityViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A1559D71CB6D56500CAB1AF /* CYLSameCityViewController.m */; }; 9A1559E41CB6EB1F00CAB1AF /* CYLPlusButtonSubclass.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A1559E31CB6EB1F00CAB1AF /* CYLPlusButtonSubclass.m */; }; - 9AB37B221DC869E1000782F2 /* README.md in Sources */ = {isa = PBXBuildFile; fileRef = 9AB37B211DC869E1000782F2 /* README.md */; }; - 9AB37B241DC869F2000782F2 /* issue_template.md in Sources */ = {isa = PBXBuildFile; fileRef = 9AB37B231DC869F2000782F2 /* issue_template.md */; }; 9AE667131C800085001DED12 /* UIViewController+CYLTabBarControllerExtention.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AE667121C800085001DED12 /* UIViewController+CYLTabBarControllerExtention.m */; }; 9AE942E71BDC933E00354519 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9AE942CB1BDC933E00354519 /* LaunchScreen.xib */; }; 9AE942E81BDC933E00354519 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9AE942CD1BDC933E00354519 /* Main.storyboard */; }; @@ -45,8 +43,6 @@ 9A1559E21CB6EB1F00CAB1AF /* CYLPlusButtonSubclass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYLPlusButtonSubclass.h; sourceTree = ""; }; 9A1559E31CB6EB1F00CAB1AF /* CYLPlusButtonSubclass.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYLPlusButtonSubclass.m; sourceTree = ""; }; 9A5B29111D3475BC009E1BEE /* CYLConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CYLConstants.h; sourceTree = ""; }; - 9AB37B211DC869E1000782F2 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; - 9AB37B231DC869F2000782F2 /* issue_template.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = issue_template.md; path = .github/issue_template.md; sourceTree = SOURCE_ROOT; }; 9AE667111C800085001DED12 /* UIViewController+CYLTabBarControllerExtention.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+CYLTabBarControllerExtention.h"; sourceTree = ""; }; 9AE667121C800085001DED12 /* UIViewController+CYLTabBarControllerExtention.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+CYLTabBarControllerExtention.m"; sourceTree = ""; }; 9AE942741BDC91B800354519 /* CYLTabBarController.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CYLTabBarController.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -182,8 +178,6 @@ 9AE942E31BDC933E00354519 /* Images.xcassets */, 9AE942E41BDC933E00354519 /* Info.plist */, 9AE942E51BDC933E00354519 /* main.m */, - 9AB37B211DC869E1000782F2 /* README.md */, - 9AB37B231DC869F2000782F2 /* issue_template.md */, ); path = Example; sourceTree = ""; @@ -294,9 +288,7 @@ 9AE942F91BDC937F00354519 /* CYLPlusButton.m in Sources */, 9A1559C81CB6D4D300CAB1AF /* AppDelegate.m in Sources */, 9A1559DD1CB6D56500CAB1AF /* CYLMineViewController.m in Sources */, - 9AB37B221DC869E1000782F2 /* README.md in Sources */, 9AE942FB1BDC937F00354519 /* CYLTabBarController.m in Sources */, - 9AB37B241DC869F2000782F2 /* issue_template.md in Sources */, 9AE942F11BDC933E00354519 /* main.m in Sources */, 9AE942FA1BDC937F00354519 /* CYLTabBar.m in Sources */, ); diff --git a/CYLTabBarController.xcodeproj/project.xcworkspace/xcuserdata/chenyilong.xcuserdatad/UserInterfaceState.xcuserstate b/CYLTabBarController.xcodeproj/project.xcworkspace/xcuserdata/chenyilong.xcuserdatad/UserInterfaceState.xcuserstate index e51da80c..1a6145e0 100644 Binary files a/CYLTabBarController.xcodeproj/project.xcworkspace/xcuserdata/chenyilong.xcuserdatad/UserInterfaceState.xcuserstate and b/CYLTabBarController.xcodeproj/project.xcworkspace/xcuserdata/chenyilong.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/CYLTabBarController.xcodeproj/xcuserdata/chenyilong.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/CYLTabBarController.xcodeproj/xcuserdata/chenyilong.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 026225e1..762feda3 100644 --- a/CYLTabBarController.xcodeproj/xcuserdata/chenyilong.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/CYLTabBarController.xcodeproj/xcuserdata/chenyilong.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -20,11 +20,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "Example/CYLTabBarControllerConfig.m" - timestampString = "505586344.471096" + timestampString = "518244204.694397" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "202" - endingLineNumber = "202" + startingLineNumber = "207" + endingLineNumber = "207" landmarkName = "+imageWithColor:size:" landmarkType = "7"> @@ -36,27 +36,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "CYLTabBarController/CYLTabBarController.m" - timestampString = "483515235.928086" + timestampString = "518268313.152042" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "70" - endingLineNumber = "70" - landmarkName = "-supportedInterfaceOrientations" - landmarkType = "7"> - - - - @@ -68,11 +52,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "CYLTabBarController/CYLTabBarController.m" - timestampString = "483515235.928086" + timestampString = "518268313.152042" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "171" - endingLineNumber = "171" + startingLineNumber = "206" + endingLineNumber = "206" landmarkName = "-setViewControllers:" landmarkType = "7"> @@ -84,11 +68,11 @@ moduleName = "CYLTabBarController" usesParentBreakpointCondition = "Yes" urlString = "file:///Users/chenyilong/Documents/Git/%E7%AC%AC%E4%B8%89%E6%96%B9/CYLTabBarController/CYLTabBarController/CYLTabBarController.m" - timestampString = "505585873.800656" + timestampString = "518268577.264112" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "171" - endingLineNumber = "171" + startingLineNumber = "206" + endingLineNumber = "206" offsetFromSymbolStart = "1380"> @@ -144,31 +128,15 @@ - - - - @@ -180,27 +148,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "CYLTabBarController/CYLTabBarController.m" - timestampString = "505585386.994016" - startingColumnNumber = "9223372036854775807" - endingColumnNumber = "9223372036854775807" - startingLineNumber = "282" - endingLineNumber = "282" - landmarkName = "-updateSelectionStatusIfNeededForTabBarController:shouldSelectViewController:" - landmarkType = "7"> - - - - diff --git a/CYLTabBarController/CYLPlusButton.h b/CYLTabBarController/CYLPlusButton.h index 5a8364b3..977ac394 100644 --- a/CYLTabBarController/CYLPlusButton.h +++ b/CYLTabBarController/CYLPlusButton.h @@ -47,7 +47,7 @@ + (CGFloat)constantOfPlusButtonCenterYOffsetForTabBarHeight:(CGFloat)tabBarHeight; /*! - * 实现该方法后,能让 PlusButton 的点击效果与跟点击其他 UITabBarButton 效果一样,跳转到该方法指定的 UIViewController 。 + * 实现该方法后,能让 PlusButton 的点击效果与跟点击其他 TabBar 按钮效果一样,跳转到该方法指定的 UIViewController 。 * @attention 必须同时实现 `+indexOfPlusButtonInTabBar` 来指定 PlusButton 的位置。 * @return 指定 PlusButton 点击后跳转的 UIViewController。 * diff --git a/CYLTabBarController/CYLTabBar.m b/CYLTabBarController/CYLTabBar.m index e1767bef..de9724f5 100644 --- a/CYLTabBarController/CYLTabBar.m +++ b/CYLTabBarController/CYLTabBar.m @@ -60,8 +60,7 @@ - (instancetype)sharedInit { */ - (NSArray *)tabBarButtonArray { if (_tabBarButtonArray == nil) { - NSArray *tabBarButtonArray = [[NSArray alloc] init]; - _tabBarButtonArray = tabBarButtonArray; + _tabBarButtonArray = @[]; } return _tabBarButtonArray; } @@ -251,19 +250,19 @@ - (void)setupSwappableImageViewDefaultOffset:(UIView *)tabBarButton { * Capturing touches on a subview outside the frame of its superview. */ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { + //1. 边界情况:不能响应点击事件 + BOOL canNotResponseEvent = self.hidden || (self.alpha <= 0.01f) || (self.userInteractionEnabled == NO); if (canNotResponseEvent) { return nil; } - if (!CYLExternPlusButton && ![self pointInside:point withEvent:event]) { - return nil; - } + + //2. 优先处理 PlusButton (包括其突出的部分)、TabBarItems 未凸出的部分 + //这一步主要是在处理只有两个 TabBarItems 的场景。 + if (CYLExternPlusButton) { CGRect plusButtonFrame = self.plusButton.frame; BOOL isInPlusButtonFrame = CGRectContainsPoint(plusButtonFrame, point); - if (!isInPlusButtonFrame && (point.y < 0) ) { - return nil; - } if (isInPlusButtonFrame) { return CYLExternPlusButton; } @@ -275,10 +274,26 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { for (NSUInteger index = 0; index < tabBarButtons.count; index++) { UIView *selectedTabBarButton = tabBarButtons[index]; CGRect selectedTabBarButtonFrame = selectedTabBarButton.frame; - if (CGRectContainsPoint(selectedTabBarButtonFrame, point)) { + BOOL isTabBarButtonFrame = CGRectContainsPoint(selectedTabBarButtonFrame, point);\ + if (isTabBarButtonFrame) { return selectedTabBarButton; } } + + //3. 最后处理 TabBarItems 凸出的部分、添加到 TabBar 上的自定义视图、点击到 TabBar 上的空白区域 + + UIView *result = [super hitTest:point withEvent:event]; + if (result) { + return result; + } + + for (UIView *subview in self.subviews.reverseObjectEnumerator) { + CGPoint subPoint = [subview convertPoint:point fromView:self]; + result = [subview hitTest:subPoint withEvent:event]; + if (result) { + return result; + } + } return nil; } diff --git a/CYLTabBarController/CYLTabBarController.h b/CYLTabBarController/CYLTabBarController.h index cd1c9d5b..11a2f36f 100644 --- a/CYLTabBarController/CYLTabBarController.h +++ b/CYLTabBarController/CYLTabBarController.h @@ -17,7 +17,18 @@ FOUNDATION_EXTERN NSUInteger CYLPlusButtonIndex; FOUNDATION_EXTERN CGFloat CYLPlusButtonWidth; FOUNDATION_EXTERN CGFloat CYLTabBarItemWidth; -@interface CYLTabBarController : UITabBarController +@protocol CYLTabBarControllerDelegate + +/*! + * @param tabBarController The tab bar controller containing viewController. + * @param control Selected UIControl in TabBar. + * @attention If PlusButton also add an action, then this delegate method will not be invoked when the PlusButton is selected. + */ +- (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control; + +@end + +@interface CYLTabBarController : UITabBarController /*! * An array of the root view controllers displayed by the tab bar interface. @@ -38,17 +49,29 @@ FOUNDATION_EXTERN CGFloat CYLTabBarItemWidth; * To set both UIBarItem image view attributes in the tabBar, * default is UIEdgeInsetsZero. */ -@property (nonatomic, readwrite, assign) UIEdgeInsets imageInsets; +@property (nonatomic, readonly, assign) UIEdgeInsets imageInsets; /*! * To set both UIBarItem label text attributes in the tabBar, * use the following to tweak the relative position of the label within the tab button (for handling visual centering corrections if needed because of custom text attributes) */ -@property (nonatomic, readwrite, assign) UIOffset titlePositionAdjustment; +@property (nonatomic, readonly, assign) UIOffset titlePositionAdjustment; + +- (instancetype)initWithViewControllers:(NSArray *)viewControllers + tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes; + ++ (instancetype)tabBarControllerWithViewControllers:(NSArray *)viewControllers + tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes; -- (instancetype)initWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes; +- (instancetype)initWithViewControllers:(NSArray *)viewControllers + tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes + imageInsets:(UIEdgeInsets)imageInsets + titlePositionAdjustment:(UIOffset)titlePositionAdjustment; -+ (instancetype)tabBarControllerWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes; ++ (instancetype)tabBarControllerWithViewControllers:(NSArray *)viewControllers + tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes + imageInsets:(UIEdgeInsets)imageInsets + titlePositionAdjustment:(UIOffset)titlePositionAdjustment; - (void)updateSelectionStatusIfNeededForTabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController; @@ -68,12 +91,12 @@ FOUNDATION_EXTERN CGFloat CYLTabBarItemWidth; @end -@interface NSObject (CYLTabBarController) +@interface NSObject (CYLTabBarControllerReferenceExtension) /*! * If `self` is kind of `UIViewController`, this method will return the nearest ancestor in the view controller hierarchy that is a tab bar controller. If `self` is not kind of `UIViewController`, it will return the `rootViewController` of the `rootWindow` as long as you have set the `CYLTabBarController` as the `rootViewController`. Otherwise return nil. (read-only) */ -@property (nonatomic, readonly) CYLTabBarController *cyl_tabBarController; +@property (nonatomic, setter=cyl_setTabBarController:) CYLTabBarController *cyl_tabBarController; @end diff --git a/CYLTabBarController/CYLTabBarController.m b/CYLTabBarController/CYLTabBarController.m index bc29818c..e0f2919e 100644 --- a/CYLTabBarController/CYLTabBarController.m +++ b/CYLTabBarController/CYLTabBarController.m @@ -9,6 +9,7 @@ #import "CYLTabBarController.h" #import "CYLTabBar.h" #import +#import "UIViewController+CYLTabBarControllerExtention.h" NSString *const CYLTabBarItemTitle = @"CYLTabBarItemTitle"; NSString *const CYLTabBarItemImage = @"CYLTabBarItemImage"; @@ -20,12 +21,6 @@ NSString *const CYLTabBarItemWidthDidChangeNotification = @"CYLTabBarItemWidthDidChangeNotification"; static void * const CYLSwappableImageViewDefaultOffsetContext = (void*)&CYLSwappableImageViewDefaultOffsetContext; -@interface NSObject (CYLTabBarControllerItemInternal) - -- (void)cyl_setTabBarController:(CYLTabBarController *)tabBarController; - -@end - @interface CYLTabBarController () @property (nonatomic, assign, getter=isObservingSwappableImageViewDefaultOffset) BOOL observingSwappableImageViewDefaultOffset; @@ -47,12 +42,23 @@ - (void)viewDidLoad { [self.tabBar addObserver:self forKeyPath:@"swappableImageViewDefaultOffset" options:NSKeyValueObservingOptionNew context:CYLSwappableImageViewDefaultOffsetContext]; self.observingSwappableImageViewDefaultOffset = YES; } - self.delegate = self; + } //Fix issue #93 - (void)viewDidLayoutSubviews { [self.tabBar layoutSubviews]; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + UITabBar *tabBar = self.tabBar; + for (UIControl *control in tabBar.subviews) { + if ([control isKindOfClass:[UIControl class]]) { + SEL actin = @selector(didSelectControl:); + [control addTarget:self action:actin forControlEvents:UIControlEventTouchUpInside]; + } + } + }); + } - (void)viewWillLayoutSubviews { @@ -89,15 +95,44 @@ - (void)dealloc { #pragma mark - public Methods - (instancetype)initWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes { + return [self initWithViewControllers:viewControllers + tabBarItemsAttributes:tabBarItemsAttributes + imageInsets:UIEdgeInsetsZero + titlePositionAdjustment:UIOffsetZero]; +} + +- (instancetype)initWithViewControllers:(NSArray *)viewControllers + tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes + imageInsets:(UIEdgeInsets)imageInsets + titlePositionAdjustment:(UIOffset)titlePositionAdjustment { if (self = [super init]) { + _imageInsets = imageInsets; + _titlePositionAdjustment = titlePositionAdjustment; _tabBarItemsAttributes = tabBarItemsAttributes; self.viewControllers = viewControllers; + if (CYLPlusChildViewController) { + self.delegate = self; + } } return self; } + ++ (instancetype)tabBarControllerWithViewControllers:(NSArray *)viewControllers + tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes + imageInsets:(UIEdgeInsets)imageInsets + titlePositionAdjustment:(UIOffset)titlePositionAdjustment { + return [[self alloc] initWithViewControllers:viewControllers + tabBarItemsAttributes:tabBarItemsAttributes + imageInsets:imageInsets + titlePositionAdjustment:titlePositionAdjustment]; +} + + (instancetype)tabBarControllerWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes { - return [[self alloc] initWithViewControllers:viewControllers tabBarItemsAttributes:tabBarItemsAttributes]; + return [self tabBarControllerWithViewControllers:viewControllers + tabBarItemsAttributes:tabBarItemsAttributes + imageInsets:UIEdgeInsetsZero + titlePositionAdjustment:UIOffsetZero]; } + (BOOL)havePlusButton { @@ -292,20 +327,28 @@ - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectView return YES; } -@end +- (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control { + +} + +- (void)didSelectControl:(UIControl *)control { + SEL actin = @selector(tabBarController:didSelectControl:); + if ([self.delegate respondsToSelector:actin]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + [self.delegate performSelector:actin withObject:self withObject:control]; +#pragma clang diagnostic pop + } +} -#pragma mark - NSObject+CYLTabBarControllerItem +@end -@implementation NSObject (CYLTabBarControllerItemInternal) +@implementation NSObject (CYLTabBarControllerReferenceExtension) - (void)cyl_setTabBarController:(CYLTabBarController *)tabBarController { objc_setAssociatedObject(self, @selector(cyl_tabBarController), tabBarController, OBJC_ASSOCIATION_ASSIGN); } -@end - -@implementation NSObject (CYLTabBarController) - - (CYLTabBarController *)cyl_tabBarController { CYLTabBarController *tabBarController = objc_getAssociatedObject(self, @selector(cyl_tabBarController)); if (tabBarController) { @@ -317,7 +360,8 @@ - (CYLTabBarController *)cyl_tabBarController { } id delegate = ((id)[[UIApplication sharedApplication] delegate]); UIWindow *window = delegate.window; - if ([window.rootViewController isKindOfClass:[CYLTabBarController class]]) { + UIViewController *rootViewController = [window.rootViewController cyl_getViewControllerInsteadIOfNavigationController];; + if ([rootViewController isKindOfClass:[CYLTabBarController class]]) { tabBarController = (CYLTabBarController *)window.rootViewController; } return tabBarController; diff --git a/Example/AppDelegate.m b/Example/AppDelegate.m index 0f1d98aa..c324499a 100644 --- a/Example/AppDelegate.m +++ b/Example/AppDelegate.m @@ -10,7 +10,7 @@ #import "CYLTabBarControllerConfig.h" #import "CYLPlusButtonSubclass.h" -@interface AppDelegate () +@interface AppDelegate () @end @@ -23,6 +23,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [CYLPlusButtonSubclass registerPlusButton]; CYLTabBarControllerConfig *tabBarControllerConfig = [[CYLTabBarControllerConfig alloc] init]; [self.window setRootViewController:tabBarControllerConfig.tabBarController]; + tabBarControllerConfig.tabBarController.delegate = self; [self.window makeKeyAndVisible]; [self customizeInterface]; return YES; @@ -64,4 +65,60 @@ - (void)setUpNavigationBarAppearance { [navigationBarAppearance setTitleTextAttributes:textAttributes]; } + +#pragma mark - delegate + +- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController { + [[self cyl_tabBarController] updateSelectionStatusIfNeededForTabBarController:tabBarController shouldSelectViewController:viewController]; + return YES; +} + +- (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control { + UIView *animationView; + NSString *button = [NSString stringWithFormat:@"UIT%@arB%@", @"abB", @"utton"]; + // 如果 PlusButton 也添加了点击事件,那么点击 PlusButton 后不会触发该代理方法。 + if ([control isKindOfClass:[CYLExternPlusButton class]]) { + UIButton *button = CYLExternPlusButton; + animationView = button.imageView; + + } else if ([control isKindOfClass:NSClassFromString(button)]) { + NSString *imageView = [NSString stringWithFormat:@"UITabB%@pp%@", @"arSwa", @"ableImageView"]; + for (UIView *subView in control.subviews) { + if ([subView isKindOfClass:NSClassFromString(imageView)]) { + animationView = subView; + } + } + } + + if ([self cyl_tabBarController].selectedIndex % 2 == 0) { + [self addScaleAnimationOnView:animationView]; + } else { + [self addRotateAnimationOnView:animationView]; + } +} + +//缩放动画 +- (void)addScaleAnimationOnView:(UIView *)animationView { + //需要实现的帧动画,这里根据需求自定义 + CAKeyframeAnimation *animation = [CAKeyframeAnimation animation]; + animation.keyPath = @"transform.scale"; + animation.values = @[@1.0,@1.3,@0.9,@1.15,@0.95,@1.02,@1.0]; + animation.duration = 1; + animation.calculationMode = kCAAnimationCubic; + [animationView.layer addAnimation:animation forKey:nil]; +} + +//旋转动画 +- (void)addRotateAnimationOnView:(UIView *)animationView { + [UIView animateWithDuration:0.32 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ + animationView.layer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0); + } completion:nil]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [UIView animateWithDuration:0.70 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0.2 options:UIViewAnimationOptionCurveEaseOut animations:^{ + animationView.layer.transform = CATransform3DMakeRotation(2 * M_PI, 0, 1, 0); + } completion:nil]; + }); +} + @end diff --git a/Example/CYLTabBarControllerConfig.m b/Example/CYLTabBarControllerConfig.m index e854dd0d..b10ccbee 100644 --- a/Example/CYLTabBarControllerConfig.m +++ b/Example/CYLTabBarControllerConfig.m @@ -27,7 +27,7 @@ - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)ani #import "CYLMineViewController.h" #import "CYLSameCityViewController.h" -@interface CYLTabBarControllerConfig () +@interface CYLTabBarControllerConfig () @property (nonatomic, readwrite, strong) CYLTabBarController *tabBarController; @@ -42,8 +42,19 @@ @implementation CYLTabBarControllerConfig */ - (CYLTabBarController *)tabBarController { if (_tabBarController == nil) { + /** + * 以下两行代码目的在于手动设置让TabBarItem只显示图标,不显示文字,并让图标垂直居中。 + * 等效于在 `-tabBarItemsAttributesForController` 方法中不传 `CYLTabBarItemTitle` 字段。 + * 更推荐后一种做法。 + */ + UIEdgeInsets imageInsets = UIEdgeInsetsZero;//UIEdgeInsetsMake(4.5, 0, -4.5, 0); + UIOffset titlePositionAdjustment = UIOffsetZero;//UIOffsetMake(0, MAXFLOAT); + CYLTabBarController *tabBarController = [CYLTabBarController tabBarControllerWithViewControllers:self.viewControllers - tabBarItemsAttributes:self.tabBarItemsAttributesForController]; + tabBarItemsAttributes:self.tabBarItemsAttributesForController + imageInsets:imageInsets + titlePositionAdjustment:titlePositionAdjustment]; + [self customizeTabBarAppearance:tabBarController]; _tabBarController = tabBarController; } @@ -67,13 +78,7 @@ - (NSArray *)viewControllers { UIViewController *fourthNavigationController = [[CYLBaseNavigationController alloc] initWithRootViewController:fourthViewController]; - /** - * 以下两行代码目的在于手动设置让TabBarItem只显示图标,不显示文字,并让图标垂直居中。 - * 等效于在 `-tabBarItemsAttributesForController` 方法中不传 `CYLTabBarItemTitle` 字段。 - * 更推荐后一种做法。 - */ - //tabBarController.imageInsets = UIEdgeInsetsMake(4.5, 0, -4.5, 0); - //tabBarController.titlePositionAdjustment = UIOffsetMake(0, MAXFLOAT); + NSArray *viewControllers = @[ firstNavigationController, secondNavigationController, @@ -156,8 +161,8 @@ - (void)customizeTabBarAppearance:(CYLTabBarController *)tabBarController { // set the bar background image // 设置背景图片 - // UITabBar *tabBarAppearance = [UITabBar appearance]; - // [tabBarAppearance setBackgroundImage:[UIImage imageNamed:@"tabbar_background"]]; +// UITabBar *tabBarAppearance = [UITabBar appearance]; +// [tabBarAppearance setBackgroundImage:[UIImage imageNamed:@"tab_bar"]]; // remove the bar system shadow image // 去除 TabBar 自带的顶部阴影 @@ -208,4 +213,6 @@ - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } + + @end diff --git a/Example/Classes/View/CYLPlusButtonSubclass.m b/Example/Classes/View/CYLPlusButtonSubclass.m index 99b9b64b..96ace31f 100644 --- a/Example/Classes/View/CYLPlusButtonSubclass.m +++ b/Example/Classes/View/CYLPlusButtonSubclass.m @@ -75,7 +75,7 @@ + (id)plusButton { [button setTitle:@"发布" forState:UIControlStateNormal]; [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal]; - [button setTitle:@"选中" forState:UIControlStateSelected]; + [button setTitle:@"发布" forState:UIControlStateSelected]; [button setTitleColor:[UIColor blueColor] forState:UIControlStateSelected]; button.titleLabel.font = [UIFont systemFontOfSize:9.5]; diff --git a/Example/Images.xcassets/AppIcon.appiconset/Contents.json b/Example/Images.xcassets/AppIcon.appiconset/Contents.json index d99d6a17..bfdf653d 100644 --- a/Example/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/Example/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,117 +1,137 @@ { "images" : [ { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-40.png", + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-Small.png", "scale" : "1x" }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-Small@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-Small@3x.png", + "scale" : "3x" + }, { "size" : "40x40", - "idiom" : "ipad", + "idiom" : "iphone", "filename" : "Icon-40@2x.png", "scale" : "2x" }, { - "size" : "60x60", + "size" : "40x40", "idiom" : "iphone", - "filename" : "Icon-60@2x.png", - "scale" : "2x" + "filename" : "Icon-40@3x.png", + "scale" : "3x" }, { - "size" : "72x72", - "idiom" : "ipad", - "filename" : "Icon-72.png", + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon.png", "scale" : "1x" }, { - "size" : "72x72", - "idiom" : "ipad", - "filename" : "Icon-72@2x.png", + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon@2x.png", "scale" : "2x" }, { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-76.png", - "scale" : "1x" + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-60@2x.png", + "scale" : "2x" }, { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-76@2x.png", - "scale" : "2x" + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-60@3x.png", + "scale" : "3x" }, { - "size" : "50x50", "idiom" : "ipad", - "filename" : "Icon-Small-50.png", + "size" : "20x20", "scale" : "1x" }, { - "size" : "50x50", "idiom" : "ipad", - "filename" : "Icon-Small-50@2x.png", + "size" : "20x20", "scale" : "2x" }, { "size" : "29x29", - "idiom" : "iphone", + "idiom" : "ipad", "filename" : "Icon-Small.png", "scale" : "1x" }, { "size" : "29x29", - "idiom" : "iphone", + "idiom" : "ipad", "filename" : "Icon-Small@2x.png", "scale" : "2x" }, { - "size" : "57x57", - "idiom" : "iphone", - "filename" : "Icon.png", + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-40.png", "scale" : "1x" }, { - "size" : "57x57", - "idiom" : "iphone", - "filename" : "Icon@2x.png", + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-40@2x.png", "scale" : "2x" }, { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-Small@3x.png", - "scale" : "3x" + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-Small-50.png", + "scale" : "1x" }, { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-40@3x.png", - "scale" : "3x" + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-Small-50@2x.png", + "scale" : "2x" }, { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-60@3x.png", - "scale" : "3x" + "size" : "72x72", + "idiom" : "ipad", + "filename" : "Icon-72.png", + "scale" : "1x" }, { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-40@2x.png", + "size" : "72x72", + "idiom" : "ipad", + "filename" : "Icon-72@2x.png", "scale" : "2x" }, { - "size" : "29x29", + "size" : "76x76", "idiom" : "ipad", - "filename" : "Icon-Small.png", + "filename" : "Icon-76.png", "scale" : "1x" }, { - "size" : "29x29", + "size" : "76x76", "idiom" : "ipad", - "filename" : "Icon-Small@2x.png", + "filename" : "Icon-76@2x.png", "scale" : "2x" }, { diff --git a/Example/Images.xcassets/tab_bar.imageset/Contents.json b/Example/Images.xcassets/tab_bar.imageset/Contents.json new file mode 100755 index 00000000..5deebf37 --- /dev/null +++ b/Example/Images.xcassets/tab_bar.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "tab_bar.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "tab_bar@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "tab_bar@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/Images.xcassets/tab_bar.imageset/tab_bar.png b/Example/Images.xcassets/tab_bar.imageset/tab_bar.png new file mode 100755 index 00000000..f4c7cbcd Binary files /dev/null and b/Example/Images.xcassets/tab_bar.imageset/tab_bar.png differ diff --git a/Example/Images.xcassets/tab_bar.imageset/tab_bar@2x.png b/Example/Images.xcassets/tab_bar.imageset/tab_bar@2x.png new file mode 100755 index 00000000..a754b790 Binary files /dev/null and b/Example/Images.xcassets/tab_bar.imageset/tab_bar@2x.png differ diff --git a/Example/Images.xcassets/tab_bar.imageset/tab_bar@3x.png b/Example/Images.xcassets/tab_bar.imageset/tab_bar@3x.png new file mode 100644 index 00000000..9679cf11 Binary files /dev/null and b/Example/Images.xcassets/tab_bar.imageset/tab_bar@3x.png differ diff --git a/README.md b/README.md index a510c10c..a7f6393c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

- + @@ -16,26 +16,7 @@ ## 导航 - 1. [与其他自定义TabBarController的区别](https://github.com/ChenYilong/CYLTabBarController#与其他自定义tabbarcontroller的区别) - 2. [集成后的效果](https://github.com/ChenYilong/CYLTabBarController#集成后的效果) - 3. [项目结构](https://github.com/ChenYilong/CYLTabBarController#项目结构) - 4. [使用CYLTabBarController](https://github.com/ChenYilong/CYLTabBarController#使用cyltabbarcontroller) - 1. [ 第一步:使用CocoaPods导入CYLTabBarController ](https://github.com/ChenYilong/CYLTabBarController#第一步使用cocoapods导入cyltabbarcontroller) - 2. [第二步:设置CYLTabBarController的两个数组:控制器数组和TabBar属性数组](https://github.com/ChenYilong/CYLTabBarController#第二步设置cyltabbarcontroller的两个数组控制器数组和tabbar属性数组) - 3. [第三步:将CYLTabBarController设置为window的RootViewController](https://github.com/ChenYilong/CYLTabBarController#第三步将cyltabbarcontroller设置为window的rootviewcontroller) - 4. [第四步(可选):创建自定义的形状不规则加号按钮](https://github.com/ChenYilong/CYLTabBarController#第四步可选创建自定义的形状不规则加号按钮) - 5. [补充说明](https://github.com/ChenYilong/CYLTabBarController#补充说明) - 1. [自定义 TabBar 样式](https://github.com/ChenYilong/CYLTabBarController#自定义-tabbar-样式) - 2. [横竖屏适配](https://github.com/ChenYilong/CYLTabBarController#横竖屏适配) - 3. [访问初始化好的 CYLTabBarController 对象](https://github.com/ChenYilong/CYLTabBarController#访问初始化好的-cyltabbarcontroller-对象) - 4. [点击 PlusButton 跳转到指定 UIViewController](https://github.com/ChenYilong/CYLTabBarController#点击-plusbutton-跳转到指定-uiviewcontroller) - 5. [让TabBarItem仅显示图标,并使图标垂直居中](https://github.com/ChenYilong/CYLTabBarController#让tabbaritem仅显示图标并使图标垂直居中) - 6. [在 Swift 项目中使用 CYLTabBarController](https://github.com/ChenYilong/CYLTabBarController#在-swift-项目中使用-cyltabbarcontroller) - 7. [搭配 Storyboard 使用 CYLTabBarController](https://github.com/ChenYilong/CYLTabBarController#搭配-storyboard-使用-cyltabbarcontroller) - 8. [源码实现原理](https://github.com/ChenYilong/CYLTabBarController#源码实现原理) - 6. [Q-A](https://github.com/ChenYilong/CYLTabBarController#q-a) - - +[TOC] ## 与其他自定义TabBarController的区别 @@ -47,9 +28,10 @@ 4|即使加号按钮超出了tabbar的区域,

超出部分依然能响应点击事件 | 红线内的区域均能响应tabbar相关的点击事件,

![enter image description here](http://i57.tinypic.com/2r7ndzk.jpg) 5 | 允许指定加号按钮位置 | 效果如下:

![enter image description here](http://a64.tinypic.com/2mo0h.jpg)

Airbnb-app效果:

![enter image description here](http://a63.tinypic.com/2mgk02v.gif) 6| 支持让 `TabBarItem` 仅显示图标,并自动使图标垂直居中,支持自定义TabBar高度 | 效果可见Airbnb-app效果,或者下图

![enter image description here](https://cloud.githubusercontent.com/assets/7238866/10777333/5d7811c8-7d55-11e5-88be-8cb11bbeaf90.png) -7 |支持CocoaPods |容易集成 -8 |支持Swift项目导入 | 兼容 -9 |支持横竖屏 | -- +7 | 支持自定义动画 | ![](https://ww1.sinaimg.cn/large/006tNbRwly1fg9hu6qnwbg308v0gctcc.gif) +8 |支持CocoaPods |容易集成 +9 |支持Swift项目导入 | 兼容 +10 |支持横竖屏 | -- @@ -95,6 +77,7 @@ ## 使用[CYLTabBarController](https://github.com/ChenYilong/CYLTabBarController) + 四步完成主流App框架搭建: 1. [ 第一步:使用CocoaPods导入CYLTabBarController ](https://github.com/ChenYilong/CYLTabBarController#第一步使用cocoapods导入cyltabbarcontroller) @@ -105,8 +88,6 @@ ### 第一步:使用CocoaPods导入CYLTabBarController -### CocoaPods 导入 - 1. CocoaPods 安装   如果您的机器上已经安装了 CocoaPods,直接进入下一步即可。 @@ -159,7 +140,7 @@   在文件 `Podfile` 中加入以下内容: ``` -    pod 'CYLTabBarController', '1.10.0' +    pod 'CYLTabBarController', '1.11.0' ```   然后在终端中运行以下命令: @@ -185,15 +166,15 @@ CocoaPods 中,有几种设置 CYLTabBarController 版本的方法。如: -`>= 1.10.X` 会根据您本地的 CocoaPods 源列表,导入不低于 `1.11.X` 版本的 CYLTabBarController。 +`>= 1.11.X` 会根据您本地的 CocoaPods 源列表,导入不低于 `1.12.X` 版本的 CYLTabBarController。 -`~> 1.10.X` 会根据您本地的 CocoaPods 源列表,介于 1.10.X~1.11.0 之前版本的 CYLTabBarController。 -我们建议您锁定版本,便于团队开发。如,指定 1.10.0 版本。 +`~> 1.11.X` 会根据您本地的 CocoaPods 源列表,介于 1.11.X~1.12.0 之前版本的 CYLTabBarController。 +我们建议您锁定版本,便于团队开发。如,指定 1.11.0 版本。 ``` -pod 'CYLTabBarController', '1.10.0' - ``` +pod 'CYLTabBarController', '1.11.0' +``` - 升级本地 CocoaPods 源 @@ -226,7 +207,8 @@ pod update 关于 CocoaPods 的更多内容,您可以参考 [CocoaPods 文档](https://cocoapods.org/)。 -### 第二步:设置CYLTabBarController的两个数组:控制器数组和TabBar属性数组 + +### 第二步:设置CYLTabBarController的两个数组:控制器数组和TabBar属性数组 ```Objective-C - (void)setupViewControllers { @@ -275,7 +257,8 @@ pod update 在这个字典中,`CYLTabBarItemImage` 和 `CYLTabBarItemSelectedImage` 支持 `NSString`、`UIImage` 两种格式。`CYLTabBarItemTitle` 不设置将只展示图标,并会对布局作出居中处理。 -### 第三步:将CYLTabBarController设置为window的RootViewController + +### 第三步:将CYLTabBarController设置为window的RootViewController ```Objective-C - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { @@ -286,7 +269,8 @@ pod update } ``` -### 第四步(可选):创建自定义的形状不规则加号按钮 + +### 第四步(可选):创建自定义的形状不规则加号按钮 创建一个继承于 CYLPlusButton 的类,要求和步骤: @@ -442,6 +426,152 @@ Airbnb-app效果: return YES; } ``` + +#### 捕获 TabBar 点击事件 + +实现 CYLTabBarController 的如下几个代理方法即可捕获点击事件。 + + 下面这个方法能捕获当前点击的 `TabBar` 上的控件,可以是 `UITabBarButton`、也可以 `PlusButton`、也可以是添加到 `TabBar` 上的任意 `UIControl` 的子类。但是如果 `PlusButton` 也添加了点击事件,那么点击 `PlusButton` 将不会被触发这个代理方法。 + + ```Objective-C +//CYLTabBarController.h + +@protocol CYLTabBarControllerDelegate + +/*! + * @param tabBarController The tab bar controller containing viewController. + * @param control Selected UIControl in TabBar. + * @attention If PlusButton also add an action, then this delegate method will not be invoked when the PlusButton is selected. + */ +- (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control; + +@end + + ``` + + 下面这个方法能捕获跳转前所在的控制器,以及跳转到的目标控制器。 + + ```Objective-C +//UITabBarController.h +@protocol UITabBarControllerDelegate +@optional +- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController NS_AVAILABLE_IOS(3_0); +@end + + ``` + +注意:在调用该方法时应该始终调用 +` [[self cyl_tabBarController] updateSelectionStatusIfNeededForTabBarController:tabBarController shouldSelectViewController:viewController];` 来确保 `PlusButton` 的选中状态。示例如下: + + ```Objective-C +- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController { + [[self cyl_tabBarController] updateSelectionStatusIfNeededForTabBarController:tabBarController shouldSelectViewController:viewController]; + return YES; +} + ``` + +相关用法已经在 Demo 中展示。 + + 遵循协议的方式如下: + + + ```Objective-C +@interface AppDelegate () + +@end + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + //... + tabBarControllerConfig.tabBarController.delegate = self; + //... + return YES; +} + ``` + +#### 点击 TabBarButton 时添加动画 + +Demo 演示的效果图: + +![](https://ww1.sinaimg.cn/large/006tNbRwly1fg9hu6qnwbg308v0gctcc.gif) + +实现如下代理方法,就能得到对应的选中控件,可以在控件上直接添加动画。 + + + ```Objective-C +//CYLTabBarController.h + +@protocol CYLTabBarControllerDelegate + +/*! + * @param tabBarController The tab bar controller containing viewController. + * @param control Selected UIControl in TabBar. + * @attention If PlusButton also add an action, then this delegate method will not be invoked when the PlusButton is selected. + */ +- (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control; + +@end + + ``` + + Demo 中示例代码如下: + + 遵循协议 + + + ```Objective-C +@interface AppDelegate () + +@end + ``` + + + ```Objective-C + //AppDelegate.m +- (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control { + UIView *animationView; + // 如果 PlusButton 也添加了点击事件,那么点击 PlusButton 后不会触发该代理方法。 + if ([control isKindOfClass:[CYLExternPlusButton class]]) { + UIButton *button = CYLExternPlusButton; + animationView = button.imageView; + } else if ([control isKindOfClass:NSClassFromString(@"UITabBarButton")]) { + for (UIView *subView in control.subviews) { + if ([subView isKindOfClass:NSClassFromString(@"UITabBarSwappableImageView")]) { + animationView = subView; + } + } + } + + if ([self cyl_tabBarController].selectedIndex % 2 == 0) { + [self addScaleAnimationOnView:animationView]; + } else { + [self addRotateAnimationOnView:animationView]; + } +} + +//缩放动画 +- (void)addScaleAnimationOnView:(UIView *)animationView { + //需要实现的帧动画,这里根据需求自定义 + CAKeyframeAnimation *animation = [CAKeyframeAnimation animation]; + animation.keyPath = @"transform.scale"; + animation.values = @[@1.0,@1.3,@0.9,@1.15,@0.95,@1.02,@1.0]; + animation.duration = 1; + animation.calculationMode = kCAAnimationCubic; + [animationView.layer addAnimation:animation forKey:nil]; +} + +//旋转动画 +- (void)addRotateAnimationOnView:(UIView *)animationView { + [UIView animateWithDuration:0.32 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ + animationView.layer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0); + } completion:nil]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [UIView animateWithDuration:0.70 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0.2 options:UIViewAnimationOptionCurveEaseOut animations:^{ + animationView.layer.transform = CATransform3DMakeRotation(2 * M_PI, 0, 1, 0); + } completion:nil]; + }); +} + ``` #### 横竖屏适配 @@ -519,7 +649,7 @@ Airbnb-app效果: ![enter image description here](http://i68.tinypic.com/2who9rs.jpg) -实现该方法后,能让 PlusButton 的点击效果与跟点击其他 UITabBarButton 效果一样,跳转到该方法指定的 UIViewController 。 +实现该方法后,能让 PlusButton 的点击效果与跟点击其他 TabBar 按钮效果一样,跳转到该方法指定的 UIViewController 。 注意:必须同时实现 `+indexOfPlusButtonInTabBar` 来指定 PlusButton 的位置。 @@ -577,7 +707,7 @@ Airbnb-app效果: 注:“仅显示图标,并使图标垂直居中”这里所指的“图标”,其所属的类是私有类: `UITabBarSwappableImageView`,所以 `CYLTabBarController` 在相关的接口命名时会包含 `SwappableImageView` 字样。另外,使用该特性需要 `pod update` 到 1.5.5以上的版本。 -#### 在 Swift 项目中使用 CYLTabBarController +### 在 Swift 项目中使用 CYLTabBarController 仓库中给出了一个Swift Demo,文件夹叫做 Example-Swift。