在做开发的时候,我们经常会感觉到系统自带的东西不要用,比如说UITabBar,那么我们可以去自定义。
比如像微博,QQ空间那样的应用,中间都有个加号,发表微博,说说的,那么这样的怎么去实现呢?
自定义一个tabBar继承自系统自带的,然后重写其中的
- (void)layoutSubviews
方法。
#import "HWTabBar.h" @interface HWTabBar() @property (nonatomic, weak) UIButton *plusBtn; @end @implementation HWTabBar - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // 添加一个按钮到tabbar中 UIButton *plusBtn = [[UIButton alloc] init]; [plusBtn setBackgroundImage:[UIImage imageNamed:@"tabbar_compose_button"] forState:UIControlStateNormal]; [plusBtn setBackgroundImage:[UIImage imageNamed:@"tabbar_compose_button_highlighted"] forState:UIControlStateHighlighted]; [plusBtn setImage:[UIImage imageNamed:@"tabbar_compose_icon_add"] forState:UIControlStateNormal]; [plusBtn setImage:[UIImage imageNamed:@"tabbar_compose_icon_add_highlighted"] forState:UIControlStateHighlighted]; plusBtn.size = plusBtn.currentBackgroundImage.size; [plusBtn addTarget:self action:@selector(plusClick) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:plusBtn]; self.plusBtn = plusBtn; } return self; } /** * 加号按钮点击 */ - (void)plusClick { // 通知代理 if ([self.delegate respondsToSelector:@selector(tabBarDidClickPlusButton:)]) { [self.delegate tabBarDidClickPlusButton:self]; } } - (void)layoutSubviews { #warning [super layoutSubviews] 一定要调用 [super layoutSubviews]; // 1.设置加号按钮的位置 self.plusBtn.centerX = self.width * 0.5; self.plusBtn.centerY = self.height * 0.5; // 2.设置其他tabbarButton的位置和尺寸 CGFloat tabbarButtonW = self.width / 5; CGFloat tabbarButtonIndex = 0; for (UIView *child in self.subviews) { Class class = NSClassFromString(@"UITabBarButton"); if ([child isKindOfClass:class]) { // 设置宽度 child.width = tabbarButtonW; // 设置x child.x = tabbarButtonIndex * tabbarButtonW; // 增加索引 tabbarButtonIndex++; if (tabbarButtonIndex == 2) { tabbarButtonIndex++; } } } } @end
注意到tabBar中的每个选项卡的类名叫做UITabBarButton。
当你在UITabBarController中添加选项卡的时候,需要用KVC去修改系统自带的tabBar,只能通过KVC去修改,因为如果直接使用self.tabBar=自定义的,这样会报错,因为tabBar这个属性是readonly也就是只读的,不能直接去修改,但是通过KVC就行,KVC可以修改任何属性!
// // HWTabBarViewController.m // 黑马微博2期 // // Created by apple on 14-10-7. // Copyright (c) 2014年 heima. All rights reserved. // #import "HWTabBarViewController.h" #import "HWHomeViewController.h" #import "HWMessageCenterViewController.h" #import "HWDiscoverViewController.h" #import "HWProfileViewController.h" #import "HWNavigationController.h" #import "HWTabBar.h" @interface HWTabBarViewController () <HWTabBarDelegate> @end @implementation HWTabBarViewController - (void)viewDidLoad { [super viewDidLoad]; // 1.初始化子控制器 HWHomeViewController *home = [[HWHomeViewController alloc] init]; [self addChildVc:home title:@"首页" image:@"tabbar_home" selectedImage:@"tabbar_home_selected"]; HWMessageCenterViewController *messageCenter = [[HWMessageCenterViewController alloc] init]; [self addChildVc:messageCenter title:@"消息" image:@"tabbar_message_center" selectedImage:@"tabbar_message_center_selected"]; HWDiscoverViewController *discover = [[HWDiscoverViewController alloc] init]; [self addChildVc:discover title:@"发现" image:@"tabbar_discover" selectedImage:@"tabbar_discover_selected"]; HWProfileViewController *profile = [[HWProfileViewController alloc] init]; [self addChildVc:profile title:@"我" image:@"tabbar_profile" selectedImage:@"tabbar_profile_selected"]; // 2.更换系统自带的tabbar HWTabBar *tabBar = [[HWTabBar alloc] init]; [self setValue:tabBar forKeyPath:@"tabBar"]; /* [self setValue:tabBar forKeyPath:@"tabBar"];相当于self.tabBar = tabBar; [self setValue:tabBar forKeyPath:@"tabBar"];这行代码过后,tabBar的delegate就是HWTabBarViewController 说明,不用再设置tabBar.delegate = self; */ /* 1.如果tabBar设置完delegate后,再执行下面代码修改delegate,就会报错 tabBar.delegate = self; 2.如果再次修改tabBar的delegate属性,就会报下面的错误 错误信息:Changing the delegate of a tab bar managed by a tab bar controller is not allowed. 错误意思:不允许修改TabBar的delegate属性(这个TabBar是被TabBarViewController所管理的) */ } /** * 添加一个子控制器 * * @param childVc 子控制器 * @param title 标题 * @param image 图片 * @param selectedImage 选中的图片 */ - (void)addChildVc:(UIViewController *)childVc title:(NSString *)title image:(NSString *)image selectedImage:(NSString *)selectedImage { // 设置子控制器的文字 childVc.title = title; // 同时设置tabbar和navigationBar的文字 // 设置子控制器的图片 childVc.tabBarItem.image = [UIImage imageNamed:image]; childVc.tabBarItem.selectedImage = [[UIImage imageNamed:selectedImage]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; // 设置文字的样式 NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary]; textAttrs[NSForegroundColorAttributeName] = HWColor(123, 123, 123); NSMutableDictionary *selectTextAttrs = [NSMutableDictionary dictionary]; selectTextAttrs[NSForegroundColorAttributeName] = [UIColor orangeColor]; [childVc.tabBarItem setTitleTextAttributes:textAttrs forState:UIControlStateNormal]; [childVc.tabBarItem setTitleTextAttributes:selectTextAttrs forState:UIControlStateSelected]; // 先给外面传进来的小控制器 包装 一个导航控制器 HWNavigationController *nav = [[HWNavigationController alloc] initWithRootViewController:childVc]; // 添加为子控制器 [self addChildViewController:nav]; } #pragma mark - HWTabBarDelegate代理方法 - (void)tabBarDidClickPlusButton:(HWTabBar *)tabBar { UIViewController *vc = [[UIViewController alloc] init]; vc.view.backgroundColor = [UIColor redColor]; [self presentViewController:vc animated:YES completion:nil]; } @end
设置好之后,点击发微博的按钮的时候,怎么去modal出一个新窗口呢,这时候就需要用到代理了。
注意到,我们用KVC修改tabBar之后并没有去设置代理,因为我们自定义的tabBar继承自系统自带的,我们定义delegate的时候,也需要继承自系统的,用KVC去修改之后,不用再去设置代理,因为已经设置好了。