iOS 自定义选项卡-CYLTabBarController
正常的选项卡流程
cocoapods就不说了
创建一个CYLTabBarControllerConfig类
#import <Foundation/Foundation.h> #import "CYLTabBarController.h" @interface CYLTabBarControllerConfig : NSObject @property (nonatomic, readonly, strong) CYLTabBarController *tabBarController; @end
#import "CYLTabBarControllerConfig.h" @import Foundation; @import UIKit; @interface CYLBaseNavigationController : UINavigationController @end @implementation CYLBaseNavigationController - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { if (self.viewControllers.count > 0) { viewController.hidesBottomBarWhenPushed = YES; } [super pushViewController:viewController animated:animated]; } @end //View Controllers #import "HandleViewController.h" #import "EnquiriesViewController.h" #import "ConsultViewController.h" #import "ManagerViewController.h" #import "ErectViewController.h" @interface CYLTabBarControllerConfig () @property (nonatomic, readwrite, strong) CYLTabBarController *tabBarController; @end @implementation CYLTabBarControllerConfig /** * lazy load tabBarController * * @return CYLTabBarController */ - (CYLTabBarController *)tabBarController { if (_tabBarController == nil) { HandleViewController *firstViewController = [[HandleViewController alloc] init]; UIViewController *firstNavigationController = [[CYLBaseNavigationController alloc] initWithRootViewController:firstViewController]; EnquiriesViewController *secondViewController = [[EnquiriesViewController alloc] init]; UIViewController *secondNavigationController = [[CYLBaseNavigationController alloc] initWithRootViewController:secondViewController]; /** * 选项卡右上角的数字 */ // secondNavigationController.tabBarItem.badgeValue = @"10"; ConsultViewController *thirdViewController = [[ConsultViewController alloc] init]; UIViewController *thirdNavigationController = [[CYLBaseNavigationController alloc] initWithRootViewController:thirdViewController]; ManagerViewController *fourthViewController = [[ManagerViewController alloc] init]; UIViewController *fourthNavigationController = [[CYLBaseNavigationController alloc] initWithRootViewController:fourthViewController]; ErectViewController *fifthViewControll = [[ErectViewController alloc]init]; UIViewController *fifthNavigationController = [[CYLBaseNavigationController alloc]initWithRootViewController:fifthViewControll]; CYLTabBarController *tabBarController = [[CYLTabBarController alloc] init]; /** * 以下两行代码目的在于手动设置让TabBarItem只显示图标,不显示文字,并让图标垂直居中。 * 等效于在`-setUpTabBarItemsAttributesForController`方法中不传`CYLTabBarItemTitle`字段。 * 更推荐后一种做法。 */ //tabBarController.imageInsets = UIEdgeInsetsMake(4.5, 0, -4.5, 0); //tabBarController.titlePositionAdjustment = UIOffsetMake(0, MAXFLOAT); // 在`-setViewControllers:`之前设置TabBar的属性,设置TabBarItem的属性,包括 title、Image、selectedImage。 [self setUpTabBarItemsAttributesForController:tabBarController]; [tabBarController setViewControllers:@[ firstNavigationController, secondNavigationController, thirdNavigationController, fourthNavigationController, fifthNavigationController ]]; // 更多TabBar自定义设置:比如:tabBarItem 的选中和不选中文字和背景图片属性、tabbar 背景图片属性 [self customizeTabBarAppearance:tabBarController]; _tabBarController = tabBarController; } return _tabBarController; } /** * 在`-setViewControllers:`之前设置TabBar的属性,设置TabBarItem的属性,包括 title、Image、selectedImage。 */ - (void)setUpTabBarItemsAttributesForController:(CYLTabBarController *)tabBarController { NSDictionary *dict1 = @{ CYLTabBarItemTitle : @"订单处理", CYLTabBarItemImage : @"tab_dingdanchuli", CYLTabBarItemSelectedImage : @"tab_dingdanchuli_s", }; NSDictionary *dict2 = @{ CYLTabBarItemTitle : @"订单查询", CYLTabBarItemImage : @"tab_dingdanchaxun", CYLTabBarItemSelectedImage : @"tab_dingdanchaxun_s", }; NSDictionary *dict3 = @{ CYLTabBarItemTitle : @"咨询", CYLTabBarItemImage : @"tab_xiaoxi", CYLTabBarItemSelectedImage : @"tab_xiaoxi_s", }; NSDictionary *dict4 = @{ CYLTabBarItemTitle : @"门店管理", CYLTabBarItemImage : @"tab_mendianguanli", CYLTabBarItemSelectedImage : @"tab_mendianguanli_s" }; NSDictionary *dict5 = @{ CYLTabBarItemTitle : @"设置", CYLTabBarItemImage : @"tab_shezhi", CYLTabBarItemSelectedImage : @"tab_shezhi_s" }; NSArray *tabBarItemsAttributes = @[ dict1, dict2, dict3, dict4, dict5 ]; tabBarController.tabBarItemsAttributes = tabBarItemsAttributes; } /** * 更多TabBar自定义设置:比如:tabBarItem 的选中和不选中文字和背景图片属性、tabbar 背景图片属性 */ - (void)customizeTabBarAppearance:(CYLTabBarController *)tabBarController { // Customize UITabBar height // 自定义 TabBar 高度 // tabBarController.tabBarHeight = 80.f; // set the text color for unselected state // 普通状态下的文字属性 NSMutableDictionary *normalAttrs = [NSMutableDictionary dictionary]; normalAttrs[NSForegroundColorAttributeName] = [UIColor grayColor]; // set the text color for selected state // 选中状态下的文字属性 NSMutableDictionary *selectedAttrs = [NSMutableDictionary dictionary]; selectedAttrs[NSForegroundColorAttributeName] = RGBColor(72, 199, 22); // set the text Attributes // 设置文字属性 UITabBarItem *tabBar = [UITabBarItem appearance]; [tabBar setTitleTextAttributes:normalAttrs forState:UIControlStateNormal]; [tabBar setTitleTextAttributes:selectedAttrs forState:UIControlStateSelected]; // Set the dark color to selected tab (the dimmed background) // TabBarItem选中后的背景颜色 // [self customizeTabBarSelectionIndicatorImage]; // update TabBar when TabBarItem width did update // If your app need support UIDeviceOrientationLandscapeLeft or UIDeviceOrientationLandscapeRight, // remove the comment '//' // 如果你的App需要支持横竖屏,请使用该方法移除注释 '//' // [self updateTabBarCustomizationWhenTabBarItemWidthDidUpdate]; // set the bar shadow image // This shadow image attribute is ignored if the tab bar does not also have a custom background image.So at least set somthing. [[UITabBar appearance] setBackgroundImage:[[UIImage alloc] init]]; [[UITabBar appearance] setBackgroundColor:[UIColor whiteColor]]; [[UITabBar appearance] setShadowImage:[UIImage imageNamed:@"tapbar_top_line"]]; // set the bar background image // 设置背景图片 // UITabBar *tabBarAppearance = [UITabBar appearance]; // [tabBarAppearance setBackgroundImage:[UIImage imageNamed:@"tabbar_background"]]; // remove the bar system shadow image // 去除 TabBar 自带的顶部阴影 // [[UITabBar appearance] setShadowImage:[[UIImage alloc] init]]; } - (void)updateTabBarCustomizationWhenTabBarItemWidthDidUpdate { void (^deviceOrientationDidChangeBlock)(NSNotification *) = ^(NSNotification *notification) { UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; if ((orientation == UIDeviceOrientationLandscapeLeft) || (orientation == UIDeviceOrientationLandscapeRight)) { NSLog(@"Landscape Left or Right !"); } else if (orientation == UIDeviceOrientationPortrait){ NSLog(@"Landscape portrait!"); } [self customizeTabBarSelectionIndicatorImage]; }; [[NSNotificationCenter defaultCenter] addObserverForName:CYLTabBarItemWidthDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:deviceOrientationDidChangeBlock]; } - (void)customizeTabBarSelectionIndicatorImage { ///Get initialized TabBar Height if exists, otherwise get Default TabBar Height. UITabBarController *tabBarController = [self cyl_tabBarController] ?: [[UITabBarController alloc] init]; CGFloat tabBarHeight = tabBarController.tabBar.frame.size.height; CGSize selectionIndicatorImageSize = CGSizeMake(CYLTabBarItemWidth, tabBarHeight); //Get initialized TabBar if exists. UITabBar *tabBar = [self cyl_tabBarController].tabBar ?: [UITabBar appearance]; [tabBar setSelectionIndicatorImage: [[self class] imageWithColor:[UIColor redColor] size:selectionIndicatorImageSize]]; } + (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size { if (!color || size.width <= 0 || size.height <= 0) return nil; CGRect rect = CGRectMake(0.0f, 0.0f, size.width + 1, size.height); UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, color.CGColor); CGContextFillRect(context, rect); UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; }
另外还有自定义的加号按钮
要创建一个CYLPlusButton的类不要忘了加上CYLPlusButtonSubclassing协议
#import <CYLTabBarController/CYLTabBarController.h> @interface CYLPlusButtonSubclass : CYLPlusButton<CYLPlusButtonSubclassing,UIActionSheetDelegate> @end
#import "CYLPlusButtonSubclass.h" #import <CYLTabBarController.h> @implementation CYLPlusButtonSubclass +(void)load{ [super registerSubclass]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.titleLabel.textAlignment = NSTextAlignmentCenter; self.adjustsImageWhenHighlighted = NO; } return self; } //上下结构的 button - (void)layoutSubviews { [super layoutSubviews]; // 控件大小,间距大小 CGFloat const imageViewEdgeWidth = self.bounds.size.width * 0.7; CGFloat const imageViewEdgeHeight = imageViewEdgeWidth * 0.9; CGFloat const centerOfView = self.bounds.size.width * 0.5; CGFloat const labelLineHeight = self.titleLabel.font.lineHeight; CGFloat const verticalMarginT = self.bounds.size.height - labelLineHeight - imageViewEdgeWidth; CGFloat const verticalMargin = verticalMarginT / 2; // imageView 和 titleLabel 中心的 Y 值 CGFloat const centerOfImageView = verticalMargin + imageViewEdgeWidth * 0.5; CGFloat const centerOfTitleLabel = imageViewEdgeWidth + verticalMargin * 2 + labelLineHeight * 0.5 + 5; //imageView position 位置 self.imageView.bounds = CGRectMake(0, 0, imageViewEdgeWidth, imageViewEdgeHeight); self.imageView.center = CGPointMake(centerOfView, centerOfImageView); //title position 位置 self.titleLabel.bounds = CGRectMake(0, 0, self.bounds.size.width, labelLineHeight); self.titleLabel.center = CGPointMake(centerOfView, centerOfTitleLabel); } /* * Create a custom UIButton with title and add it to the center of our tab bar * */ + (id)plusButton { CYLPlusButtonSubclass *button = [[CYLPlusButtonSubclass alloc] init]; UIImage *buttonImage = [UIImage imageNamed:@"post_normal"]; [button setImage:buttonImage forState:UIControlStateNormal]; [button setTitle:@"发布" forState:UIControlStateNormal]; [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal]; [button setTitle:@"选中" forState:UIControlStateSelected]; [button setTitleColor:[UIColor blueColor] forState:UIControlStateSelected]; button.titleLabel.font = [UIFont systemFontOfSize:9.5]; [button sizeToFit]; // or set frame in this way `button.frame = CGRectMake(0.0, 0.0, 250, 100);` [button addTarget:button action:@selector(clickPublish) forControlEvents:UIControlEventTouchUpInside]; return button; } /* * Create a custom UIButton without title and add it to the center of our tab bar * */ //+ (id)plusButton //{ // // UIImage *buttonImage = [UIImage imageNamed:@"hood.png"]; // UIImage *highlightImage = [UIImage imageNamed:@"hood-selected.png"]; // // CYLPlusButtonSubclass* button = [CYLPlusButtonSubclass buttonWithType:UIButtonTypeCustom]; // // button.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin; // button.frame = CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height); // [button setBackgroundImage:buttonImage forState:UIControlStateNormal]; // [button setBackgroundImage:highlightImage forState:UIControlStateHighlighted]; // [button addTarget:button action:@selector(clickPublish) forControlEvents:UIControlEventTouchUpInside]; // // return button; //} - (void)clickPublish { CYLTabBarController *tabBarController = [self cyl_tabBarController]; UIViewController *viewController = tabBarController.selectedViewController; UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:nil cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"拍照", @"从相册选取", @"淘宝一键转卖", nil]; [actionSheet showInView:viewController.view]; NSLog(@"发布"); } #pragma mark - CYLPlusButtonSubclassing //+ (UIViewController *)plusChildViewController { // UIViewController *plusChildViewController = [[UIViewController alloc] init]; // plusChildViewController.view.backgroundColor = [UIColor redColor]; // plusChildViewController.navigationItem.title = @"PlusChildViewController"; // UIViewController *plusChildNavigationController = [[UINavigationController alloc] // initWithRootViewController:plusChildViewController]; // return plusChildNavigationController; //} // + (NSUInteger)indexOfPlusButtonInTabBar { return 5; } + (CGFloat)multiplerInCenterY { return 0.3; }
如果正常按钮数目是奇数的话 要实现
+ (NSUInteger)indexOfPlusButtonInTabBar { return 5; }
如何调整、自定义 PlusButton
与其它 TabBarItem
的宽度?
CYLTabBarController
规定:
TabBarItem 宽度 = ( TabBar 总宽度 - PlusButton 宽度 ) / (TabBarItem 个数)
所以想自定义宽度,只需要修改 PlusButton
的宽度即可。
比如你就可以在 Demo中的 CYLPlusButtonSubclass.m
类里:
把
[button sizeToFit]
改为
button.frame = CGRectMake(0.0, 0.0, 250, 100);
---------------
如果要把加号按钮做成跟其他按钮的点击效果一样的话需要同时实现这两个方法
+ (UIViewController *)plusChildViewController { UIViewController *plusChildViewController = [[UIViewController alloc] init]; plusChildViewController.view.backgroundColor = [UIColor redColor]; plusChildViewController.navigationItem.title = @"PlusChildViewController"; UIViewController *plusChildNavigationController = [[UINavigationController alloc] initWithRootViewController:plusChildViewController]; return plusChildNavigationController; } + (NSUInteger)indexOfPlusButtonInTabBar { return 5; }
之前不知道怎么回事,出了些莫名其妙的问题。。记录下
前人种树后人乘凉啊!感谢原作作者