ios自定义中间凸出 UITabBar,so easy……

IOS 自定义UITabBar ,中间按钮凸出

很多项目中都有中间凸出的UI设计,这个不规则的设计才坑爹,必须要自定义。在安卓上 做这个也是坑,现在只说ios的实现。


示意图:
demo示意图

问题和难点:

  1. 横线,凸出部分上的黑色半圆线;
  2. 超出UITabbr部分的点击事件;
  3. UITabBar 隐藏后,上面自定义的凸出按钮隐藏。
  4. 按钮点击事件传递。

方案:

  1. 自定义UITabBar;
  2. 重写UITabBar的layoutSubviews,重新排列底部的UITabBarButton,并在中间加入自定义的按钮,添加点击监听,处理点击事件。
  3. 自定义UITabBarController ,通过kvc 替换自己的UITabBar;

解决:

解决示意图

我的解决方法:
1、中间的是一个圆形图片按钮,下面是一个UIlabel,组成了中间的按钮。
2、在自定义的UITab 上自己画一条横线,流出中间部分不画。
3、在中间加入一个自定义的UIView,在UIView中画半圆,设置UIView 的masksToBounds为YES;设置layer的cornerRadius 为他的宽高的一半,这样他就是一个白色的半圆,并有一个黑色半圆。

1.自定义半圆UIView

//H 文件:

#define SINGLE_LINE_WIDTH           (1 / [UIScreen mainScreen].scale)
#define SINGLE_LINE_ADJUST_OFFSET   ((1 / [UIScreen mainScreen].scale) / 2)

@interface GBArcView : UIView

@end

//M 文件:
#import "GBArcView.h"
#import "UIView+Extension.h"// 用了其他代码,这个大家自己找一下

@implementation GBArcView



//绘制半圆
- (void)drawRect:(CGRect)rect {


    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetStrokeColorWithColor(context, RGB_COLOR(200, 200, 200).CGColor);


    CGContextSetLineWidth(context, SINGLE_LINE_WIDTH);
    CGContextBeginPath(context);
    CGFloat lineMargin =self.width*0.5f;

    //1px线,偏移像素点
    CGFloat pixelAdjustOffset = 0;
    if (((int)(1 * [UIScreen mainScreen].scale) + 1) % 2 == 0) {
        pixelAdjustOffset = SINGLE_LINE_ADJUST_OFFSET;
    }




    CGFloat yPos = self.width*0.5f - pixelAdjustOffset;

     CGFloat xPos = self.width*0.5f - pixelAdjustOffset;

    CGContextAddArc(context, xPos, yPos, self.width*0.5f, M_PI, 0, 0);


    CGContextStrokePath(context);


}

2、自定义UITabbar

//H 文件
#import <UIKit/UIKit.h>

@class GBTabBar;

//自定义按钮点击事件代理
@protocol GBTabBarViewDelegate <NSObject>

- (void) mainTabBarViewDidClick : (GBTabBar *)hBTabBarView;


@end

@interface GBTabBar : UITabBar

@property(nonatomic,weak) id<GBTabBarViewDelegate> tabbarDelegate;

@end



//M 文件


#import "GBTabBar.h"
#import <UIKit/UIKit.h>
#import "UIView+Extension.h"
#import "GBArcView.h"




@interface GBTabBar()

@property (nonatomic,strong) UIButton *addButton;//自定义圆形图片按钮

@property (nonatomic,strong) UILabel *titleLabel;//中间自定义文本
@property (nonatomic,strong) GBArcView *view; //半圆View

@property(assign,nonatomic)int index;//UITabBar子view的索引
@end

@implementation GBTabBar


