先上一张效果图:
下面开始说一下思路:
第一步;先对UIView进行扩展,方便我们获取它子类的一下属性。代码如下
#import <UIKit/UIKit.h>
@interface UIView (Extension)
@property (nonatomic,assign) CGFloat x;
@property (nonatomic,assign) CGFloat y;
@property (nonatomic,assign) CGFloat width;
@property (nonatomic,assign) CGFloat height;
@property (nonatomic,assign) CGFloat centerX;
@property (nonatomic,assign) CGFloat centerY;
@property (nonatomic,assign) CGSize size;
@end
#import "UIView+Extension.h"
@implementation UIView (Extension)
#pragma mark 重写set get 方法
#pragma mark x
- (void)setX:(CGFloat)x
{
CGRect frame = self.frame;
frame.origin.x = x;
self.frame = frame;
}
- (CGFloat)x
{
return self.frame.origin.x;
}
#pragma mark y
- (void)setY:(CGFloat)y
{
CGRect frame = self.frame;
frame.origin.y = y;
self.frame = frame;
}
- (CGFloat)y
{
return self.frame.origin.y;
}
#pragma mark width
- (void)setWidth:(CGFloat)width
{
CGRect frame = self.frame;
frame.size.width = width;
self.frame = frame;
}
- (CGFloat)width
{
return self.frame.size.width;
}
#pragma mark height
- (void)setHeight:(CGFloat)height
{
CGRect frame = self.frame;
frame.size.height = height;
}
- (CGFloat)height
{
return self.frame.size.height;
}
#pragma mark centerX
- (void)setCenterX:(CGFloat)centerX
{
CGPoint center = self.center;
center.x = centerX;
self.center = center;
}
- (CGFloat)centerX
{
return self.center.x;
}
#pragma mark centerY
- (void)setCenterY:(CGFloat)centerY
{
CGPoint center = self.center;
center.y = centerY;
self.center = center;
}
- (CGFloat)centerY
{
return self.center.y;
}
#pragma mark size
- (void)setSize:(CGSize)size
{
CGRect frame = self.frame;
frame.size = size;
self.frame = frame;
}
- (CGSize)size
{
return self.frame.size;
}
@end
第二步,新建一个类ZLTabbar
,继承自UITabBar
1、.h文件
#import <UIKit/UIKit.h>
typedef void(^IrrBtnSelectedBlock)();
@interface ZLTabbar : UITabBar
//用于监听自定义tabbarButton的点击事件
@property (nonatomic,copy) IrrBtnSelectedBlock selectedIrrBtn;
- (void)didselectedIrrBtnWithBlock:(IrrBtnSelectedBlock)selectedIrrBtn;
@end
这里解释一下,我习惯用block,所以这里声明了一个block类型。你也可以根据个人习惯,来使用观察者或者代理。
2、.m文件
#import "ZLTabbar.h"
#import "UIView+Extension.h"
@interface ZLTabbar ()
@property (nonatomic,strong) UIButton *irregularItem;//不规则的按钮,可以放在在中间或者其它任意一个地方
@end
@implementation ZLTabbar
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
//TODO:加载子视图
[self createChildrenViews];
}
return self;
}
#pragma mark 创建子视图
- (void)createChildrenViews
{
self.backgroundColor = [UIColor whiteColor];
//TODO:去掉tabbar的分割线
[self setBackgroundImage:[UIImage new]];
[self setShadowImage:[UIImage new]];
self.irregularItem = [UIButton buttonWithType:UIButtonTypeCustom];
[self.irregularItem setBackgroundImage:[UIImage imageNamed:@"midBtn"] forState:UIControlStateNormal];
[self.irregularItem setBackgroundImage:[UIImage imageNamed:@"midBtn"] forState:UIControlStateHighlighted];
self.irregularItem.size = self.irregularItem.currentBackgroundImage.size;
self.irregularItem.layer.masksToBounds = YES;
self.irregularItem.layer.cornerRadius = self.irregularItem.width/2;
[self.irregularItem addTarget:self action:@selector(irregularItemSelcted) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.irregularItem];
}
#pragma mark 执行和监听不规则按钮的点击事件
- (void)irregularItemSelcted
{
if (self.selectedIrrBtn)
{
self.selectedIrrBtn();
}
}
- (void)didselectedIrrBtnWithBlock:(IrrBtnSelectedBlock)selectedIrrBtn
{
self.selectedIrrBtn = selectedIrrBtn;
}
#pragma mark layoutSubviews
- (void)layoutSubviews
{
[super layoutSubviews];
//TODO:重新排布系统按钮的位置,空出需要自定义按钮的位置,系统按钮的类型是UITabBarButton
Class class = NSClassFromString(@"UITabBarButton");
//TODO:这里设置自定义tabbarButton的位置
self.irregularItem.centerX = (self.width * 0.75 + self.irregularItem.width * 0.75);
self.irregularItem.centerY = self.height - self.irregularItem.height/2;
NSInteger btnIndex = 0;
for (UIView *btn in self.subviews)
{
if ([btn isKindOfClass:class])
{
//TODO:如果是系统的UITabBarButton,调整子控件位置,空出自定义UITabBarButton的位置
//TODO:按钮宽度为Tabbar宽度平分4块
btn.width = self.width/4;
if (btnIndex < 3)
{
//TODO: -3- 在这里为irregularItem的索引值
btn.x = btn.width * btnIndex;
}
else
{
btn.x = btn.width * btnIndex + self.irregularItem.width;
}
btnIndex ++;
if (btnIndex == 0)
{
btnIndex ++;
}
}
}
[self bringSubviewToFront:self.irregularItem];
}
#pragma mark 重写hitTest方法,去监听irregularItem的点击,目的是为了让突出在外面的部分 在点击时也有反应
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
/**判断当前手指是否点击到了irregularItem。如果是,则相应按钮点击;如果是其它,则由系统处理**/
//当前view是否被隐藏?如果隐藏,就不做其他处理了。
if (self.isHidden == NO)
{
//TODO:将当前tabbar的触摸点转换成坐标系,转换到irregularItem的身上,生成一个新的点
CGPoint new_point = [self convertPoint:point toView:self.irregularItem];
//TODO:如果这个新的点是在irregularItem上,那么处理点点击事件最合适的view就是irregularItem
if ([self.irregularItem pointInside:new_point withEvent:event])
{
return self.irregularItem;
}
}
return [super hitTest:point withEvent:event];
}
@end
说明:
1.在
layoutSubviews
方法中,重设自定义以及系统的tabbarButton的位置。
2.如果不重写hitTest
方法,点击突出在外面的button
会无事件响应。
3.当调整自定义tabbarButton
的位置时,还有可能需要调整它的索引值。此时,它的索引值为3
;
第三步,创建tabbarController
.m文件
#import "ZLTabbarController.h"
#import "LeftViewController.h"
#import "RightViewController.h"
#import "MidViewController.h"
#import "ResourceViewController.h"
#import "ZLTabbar.h"
@interface ZLTabbarController ()
@end
@implementation ZLTabbarController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupTabbar];
}
#pragma mark 设置tabbar
- (void)setupTabbar
{
LeftViewController *left = [[LeftViewController alloc]init];
[self createChildrenVC:left
childrenVCTitle:@"首页"
image:[UIImage imageNamed:@"首页"]
selectedImage:[UIImage imageNamed:@"首页_S"]];
ResourceViewController *resource = [[ResourceViewController alloc]init];
[self createChildrenVC:resource
childrenVCTitle:@"资源"
image:[UIImage imageNamed:@"资源"]
selectedImage:[UIImage imageNamed:@"资源_S"]];
RightViewController *right = [[RightViewController alloc]init];
[self createChildrenVC:right
childrenVCTitle:@"个人中心"
image:[UIImage imageNamed:@"个人中心"]
selectedImage:[UIImage imageNamed:@"个人中心_S"]];
ZLTabbar *tabbar = [[ZLTabbar alloc]init];
tabbar.selectedItem = left.tabBarItem;
MidViewController *mid = [[MidViewController alloc]init];
[tabbar didselectedIrrBtnWithBlock:^{
[self presentViewController:mid animated:YES completion:nil];
}];
[self setValue:tabbar forKey:@"tabBar"];
}
#pragma mark 添加子控制器
- (void)createChildrenVC:(UIViewController *)childViewController
childrenVCTitle:(NSString *)title
image:(UIImage *)image
selectedImage:(UIImage *)selectedImg
{
//设置选中时item的字体颜色
UIColor *selectedTinColor = [UIColor colorWithRed:60.0/255
green:160.0/255
blue:220.0/255
alpha:1.0f];
[[UITabBarItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObject:NSForegroundColorAttributeName
forKey:selectedTinColor]
forState:UIControlStateSelected];
//设置未选中的image
UIImage *deselectedImage = image;
deselectedImage = [deselectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
childViewController.tabBarItem.image = deselectedImage;
//设置选中的image
UIImage *selectedImage = selectedImg;
selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
childViewController.tabBarItem.selectedImage = selectedImage;
//设置tabbarItem文字和图标 之间的距离
childViewController.tabBarItem.title = title;
// childViewController.tabBarItem.titlePositionAdjustment = UIOffsetMake(0, MAXFLOAT);
//添加控制器对象
UINavigationController *childNavigationContorller = [[UINavigationController alloc]initWithRootViewController:childViewController];
[self addChildViewController:childNavigationContorller];
}
@end
说明:
1.我们可通过
tabBarItem.titlePositionAdjustment
来设置文字与图表之间的距离,当值为MAXFLOAT
时,这个方法也起到了隐藏文字的作用。当然,你可以直接tabBarItem.title
设置为空字符串对象。
2.我们可以通过[tabbar didselectedIrrBtnWithBlock:^{ /**在这里做一些操作**/ }];
来响应一些操作。