1、需要两个类:
(1)TBTabBar
#import <UIKit/UIKit.h>
@interface TBTabBar : UITabBar
//@property(nonatomic,strong)UIButton *publishBtn;
@property (nonatomic,copy) void(^didClickPublishBtn)();
@end
#import "TBTabBar.h"
//button拓展类
#import "UIButton+SSEdgeInsets.h"
@interface TBTabBar ()
/** plus按钮 */
@property (nonatomic, weak) UIButton *plusBtn ;
@end
@implementation TBTabBar
- (void)layoutSubviews {
[super layoutSubviews];
CGFloat w = self.width/5.0;
UIButton *publishBtn = [[UIButton alloc] init];
[publishBtn setImage:[UIImage imageNamed:@"发布3.3"] forState:UIControlStateNormal];
[publishBtn setTitle:@" " forState:UIControlStateNormal];
publishBtn.titleLabel.font = [UIFont systemFontOfSize:10];
[publishBtn addTarget:self action:@selector(didClickPublishBtn:) forControlEvents:UIControlEventTouchUpInside];
publishBtn.adjustsImageWhenHighlighted = NO;
publishBtn.size = CGSizeMake(w, 70);
publishBtn.centerX = self.width / 2;
publishBtn.centerY = 12;
[publishBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[self addSubview:publishBtn];
self.plusBtn = publishBtn;
//button按钮
[publishBtn setImagePositionWithType:SSImagePositionTypeTop spacing:5];
// 其他位置按钮
NSUInteger count = self.subviews.count;
for (NSUInteger i = 0 , j = 0; i < count; i++) {
UIView *view = self.subviews[i];
Class class = NSClassFromString(@"UITabBarButton");
if ([view isKindOfClass:class]) {
view.width = self.width / 5.0;
view.x = self.width * j / 5.0;
j++;
if (j == 2) {
j++;
}
}
}
}
// 点击发布
- (void) didClickPublishBtn:(UIButton*)sender {
// NSLog(@"点击了发布");
if (self.didClickPublishBtn) {
self.didClickPublishBtn();
}
}
//重写hitTest方法,去监听发布按钮的点击,目的是为了让凸出的部分点击也有反应
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
//这一个判断是关键,不判断的话push到其他页面,点击发布按钮的位置也是会有反应的,这样就不好了
//self.isHidden == NO 说明当前页面是有tabbar的,那么肯定是在导航控制器的根控制器页面
//在导航控制器根控制器页面,那么我们就需要判断手指点击的位置是否在发布按钮身上
//是的话让发布按钮自己处理点击事件,不是的话让系统去处理点击事件就可以了
if (self.isHidden == NO) {
//将当前tabbar的触摸点转换坐标系,转换到发布按钮的身上,生成一个新的点
CGPoint newP = [self convertPoint:point toView:self.plusBtn];
//判断如果这个新的点是在发布按钮身上,那么处理点击事件最合适的view就是发布按钮
if ( [self.plusBtn pointInside:newP withEvent:event]) {
return self.plusBtn;
}else{//如果点不在发布按钮身上,直接让系统处理就可以了
return [super hitTest:point withEvent:event];
}
}
else {//tabbar隐藏了,那么说明已经push到其他的页面了,这个时候还是让系统去判断最合适的view处理就好了
return [super hitTest:point withEvent:event];
}
}
@end
(2)UIButton+SSEdgeInsets
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger, SSImagePositionType) {
SSImagePositionTypeLeft, //图片在左,标题在右,默认风格
SSImagePositionTypeRight, //图片在右,标题在左
SSImagePositionTypeTop, //图片在上,标题在下
SSImagePositionTypeBottom //图片在下,标题在上
};
typedef NS_ENUM(NSInteger, SSEdgeInsetsType) {
SSEdgeInsetsTypeTitle,//标题
SSEdgeInsetsTypeImage//图片
};
typedef NS_ENUM(NSInteger, SSMarginType) {
SSMarginTypeTop ,
SSMarginTypeBottom ,
SSMarginTypeLeft ,
SSMarginTypeRight ,
SSMarginTypeTopLeft ,
SSMarginTypeTopRight ,
SSMarginTypeBottomLeft ,
SSMarginTypeBottomRight
};
/**
默认情况下,imageEdgeInsets和titleEdgeInsets都是0。先不考虑height,
if (button.width小于imageView上image的width){图像会被压缩,文字不显示}
if (button.width < imageView.width + label.width){图像正常显示,文字显示不全}
if (button.width >= imageView.width + label.width){图像和文字都居中显示,imageView在左,label在右,中间没有空隙}
*/
@interface UIButton (SSEdgeInsets)
/**
* 利用UIButton的titleEdgeInsets和imageEdgeInsets来实现图片和标题的自由排布
* 注意:1.该方法需在设置图片和标题之后才调用;
2.图片和标题改变后需再次调用以重新计算titleEdgeInsets和imageEdgeInsets
*
* @param type 图片位置类型
* @param spacing 图片和标题之间的间隙
*/
- (void)setImagePositionWithType:(SSImagePositionType)type spacing:(CGFloat)spacing;
/**
* 按钮只设置了title or image,该方法可以改变它们的位置
*
* @param edgeInsetsType <#edgeInsetsType description#>
* @param marginType <#marginType description#>
* @param margin <#margin description#>
*/
- (void)setEdgeInsetsWithType:(SSEdgeInsetsType)edgeInsetsType marginType:(SSMarginType)marginType margin:(CGFloat)margin;
/**
* 图片在上,标题在下
*
* @param spacing image 和 title 之间的间隙
*/
- (void)setImageUpTitleDownWithSpacing:(CGFloat)spacing __deprecated_msg("Method deprecated. Use `setImagePositionWithType:spacing:`");
/**
* 图片在右,标题在左
*
* @param spacing image 和 title 之间的间隙
*/
- (void)setImageRightTitleLeftWithSpacing:(CGFloat)spacing __deprecated_msg("Method deprecated. Use `setImagePositionWithType:spacing:`");
@end
#import "UIButton+SSEdgeInsets.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
#define SS_SINGLELINE_TEXTSIZE(text, font) [text length] > 0 ? [text \
sizeWithAttributes:@{NSFontAttributeName:font}] : CGSizeZero;
#else
#define SS_SINGLELINE_TEXTSIZE(text, font) [text length] > 0 ? [text sizeWithFont:font] : CGSizeZero;
#endif
@implementation UIButton (SSEdgeInsets)
- (void)setImagePositionWithType:(SSImagePositionType)type spacing:(CGFloat)spacing {
CGSize imageSize = [self imageForState:UIControlStateNormal].size;
CGSize titleSize = SS_SINGLELINE_TEXTSIZE([self titleForState:UIControlStateNormal], self.titleLabel.font);
switch (type) {
case SSImagePositionTypeLeft: {
self.titleEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, 0);
self.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, spacing);
break;
}
case SSImagePositionTypeRight: {
self.titleEdgeInsets = UIEdgeInsetsMake(0, - imageSize.width, 0, imageSize.width + spacing);
self.imageEdgeInsets = UIEdgeInsetsMake(0, titleSize.width + spacing, 0, - titleSize.width);
break;
}
case SSImagePositionTypeTop: {
// lower the text and push it left so it appears centered
// below the image
self.titleEdgeInsets = UIEdgeInsetsMake(0, - imageSize.width, - (imageSize.height + spacing), 0);
// raise the image and push it right so it appears centered
// above the text
self.imageEdgeInsets = UIEdgeInsetsMake(- (titleSize.height + spacing), 0, 0, - titleSize.width);
break;
}
case SSImagePositionTypeBottom: {
self.titleEdgeInsets = UIEdgeInsetsMake(- (imageSize.height + spacing), - imageSize.width, 0, 0);
self.imageEdgeInsets = UIEdgeInsetsMake(0, 0, - (titleSize.height + spacing), - titleSize.width);
break;
}
}
}
- (void)setImageUpTitleDownWithSpacing:(CGFloat)spacing {
[self setImagePositionWithType:SSImagePositionTypeTop spacing:spacing];
}
- (void)setImageRightTitleLeftWithSpacing:(CGFloat)spacing {
[self setImagePositionWithType:SSImagePositionTypeRight spacing:spacing];
}
- (void)setEdgeInsetsWithType:(SSEdgeInsetsType)edgeInsetsType marginType:(SSMarginType)marginType margin:(CGFloat)margin {
CGSize itemSize = CGSizeZero;
if (edgeInsetsType == SSEdgeInsetsTypeTitle) {
itemSize = SS_SINGLELINE_TEXTSIZE([self titleForState:UIControlStateNormal], self.titleLabel.font);
} else {
itemSize = [self imageForState:UIControlStateNormal].size;
}
CGFloat horizontalDelta = (CGRectGetWidth(self.frame) - itemSize.width) / 2.f - margin;
CGFloat vertivalDelta = (CGRectGetHeight(self.frame) - itemSize.height) / 2.f - margin;
NSInteger horizontalSignFlag = 1;
NSInteger verticalSignFlag = 1;
switch (marginType) {
case SSMarginTypeTop: {
horizontalSignFlag = 0;
verticalSignFlag = - 1;
break;
}
case SSMarginTypeBottom: {
horizontalSignFlag = 0;
verticalSignFlag = 1;
break;
}
case SSMarginTypeLeft: {
horizontalSignFlag = - 1;
verticalSignFlag = 0;
break;
}
case SSMarginTypeRight: {
horizontalSignFlag = 1;
verticalSignFlag = 0;
break;
}
case SSMarginTypeTopLeft: {
horizontalSignFlag = - 1;
verticalSignFlag = - 1;
break;
}
case SSMarginTypeTopRight: {
horizontalSignFlag = 1;
verticalSignFlag = - 1;
break;
}
case SSMarginTypeBottomLeft: {
horizontalSignFlag = - 1;
verticalSignFlag = 1;
break;
}
case SSMarginTypeBottomRight: {
horizontalSignFlag = 1;
verticalSignFlag = 1;
break;
}
}
UIEdgeInsets edgeInsets = UIEdgeInsetsMake(vertivalDelta * verticalSignFlag, horizontalDelta * horizontalSignFlag, - vertivalDelta * verticalSignFlag, - horizontalDelta * horizontalSignFlag);
if (edgeInsetsType == SSEdgeInsetsTypeTitle) {
self.titleEdgeInsets = edgeInsets;
} else {
self.imageEdgeInsets = edgeInsets;
}
}
@end
2、控制器里:MainViewController
#import <UIKit/UIKit.h>
@interface MainViewController : UITabBarController
@end
#import "MainViewController.h"
//tabbar
#import "TBTabBar.h"
//导航栏
#import "MineNavigationController.h"
//主页
#import "MainHomeViewControllerV3_3.h"
//逛街
#import "ShoppingViewController.h"
//美聊
#import "BeautyChatControllerV2_0.h"
//个人中心3.1.0
#import "MyCenterViewController3_1_0.h"
//发布话题
#import "SendTopicViewController.h"
@interface MainViewController ()
/** 之前被选中的UITabBarItem */
@property (nonatomic, strong) UITabBarItem *lastItem;
@end
@implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化所有控制器
[self setUpChildVC];
// 创建tabbar中间的tabbarItem
[self setUpMidelTabbarItem];
}
#pragma mark -创建tabbar中间的tabbarItem
- (void)setUpMidelTabbarItem {
TBTabBar *tabBar = [[TBTabBar alloc] init];
// KVC:如果要修系统的某些属性,但被设为readOnly,就是用KVC,即setValue:forKey:。
[self setValue:tabBar forKey:@"tabBar"];
//去掉黑线,然后替换tabbar上面那一条线,下面两个方法必须同时设置,否则无效imageWithColor是根据颜色生成图片的封装
[tabBar setBackgroundImage:[UIImage imageWithColor:[UIColor whiteColor] size:CGSizeMake(self.view.frame.size.width, .5)]];
[tabBar setShadowImage:[UIImage imageWithColor:[UIColor colorWithHexString:@"#d1d3db"] size:CGSizeMake(self.view.frame.size.width, .5)]];
//(3)设置其他属性
tabBar.barTintColor = [UIColor whiteColor];//设置tabbar背景颜色
tabBar.translucent = NO;
// 二次点击触发刷新将默认被选中的tabBarItem保存为属性
self.lastItem = tabBar.selectedItem;
//中间发布按钮点击回调
__weak typeof(self) weakSelf = self;
[tabBar setDidClickPublishBtn:^{
//凸出按钮点击事件
[weakSelf plusBtnClick];
}];
}
#pragma mark -初始化所有控制器
- (void)setUpChildVC {
MainHomeViewControllerV3_3 *homeVC = [[MainHomeViewControllerV3_3 alloc] init];
//设置角标数量
// homeVC.tabBarItem.badgeValue = @"1111";
[self setChildVC:homeVC title:@"" image:@"首页" selectedImage:@"首页s"];
ShoppingViewController *fishpidVC = [[ShoppingViewController alloc] init];
[self setChildVC:fishpidVC title:@"" image:@"逛街" selectedImage:@"逛街s"];
BeautyChatControllerV2_0 *messageVC = [[BeautyChatControllerV2_0 alloc] init];
[self setChildVC:messageVC title:@"" image:@"美聊" selectedImage:@"美聊s"];
MyCenterViewController3_1_0 *myVC = [[MyCenterViewController3_1_0 alloc] init];
[self setChildVC:myVC title:@"" image:@"我的" selectedImage:@"我的s"];
}
//设置子控制器
- (void) setChildVC:(UIViewController *)childVC title:(NSString *) title image:(NSString *) image selectedImage:(NSString *) selectedImage {
childVC.tabBarItem.title = title;
//设置字体属性
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSForegroundColorAttributeName] = [UIColor blackColor];
dict[NSFontAttributeName] = [UIFont systemFontOfSize:10];
// 禁用图片渲染
[childVC.tabBarItem setTitleTextAttributes:dict forState:UIControlStateNormal];
childVC.tabBarItem.image = [[UIImage imageNamed:image] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
childVC.tabBarItem.selectedImage = [[UIImage imageNamed:selectedImage] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
//字控制器图片调整位置
childVC.tabBarItem.imageInsets = UIEdgeInsetsMake(5, 0, -5, 0);
// childVc.view.backgroundColor = RandomColor; // 这句代码会自动加载主页,消息,发现,我四个控制器的view,但是view要在我们用的时候去提前加载
//导航
MineNavigationController *nav = [[MineNavigationController alloc] initWithRootViewController:childVC];
//导航栏颜色
nav.navigationBar.barTintColor = [UIColor whiteColor];
[self addChildViewController:nav];
}
//二次点击tabbar触发刷新代理方法
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
// 判断本次点击的UITabBarItem是否和上次的一样
if (item == self.lastItem) { // 一样就发出通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"LLTabBarDidClickNotification" object:nil userInfo:nil];
}
// 将这次点击的UITabBarItem赋值给属性
self.lastItem = item;
}
//发布按钮
- (void)plusBtnClick{
//友盟点击量统计
[MobClick event:@"changwenfabu"];
//push控制器
MineNavigationController * nav = [(UITabBarController *)[UIApplication sharedApplication].keyWindow.rootViewController selectedViewController];
if (SESSIONID.length>0) {
//跳转到发话题界面
SendTopicViewController * SendTopic = [[SendTopicViewController alloc]init];
SendTopic.hidesBottomBarWhenPushed = YES;
SendTopic.type = @"UGC话题";
[nav pushViewController:SendTopic animated:YES];
}else{
//跳到登陆界面
LoginViewController * loginVc = [[LoginViewController alloc]init];
loginVc.hidesBottomBarWhenPushed = YES;
[nav pushViewController:loginVc animated:YES];
}
}
#pragma mark ====================== 处理屏幕旋转(在用,请不要删)=========================
-(BOOL)shouldAutorotate{
return [self.selectedViewController shouldAutorotate];
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return [self.selectedViewController supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [self.selectedViewController preferredInterfaceOrientationForPresentation];
}
@end
总结:这是我用过最好的中间凸出的tabbar了,希望大家喜欢(2017年6月13日)