//绘制横线
- (void)drawRect:(CGRect)rect {


    //中间的按钮宽度是UItabBar的高度,其他按钮的宽度就是,(self.width-self.height)/4.0

    CGFloat buttonW = (self.width-self.height)/4.0;


    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetStrokeColorWithColor(context, RGB_COLOR(200, 200, 200).CGColor);


    CGContextSetLineWidth(context, SINGLE_LINE_WIDTH);
    CGContextBeginPath(context);
    CGFloat lineMargin =0;

  //1PX线,像素偏移
    CGFloat pixelAdjustOffset = 0;
    if (((int)(1 * [UIScreen mainScreen].scale) + 1) % 2 == 0) {
        pixelAdjustOffset = SINGLE_LINE_ADJUST_OFFSET;
    }


    CGFloat yPos = lineMargin - pixelAdjustOffset;

    //第一段线
    CGContextMoveToPoint(context, 0, yPos);
    CGContextAddLineToPoint(context, buttonW*2+SINGLE_LINE_WIDTH*2, yPos);
    CGContextStrokePath(context);

    //第二段线

    CGContextMoveToPoint(context, buttonW*2+self.height-SINGLE_LINE_WIDTH*2, yPos);
    CGContextAddLineToPoint(context, self.bounds.size.width, yPos);

    CGContextSetStrokeColorWithColor(context, RGB_COLOR(200, 200, 200).CGColor);
    CGContextStrokePath(context);



}

//自定义的按钮点击事件处理,如果点击的点在自定义的按钮中,就返回自定义按钮处理事件。如果不处理,那么按钮只有在UITabrBar 中的 一半可以被点击,有点击事件响应。
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{

    //判断点是否在按钮上,如果是就让按钮处理事件
    if(CGRectContainsPoint(self.addButton.frame, point)){
        return self.addButton ;
    }



   return  [super hitTest:point withEvent:event];

}


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


    }
    return self;
}

//重新初始化方法,从stroyboard 中加载,会调用
-(instancetype)initWithCoder:(NSCoder *)aDecoder{



    if (self = [super initWithCoder:aDecoder]) {

        self.backgroundColor=[UIColor whiteColor];
        self.clipsToBounds=NO;//不裁剪子控件
        self.index=0;//初始化索引

        //设置tabBaritem 的文字颜色
        [[UITabBarItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:RGB_COLOR(74, 74, 74), UITextAttributeTextColor, nil] forState:UIControlStateNormal];

        [[UITabBarItem appearance] setTitleTextAttributes:                                                         [NSDictionary dictionaryWithObjectsAndKeys:RGB_COLOR(0, 147, 197),UITextAttributeTextColor, nil]forState:UIControlStateSelected];

    }
    return self;
}
//自定义按钮的懒加载
-(UIButton *)addButton{


    if(!_addButton){


        UIButton *button=[[UIButton alloc] init];
        self.addButton = button;
        [self.addButton setImage:[UIImage imageNamed:@"tab_open"] forState:UIControlStateNormal];
        [self.addButton addTarget:self action:@selector(addClick) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:self.addButton];
    }


    return _addButton;
}



//自定义半圆View的懒加载
-(UIView *)view{


    if(!_view){

       CGFloat buttonW = (self.width-self.height)/4.0;


        GBArcView *view = [[GBArcView alloc]initWithFrame:CGRectMake(buttonW*2, -self.height*0.5f, self.height, self.height)];


        view.backgroundColor=[UIColor whiteColor];

        view.layer.masksToBounds=YES;
        view.layer.cornerRadius=self.height*0.5f;


        _view=view;

        [self addSubview:view];



    }


    return _view;

}



-(UILabel *)titleLabel{

    if(!_titleLabel){


        UILabel *titleLabel=[[UILabel alloc] init];

        titleLabel.text=@"开门";
        titleLabel.textColor=[UIColor blackColor];

        titleLabel.font=[UIFont systemFontOfSize:12.0];
        [titleLabel sizeToFit];

       _titleLabel = titleLabel;

        [self addSubview:titleLabel];
    }


    return _titleLabel;
}



//重写layoutSubviews,重新排布子View

