iOS开发: 自定义tabBar

下面是自定义tabBar的一种效果, 如果有错误请留言, 我会修改

一、目标

  • 目标效果


    iOS开发: 自定义tabBar_第1张图片
    目标效果
  • tabBar中间添加一个红色的圆形按钮, 并且按钮上所有位置都可以触发点击事件

二、实现方式

  • 1: 自定义标签控制器(继承自UITabBarController), 并添加四个子控制器


    iOS开发: 自定义tabBar_第2张图片
    • 图中的四个按钮位置靠上是因为 图片文字 整体是一张图的原因, 稍后会调整
  • 2: 自定义类LTTabBar(继承自UITabBar)
  • 3: 在自定义的标签控制器中使用KVC替换tabBar
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 替换掉系统的tabBar, 换成自己自定义的TabBar
    [self setValue:[LTTabBar new] forKey:@"tabBar"];
}
- (void)layoutSubviews
{
    [super layoutSubviews];
    
    NSInteger count = self.items.count;
    
    NSInteger index = 0;
    
    CGFloat width = self.width / (count + 1);
    CGFloat height = self.height;
    
    // 遍历所有按钮, 调整按钮位置
    for (UIView *subView in self.subviews) {
        if ([subView isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
            // 当遇到第三个按钮(标记是2)时, 调整数值
            if (index == 2) index++;
            CGFloat x = index * width;
            CGFloat y = 5;
            subView.frame = CGRectMake(x, y, width, height);
            index++;
        }
    }
}
  • 调整后的效果图


    iOS开发: 自定义tabBar_第3张图片
    调整按钮位置后的效果
  • 在按钮的中间添加一个视图, 这个视图的大小根据需求而定

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setUpInit];
    }
    return self;
}

- (UIView *)middleView
{
    if (!_middleView) {
        UIView *middleView = [[UIView alloc] init];
        [self addSubview:middleView];
        _middleView = middleView;
    }
    return _middleView;
}

- (void)setUpInit
{
    // 设置中间视图的大小 和 颜色
    // 这里颜色为蓝色, 方便看效果, 在这上面可以添加任意的视图 或者 图片
    self.middleView.frame = CGRectMake(0, 0, 65, 65);
    self.middleView.backgroundColor = [UIColor blueColor];
}
  • 效果图


    iOS开发: 自定义tabBar_第4张图片
  • 在蓝色视图上添加我们需要的红色按钮

@interface LTTabBar ()

/** 中间View */
@property (nonatomic, weak) UIView *middleView;

/** 中心的红色圆 */
@property (nonatomic, weak) UIButton *circleBtn;

@end

@implementation LTTabBar

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setUpInit];
    }
    return self;
}

- (UIView *)middleView
{
    if (!_middleView) {
        UIView *middleView = [[UIView alloc] init];
        [self addSubview:middleView];
        _middleView = middleView;
    }
    return _middleView;
}

- (void)setUpInit
{
    // 设置中间视图的大小 和 颜色
    // 这里颜色为透明, 这样就看不见了, 在这上面可以添加任意的视图 或者 图片
    self.middleView.frame = CGRectMake(0, 0, 65, 65);
    self.middleView.backgroundColor = [UIColor blueColor];
    
    // 添加红色的圆形按钮
    UIButton *circleBtn = [UIButton new];
    circleBtn.frame = self.middleView.frame;
    circleBtn.layer.cornerRadius = circleBtn.width * 0.5;
    circleBtn.layer.masksToBounds = YES;
    circleBtn.backgroundColor = [UIColor redColor];
    [self.middleView addSubview:circleBtn];
    _circleBtn = circleBtn;
    // 添加点击事件
    [circleBtn addTarget:self action:@selector(circleBtnClick:) forControlEvents:(UIControlEventTouchUpInside)];
}

