自定义UITabBar
本文参考至:[iOS 自定义 UITabBar 的样式]http://www.jianshu.com/p/fcf0f6933ffe
自定义以下控件类:
- 自定义UIButton(图标与文字垂直居中显示)
- 自定义View放置Tab选项
- 自定义UITabBar覆盖原有的视图内容
- 自定义UITabBarController,添加相关逻辑及子视图
自定义UIButton
主要将原有的layout方法改写
自定义VerticalCenterButton类的代码具体如下:
-(void)layoutSubviews
{
[super layoutSubviews];
// 图片居中
CGPoint center = self.imageView.center;
center.x = self.frame.size.width/2;
center.y = self.imageView.frame.size.height/2+5;
self.imageView.center = center;
// 文字居中
CGRect newFrame = [self titleLabel].frame;
newFrame.origin.x = 0;
newFrame.origin.y = CGRectGetMaxY(self.imageView.frame) + 2;
newFrame.size.width = self.frame.size.width;
self.titleLabel.frame = newFrame;
self.titleLabel.textAlignment = NSTextAlignmentCenter;
self.titleLabel.font = [UIFont systemFontOfSize:12];
}
自定义放置Tab新内容的View
该View中放置了四个上下垂直显示的Button,以及中间显示一个图标的Button,需要与自定义的UITabBarController进行事件联动,故声明代理。
自定义TabBarView具体代码,如下:
@class TabBarView;
@protocol TabBarViewDelegate <NSObject>
- (void)tabBarView:(TabBarView *)view didSelectItemAtIndex:(NSInteger)index;
- (void)tabBarViewDidClickCenterItem:(TabBarView *)view;
@end
@interface TabBarView : UIView
@property (nonatomic, weak) id<TabBarViewDelegate> viewDelegate;
@end
实现代码如下:
首先,声明内部使用的控件
@interface WDYTabBarView ()
// 背景图片
@property (nonatomic, strong) UIImageView *tabBgView;
// 当前选中的位置
@property (nonatomic, assign) NSInteger selectIndex;
// 图片名称列表
@property (nonatomic, strong) NSArray *imageNameList;
// 标题类别
@property (nonatomic, strong) NSArray *titleList;
// 上次选中的按钮
@property (nonatomic, strong) WDYVerticalCenterButton *lastItem;
// 中间图标按钮
@property (nonatomic, strong) UIButton *centerItem;
@end
其次,将各个属性进行实例化:
// 将各个属性进行懒加载实例化
- (UIImageView *)tabBgView
{
if (_tabBgView == nil) {
_tabBgView = [[UIImageView alloc] initWithImage:[UIImage new]];
}
return _tabBgView;
}
- (NSArray *)imageNameList
{
if (_imageNameList == nil) {
_imageNameList = @[@"tab_live", @"tab_following", @"tab_near", @"tab_me"];
}
return _imageNameList;
}
- (NSArray *)titleList
{
if (_titleList == nil) {
_titleList = @[@"首页", @"直播", @"附近", @"我的"];
}
return _titleList;
}
- (UIButton *)centerItem
{
if (!_centerItem) {
_centerItem = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 90, 90)];
[_centerItem setImage:[UIImage imageNamed:@"tab_launch"] forState:UIControlStateNormal];
[_centerItem addTarget:self action:@selector(clickItem:) forControlEvents:UIControlEventTouchUpInside];
}
return _centerItem;
}
再者,重写init方法:
-(instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// 加载背景
[self addSubview:self.tabBgView];
// 加载item
for (int i=0; i<self.imageNameList.count; i++) {
WDYVerticalCenterButton *item = [WDYVerticalCenterButton buttonWithType:UIButtonTypeCustom];
item.adjustsImageWhenHighlighted = NO;
[item setImage:[UIImage imageNamed:self.imageNameList[i]] forState:UIControlStateNormal];
[item setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%@_p",self.imageNameList[i]]] forState:UIControlStateSelected];
[item setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%@_p",self.imageNameList[i]]] forState:UIControlStateHighlighted];
[item setTitle:self.titleList[i] forState:UIControlStateNormal];
[item setTitleColor:[UIColor redColor] forState:UIControlStateSelected];
[item addTarget:self action:@selector(clickItem:) forControlEvents:UIControlEventTouchUpInside];
item.tag = i;
if (i==0) {
item.selected = YES;
self.lastItem = item;
}
[self addSubview:item];
}
[self addSubview:self.centerItem];
}
return self;
}
重写,layoutSubviews方法:
- (void)layoutSubviews
{
[super layoutSubviews];
self.backgroundColor = [UIColor whiteColor];
// 把 tabBarButton 取出来
NSMutableArray *tabBarBtnArr = [NSMutableArray array];
for (UIView *view in self.subviews) {
if ([view isKindOfClass:NSClassFromString(@"WDYVerticalCenterButton")]) {
[tabBarBtnArr addObject:view];
}
}
CGFloat barWidth = self.bounds.size.width;
CGFloat barHeight = self.bounds.size.height;
CGFloat centerBtnWidth = CGRectGetWidth(self.centerItem.frame);
NSLog(@"%f", centerBtnWidth);
CGFloat centerBtnHeight = CGRectGetHeight(self.centerItem.frame);
// 设置中间按钮的位置,居中,部分凸起
self.centerItem.center = CGPointMake(barWidth/2, barHeight - centerBtnWidth/2 + 10);
[self addSubview:self.centerItem];
// 重新布局其他 tabBarItem
// 平均分配其他 tabBarItem 的宽度
CGFloat barItemWidth = (barWidth - centerBtnWidth) / tabBarBtnArr.count;
// 逐个布局 tabBarItem, 修改 UITabBarButton 的 frame
[tabBarBtnArr enumerateObjectsUsingBlock:^(UIView * _Nonnull view, NSUInteger idx, BOOL * _Nonnull stop) {
CGRect frame = view.frame;
if (idx >= tabBarBtnArr.count / 2) {
// 重新设置 x 坐标, 如果排在中间按钮的右边需要加上中间按钮的宽度
frame.origin.x = idx * barItemWidth + centerBtnWidth;
} else {
frame.origin.x = idx * barItemWidth;
}
// 重新设置宽度
frame.size.width = barItemWidth;
frame.size.height = barHeight;
view.frame = frame;
}];
// 把中间按钮带到视图最前面
[self bringSubviewToFront:self.centerItem];
}
重写hiteTest:withEvent:方法
// 凸起button原本是接收不到点击事件的,需要重写 hitTest:withEvent: 方法
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (self.clipsToBounds || self.hidden || (self.alpha == 0.f)) {
return nil;
}
UIView *result = [super hitTest:point withEvent:event];
// 如果事件发生在tabbar里面直接返回
if (result) {
return result;
}
// 这里遍历那些超出的部分就可以了,不过这么写比较通用。
for (UIView *subview in self.subviews) {
// 吧这个坐标从tabbar的坐标系转为 subview 的坐标系
CGPoint subPoint = [subview convertPoint:point fromView:self];
result = [subview hitTest:subPoint withEvent:event];
// 如果事件发生在 subview 里就返回
if (result) {
return result;
}
}
return nil;
}
添加clickItem:方法
- (void)clickItem:(UIButton *)button
{
if (self.lastItem.tag == button.tag) {
return;
}
if ([button isKindOfClass:[WDYVerticalCenterButton class]]) {
// 调用代理,切换视图控制器
[self.viewDelegate wdyTabBarView:self didSelectItemAtIndex:button.tag];
// **上次选中按钮和本次点击按样式切换在此设置**
self.selectIndex = button.tag;
button.selected = YES;
self.lastItem.selected = NO;
self.lastItem = (WDYVerticalCenterButton*)button;
// 动画效果
[UIView animateWithDuration:0.3 animations:^{
button.imageView.transform = CGAffineTransformMakeScale(1.2, 1.2);
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3 animations:^{
button.imageView.transform = CGAffineTransformIdentity;
}];
}];
} else {
[self.viewDelegate wdyTabBarViewDidClickCenterItem:self];
}
}
自定义UITabBar
注:本UITabBar主要是将之前自定义的TabBarView用来替换已有的tabBar。
声明部分:
@interface TabBarCustomer : UITabBar
@property (nonatomic, strong) TabBarView *tabBarView;
@end
实现部分:
- (TabBarView *)tabBarView
{
if (!_tabBarView) {
_tabBarView = [[TabBarView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 49)];
}
return _tabBarView;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self addSubview:self.tabBarView];
}
return self;
}
-(void)layoutSubviews
{
[super layoutSubviews];
// 设置 tabBarView 的 frame
self.tabBarView.frame = self.bounds;
// 把 tabbarView 带到最前面, 覆盖 tabbar 的内容
[self bringSubviewToFront:self.tabBarView];
}
// 凸起button原本是接收不到点击事件的,需要重写 hitTest:withEvent: 方法
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (self.clipsToBounds || self.hidden || (self.alpha == 0.f)) {
return nil;
}
UIView *result = [super hitTest:point withEvent:event];
// 如果事件发生在tabbar里面直接返回
if (result) {
return result;
}
// 这里遍历那些超出的部分就可以了,不过这么写比较通用。
for (UIView *subview in self.subviews) {
// 吧这个坐标从tabbar的坐标系转为 subview 的坐标系
CGPoint subPoint = [subview convertPoint:point fromView:self];
result = [subview hitTest:subPoint withEvent:event];
// 如果事件发生在 subview 里就返回
if (result) {
return result;
}
}
return nil;
}
自定义UITabBarController
这里设置新的UITabBar,并实现代理方法
自定义UITabBarController的实现代码如下:
// 点击中间图标按钮
-(void)wdyTabBarViewDidClickCenterItem:(WDYTabBarView *)view
{
NSLog(@"点击中间部分");
}
// 子视图的切换
- (void)wdyTabBarView:(WDYTabBarView *)view didSelectItemAtIndex:(NSInteger)index
{
NSLog(@"选择-----");
self.selectedIndex = index;
}
- (void)addAllChildViewController
{
UIViewController *homeVc = [[UIViewController alloc] init];
homeVc.view.backgroundColor = [UIColor redColor];
UIViewController *liveVc = [[UIViewController alloc] init];
liveVc.view.backgroundColor = [UIColor darkGrayColor];
UIViewController *searchVc = [[UIViewController alloc] init];
searchVc.view.backgroundColor = [UIColor whiteColor];
UIViewController *meVc = [[UIViewController alloc] init];
meVc.view.backgroundColor = [UIColor lightGrayColor];
NSMutableArray *arr = [NSMutableArray arrayWithObjects:homeVc, liveVc, searchVc, meVc, nil];
self.viewControllers = arr;
}
- (void)viewDidLoad {
[super viewDidLoad];
// 利用KVO来使用自定义的tabBar
TabBarCustomer *custTabBar = [[TabBarCustomer alloc] init];
custTabBar.tabBarView.viewDelegate = self;
[self setValue:custTabBar forKey:@"tabBar"];
[self addAllChildViewController];
}
在AppDelegate中添加相关代码
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor whiteColor];
self.tabBarController = [[TabBarCtrl alloc] init];
self.window.rootViewController = self.tabBarController;
// 设置tabBar每个item选中时的颜色
[[UITabBar appearance] setTintColor:[UIColor redColor]];
// 设置这个窗口有主窗口并显示
[self.window makeKeyAndVisible];
return YES;
}
实现效果如下:
![这里