-(void)layoutSubviews{

    self.index=0;
    [super layoutSubviews];



    CGFloat buttonW = SCREEN_WIDTH * 0.2 ;//SCREEN_WIDTH * 0.2

    for (int i = 0; i < self.subviews.count; i ++) {
        UIView *view = self.subviews[i];


        if ([view isKindOfClass:NSClassFromString(@"UITabBarButton")]) {

            CGRect rect=view.frame;
            rect.size.width=buttonW;

            rect.size.height=self.frame.size.height;
            rect.origin.y=0;

            view.frame =rect;

            if(self.index<2){
             view.x=self.index*buttonW;

            }else if(self.index>=2){

                view.x=self.index*buttonW +buttonW;

            }
            self.index++;

        }
    }



    //懒加载 等所有控件排布后,然后 设置自定义的view,这里注意顺序,先设置背景的半圆view的Frame,然后设置按钮的Frame,否则半圆view会挡住按钮。
    self.view.x=2 * (self.width-self.height)/4.0;
    self.addButton.width = self.height;
    self.addButton.height = self.height;
    self.addButton.y = -self.height*0.5f;
    self.addButton.x = 2 * (self.width-self.height)/4.0;

    self.titleLabel.center=CGPointMake(self.width*0.5f, CGRectGetMaxY(self.addButton.frame)+self.titleLabel.bounds.size.height*0.5f);

}



-(void)setHidden:(BOOL)hidden{


    [super setHidden:hidden];


    //手动设置UITabBar 隐藏时,我们要将自定义的按钮和背景隐藏
    [self.view setHidden:hidden];

    [self.addButton setHidden:hidden];


}
//******核心部分******
//当配置  hidesBottomBarWhenPushed 的viewController ,隐藏UITabBar时,会改变其frame,就是将UITabBar 的Y值设为屏幕最大的y值,就不可见。我们重写这个方法,判断当frame的y小于屏幕的高度 ,那么UITabBar就是被隐藏了,这时候我们将自定的控件隐藏。相反的,我们就显示我们的自定义控件。
-(void)setFrame:(CGRect)frame{
     [super setFrame:frame];

    if(frame.origin.y>=[UIScreen mainScreen].bounds.size.height){

        [self.view setHidden:YES];

        [self.addButton setHidden:YES];
    }else{
        [self.view setHidden:NO];
        [self.addButton setHidden:NO];

    }
}


- (void)addClick
{

//代理点击事件
    if ([self.tabbarDelegate respondsToSelector:@selector(mainTabBarViewDidClick:)]) {
        [self.tabbarDelegate mainTabBarViewDidClick:self];
    }
}


补一个图,这个是UITabbar隐藏的时候,截取的,可以看出被移动到屏幕最下方。

UItabbar隐藏


3、自定义UITabBarController

这里比较简单了,就是替换系统的UItabbr 为自己的UItabbar;
由于我的项目是stroyboard 写的,替换比较简单。


@interface HomeTabBarController ()<GBTabBarViewDelegate>

@property (nonatomic, strong) NSArray *items;
@end

@implementation HomeTabBarController


- (void)viewDidLoad {
    [super viewDidLoad];

   //tabBar是UITabBarController的只读成员变量(属性),是不让修改的
   //kvc 替换系统的tabbar
  //  GBTabBar *tabBar = [[GBTabBar alloc] init];
  //  [self setValue:tabBar forKeyPath:@"tabBar"];


   //已经替换的UItabbar 设置代理为当前控制器
    [self.tabBar setValue:self forKey:@"tabbarDelegate"];


}