// 红色按钮点击事件
- (void)circleBtnClick:(UIButton *)sender
{
    NSLog(@"红色按钮被点击了");
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    NSInteger count = self.items.count;
    
    NSInteger index = 0;
    
    CGFloat width = self.width / (count + 1);
    CGFloat height = self.height;
    
    // 遍历所有按钮, 调整按钮位置
    for (UIView *subView in self.subviews) {
        if ([subView isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
            // 当遇到第三个按钮(标记是2)时, 调整数值
            if (index == 2) index++;
            CGFloat x = index * width;
            CGFloat y = 5;
            subView.frame = CGRectMake(x, y, width, height);
            index++;
        }
    }
    
    self.middleView.centerX = self.width * 0.5;
    self.middleView.y = self.height - self.middleView.height;
}
@end
  • 效果图 : 红色按钮可以换成需要的任意视图或图片


    iOS开发: 自定义tabBar_第5张图片
    效果图
  • 接下来需要重写方法- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event来确定当用户点在什么地方时才会响应点击事件

    • 目标: 点击tabBar和红色按钮上时响应点击事件
    • 红色按钮有超出父视图(tabBar)的部分, 不处理的话, 超出部分没办法响应事件, 在这里处理
/**
 此方法用来决定 点击事件 能否在本视图上传递
 */
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    // 将点击的 位置 转成在中心视图上的点
    CGPoint middlePoint = [self convertPoint:point toView:self.middleView];
    
    // 中心视图上的中心位置
    CGPoint center = CGPointMake(self.middleView.width * 0.5, self.middleView.height * 0.5);
    
    // 使用勾股定理计算出中心点的距离
    CGFloat distance = sqrt(pow(middlePoint.x - center.x, 2) + pow(middlePoint.y - center.y, 2));
    
    // 下面的判断根据个人需求定
    // 1. 如果点击的位置到红色圆的圆心距离 大于 半径, 说明点击的位置不在圆上, 但是有可能在tabBar其他区域上
    // 2. 如果点击的位置在tabBar范围上, 那么middlePoint的y值就是 大于 self.middleView.height - self.height, 反之点击的位置就不在圆内
    // 所以: 综上两点, 当点击的位置即在圆外, 又不在tabBar上时, 直接返回, 此时中间视图上边两个蓝色角也无法响应事件
    if (distance > _circleBtn.width * 0.5 && middlePoint.y < self.middleView.height - self.height) {
        return NO;
    }
    return YES;
}
  • 效果图


    iOS开发: 自定义tabBar_第6张图片
  • 此时将蓝色视图的颜色改为透明就可以了, 大家也可以根据自己的需求将红色按钮换成其他任意的视图

  • 最后效果


    iOS开发: 自定义tabBar_第7张图片
    最后效果

蓝色视图的存在意义是, 方便控制红色按钮的位置, 去掉也可以

三、代码

  • LTTabBar.h中代码
#import 

@interface LTTabBar : UITabBar

@end
#import "LTTabBar.h"
#import "UIView+LTLayout.h"

@interface LTTabBar ()

/** 中间View */
@property (nonatomic, weak) UIView *middleView;

/** 中心的红色圆 */
@property (nonatomic, weak) UIButton *circleBtn;

@end

@implementation LTTabBar

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setUpInit];
    }
    return self;
}

- (UIView *)middleView
{
    if (!_middleView) {
        UIView *middleView = [[UIView alloc] init];
        [self addSubview:middleView];
        _middleView = middleView;
    }
    return _middleView;
}

- (void)setUpInit
{
    // 设置中间视图的大小 和 颜色
    // 这里颜色为透明, 这样就看不见了, 在这上面可以添加任意的视图 或者 图片
    self.middleView.frame = CGRectMake(0, 0, 65, 65);
    self.middleView.backgroundColor = [UIColor clearColor];
    
    // 添加红色的圆形按钮
    UIButton *circleBtn = [UIButton new];
    circleBtn.frame = self.middleView.frame;
    circleBtn.layer.cornerRadius = circleBtn.width * 0.5;
    circleBtn.layer.masksToBounds = YES;
    circleBtn.backgroundColor = [UIColor redColor];
    [self.middleView addSubview:circleBtn];
    _circleBtn = circleBtn;
    
    [circleBtn addTarget:self action:@selector(circleBtnClick:) forControlEvents:(UIControlEventTouchUpInside)];
}

- (void)circleBtnClick:(UIButton *)sender
{
    NSLog(@"红色按钮被点击了");
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    NSInteger count = self.items.count;
    
    NSInteger index = 0;
    
    CGFloat width = self.width / (count + 1);
    CGFloat height = self.height;
    
    // 遍历所有按钮, 调整按钮位置
    for (UIView *subView in self.subviews) {
        if ([subView isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
            // 当遇到第三个按钮(标记是2)时, 调整数值
            if (index == 2) index++;
            CGFloat x = index * width;
            CGFloat y = 5;
            subView.frame = CGRectMake(x, y, width, height);
            index++;
        }
    }
    
    self.middleView.centerX = self.width * 0.5;
    self.middleView.y = self.height - self.middleView.height;
}

/**
 此方法用来决定 点击事件 能否在本视图上传递
 */
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    // 将点击的 位置 转成在中心蓝色视图上的点
    CGPoint middlePoint = [self convertPoint:point toView:self.middleView];
    
    // 中心蓝色视图上的中心位置
    CGPoint center = CGPointMake(self.middleView.width * 0.5, self.middleView.height * 0.5);
    
    // 使用勾股定理计算出中心点的距离
    CGFloat distance = sqrt(pow(middlePoint.x - center.x, 2) + pow(middlePoint.y - center.y, 2));
    
    // 下面的判断根据个人需求定
    // 1. 如果点击的位置到红色圆的圆心距离 大于 半径, 说明点击的位置不在圆上, 但是有可能在tabBar其他区域上
    // 2. 如果点击的位置在tabBar范围上, 那么middlePoint的y值就是 大于 self.middleView.height - self.height, 反之点击的位置就不在圆内
    // 所以: 综上两点, 当点击的位置即在圆外, 又不在tabBar上时, 直接返回, 此时中间视图上边两个蓝色角也无法响应事件
    if (distance > _circleBtn.width * 0.5 && middlePoint.y < self.middleView.height - self.height) {
        return NO;
    }
    return YES;
}

@end

你可能感兴趣的:(iOS开发: 自定义tabBar)