//代理方法 ,自定义按钮点击
-(void)mainTabBarViewDidClick:(GBTabBar *)hBTabBarView{


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
iOS自定义 TabBar 主要分为以下几个步骤: 1. 创建自定义 TabBar 创建一个继承于 UITabBar 的类,重写初始化方法和 layoutSubviews 方法,实现自定义 TabBar 的样式和布局。 2. 实现自定义 TabBarItem 创建一个继承于 UIButton 的类,用于实现自定义TabBarItem 样式,例如添加图片、文字等。 3. 设置自定义 TabBarItem 在自定义 TabBar 的初始化方法中,添加自定义TabBarItem,将其添加到 TabBar 上。 4. 替换系统 TabBar 在 AppDelegate 中,找到 TabBarController 的 tabBar 属性,将其替换为自定义TabBar。 示例代码: 自定义 TabBar 类: ``` class CustomTabBar: UITabBar { var items: [CustomTabBarItem] = [] override init(frame: CGRect) { super.init(frame: frame) setup() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setup() { // 隐藏默认的 TabBar self.tintColor = .clear self.backgroundImage = UIImage() self.shadowImage = UIImage() self.backgroundColor = .white } override func layoutSubviews() { super.layoutSubviews() // 设置自定义 TabBarItem 的布局 let itemWidth = self.frame.size.width / CGFloat(items.count) var itemIndex: CGFloat = 0 for item in items { item.frame = CGRect(x: itemWidth * itemIndex, y: 0, width: itemWidth, height: self.frame.size.height) itemIndex += 1 } } } ``` 自定义 TabBarItem 类: ``` class CustomTabBarItem: UIButton { var title: String? var normalImage: UIImage? var selectedImage: UIImage? override init(frame: CGRect) { super.init(frame: frame) setup() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setup() { // 设置 TabBarItem 的样式 self.imageView?.contentMode = .scaleAspectFit self.titleLabel?.font = UIFont.systemFont(ofSize: 12) self.setTitleColor(.gray, for: .normal) self.setTitleColor(.black, for: .selected) } override func layoutSubviews() { super.layoutSubviews() // 设置 TabBarItem 的布局 let imageHeight = self.frame.size.height * 0.6 self.imageView?.frame = CGRect(x: (self.frame.size.width - imageHeight) / 2, y: 5, width: imageHeight, height: imageHeight) self.titleLabel?.frame = CGRect(x: 0, y: self.frame.size.height - 20, width: self.frame.size.width, height: 20) } func set(title: String?, normalImage: UIImage?, selectedImage: UIImage?) { self.title = title self.normalImage = normalImage self.selectedImage = selectedImage // 设置 TabBarItem 的标题和图片 self.setTitle(title, for: .normal) self.setImage(normalImage, for: .normal) self.setImage(selectedImage, for: .selected) } } ``` 在自定义 TabBar 的初始化方法中,添加自定义TabBarItem: ``` class CustomTabBar: UITabBar { var items: [CustomTabBarItem] = [] override init(frame: CGRect) { super.init(frame: frame) setup() // 添加 TabBarItem let item1 = CustomTabBarItem() item1.set(title: "首页", normalImage: UIImage(named: "home_normal"), selectedImage: UIImage(named: "home_selected")) self.addSubview(item1) items.append(item1) let item2 = CustomTabBarItem() item2.set(title: "消息", normalImage: UIImage(named: "message_normal"), selectedImage: UIImage(named: "message_selected")) self.addSubview(item2) items.append(item2) let item3 = CustomTabBarItem() item3.set(title: "我的", normalImage: UIImage(named: "mine_normal"), selectedImage: UIImage(named: "mine_selected")) self.addSubview(item3) items.append(item3) } // ... } ``` 在 AppDelegate 中,找到 TabBarController 的 tabBar 属性,将其替换为自定义TabBar: ``` func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // ... let tabBarController = UITabBarController() tabBarController.viewControllers = [viewController1, viewController2, viewController3] // 替换为自定义 TabBar let customTabBar = CustomTabBar(frame: tabBarController.tabBar.frame) tabBarController.setValue(customTabBar, forKey: "tabBar") // ... return true } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值