• 在git上看到的自定义tabbar,比较流行的中间凸起
  • 主要实现思路: 1.重写UITabBar:在init里面创建一个button来实现不规则的图标(添加新按钮)放在最中间 -(void)layoutSubviews调整系统原本的图标的坐标(为中间这个控件留出位置) ...自定义Sam

    主要实现思路:
    1.重写UITabBar:在init里面创建一个button来实现不规则的图标(添加新按钮)放在最中间 -(void)layoutSubviews调整系统原本的图标的坐标(为中间这个控件留出位置)
    2.重写-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ 避免按钮超区不可点击

    看具体的代码:
    自定义SamTabBar视图

    //
    //  SamTabBar.h
    //  MoJing
    //
    //  Created by linpeng on 2017/3/15.
    //  Copyright © 2017年 linpeng. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    //tab页面个数
    typedef NS_ENUM(NSInteger, SamItemUIType) {
        SamItemUIType_Three = 3,//底部3个选项
        SamItemUIType_Five = 5,//底部5个选项
    };
    
    
    @class SamTabBar;
    
    @protocol SamTabBarDelegate <NSObject>
    
    -(void)tabBar:(SamTabBar *)tabBar clickCenterButton:(UIButton *)sender;
    
    @end
    
    @interface SamTabBar : UITabBar
    
    @property (nonatomic, weak) id<SamTabBarDelegate> tabDelegate;
    @property (nonatomic, strong) NSString *centerBtnTitle;
    @property (nonatomic, strong) NSString *centerBtnIcon;
    
    +(instancetype)instanceCustomTabBarWithType:(SamItemUIType)type;
    
    @end
    

    m文件

    //
    //  SamTabBar.m
    //  MoJing
    //
    //  Created by linpeng on 2017/3/15.
    //  Copyright © 2017年 linpeng. All rights reserved.
    //
    
    #import "SamTabBar.h"
    
    @interface SamTabBar()
    @property(nonatomic, strong) UIButton *centerButton;
    @property(nonatomic, strong) UILabel *centerTitle;
    @property (nonatomic,assign) SamItemUIType type;
    
    @end
    
    @implementation SamTabBar
    
    +(instancetype)instanceCustomTabBarWithType:(SamItemUIType)type{
        SamTabBar *tabBar = [[SamTabBar alloc] init];
        tabBar.type = type;
        return tabBar;
    }
    
    -(instancetype)initWithFrame:(CGRect)frame{
        self = [super initWithFrame:frame];
        if (self) {
            self.translucent = NO;
            UIButton *plusBtn = [UIButton buttonWithType:UIButtonTypeCustom];
            self.centerButton = plusBtn;
            [plusBtn addTarget:self action:@selector(plusBtnDidClick) forControlEvents:UIControlEventTouchUpInside];
            [self addSubview:plusBtn];
    
            UILabel *lblTitle = [[UILabel alloc] init];
            self.centerTitle = lblTitle;
            lblTitle.font = [UIFont systemFontOfSize:10];
            lblTitle.textColor = [UIColor blackColor];
            lblTitle.textAlignment = NSTextAlignmentCenter;
            [self addSubview:lblTitle];
    
        }
        return self;
    }
    
    -(void)plusBtnDidClick{
        if (self.tabDelegate && [self.tabDelegate respondsToSelector:@selector(tabBar:clickCenterButton:)]) {
            [self.tabDelegate tabBar:self clickCenterButton:self.centerButton];
        }
    }
    
    // 调整子视图的布局
    -(void)layoutSubviews{
        [super layoutSubviews];
        CGFloat width = self.frame.size.width/self.type;
        Class class = NSClassFromString(@"UITabBarButton");
        for (UIView *view in self.subviews) {
            if ([view isEqual:self.centerTitle]) {//self.centerButton
                view.frame = CGRectMake(0, 0, width, 15);
                view.center = CGPointMake(self.frame.size.width/2, self.frame.size.height - view.frame.size.height + 8);
            }else if ([view isEqual:self.centerButton]) {//self.centerButton
                view.frame = CGRectMake(0, 0, width, self.frame.size.height);
                [view sizeToFit];
                view.center = CGPointMake(self.frame.size.width/2, 10);
            }else if ([view isKindOfClass:class]){//system button
                CGRect frame = view.frame;
                int indexFromOrign = view.frame.origin.x/width;//防止UIView *view in self.subviews 获取到的不是有序的
                if (indexFromOrign >= (self.type - 1) / 2) {
                    indexFromOrign++;
                }
                CGFloat x = indexFromOrign * width;
                //如果是系统的UITabBarButton,那么就调整子控件位置,空出中间位置
                view.frame = CGRectMake(x, view.frame.origin.y, width, frame.size.height);
    
                //调整badge postion
                for (UIView *badgeView in view.subviews){
                    NSString *className = NSStringFromClass([badgeView class]);
                    // Looking for _UIBadgeView
                    if ([className rangeOfString:@"BadgeView"].location != NSNotFound){
                        badgeView.layer.transform = CATransform3DIdentity;
                        badgeView.layer.transform = CATransform3DMakeTranslation(-17.0, 1.0, 1.0);
                        break;
                    }
                }
            }
        }
    }
    
    
    -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
        //这一个判断是关键,不判断的话push到其他页面,点击发布按钮的位置也是会有反应的,这样就不好了
        //self.isHidden == NO 说明当前页面是有tabbar的,那么肯定是在导航控制器的根控制器页面
        //在导航控制器根控制器页面,那么我们就需要判断手指点击的位置是否在发布按钮身上
        //是的话让发布按钮自己处理点击事件,不是的话让系统去处理点击事件就可以了
        if (self.isHidden == NO) {
            //将当前tabbar的触摸点转换坐标系,转换到发布按钮的身上,生成一个新的点
            CGPoint newP = [self convertPoint:point toView:self.centerButton];
    
            //判断如果这个新的点是在发布按钮身上,那么处理点击事件最合适的view就是发布按钮
            if ( [self.centerButton pointInside:newP withEvent:event]) {
                return self.centerButton;
            }else{//如果点不在发布按钮身上,直接让系统处理就可以了
                return [super hitTest:point withEvent:event];
            }
        }
        else {//tabbar隐藏了,那么说明已经push到其他的页面了,这个时候还是让系统去判断最合适的view处理就好了
            return [super hitTest:point withEvent:event];
        }
    }
    
    -(void)setCenterBtnIcon:(NSString *)centerBtnIcon{
        _centerBtnIcon = centerBtnIcon;
        [self.centerButton setBackgroundImage:[UIImage imageNamed:self.centerBtnIcon] forState:UIControlStateNormal];
        [self.centerButton setBackgroundImage:[UIImage imageNamed:self.centerBtnIcon] forState:UIControlStateHighlighted];
    }
    
    -(void)setCenterBtnTitle:(NSString *)centerBtnTitle{
        _centerBtnTitle = centerBtnTitle;
        self.centerTitle.text = centerBtnTitle;
    }
    
    @end
    

    用法:
    以上自定义的tabbar控件就弄好了 现在就可以在VC中使用了
    创建一个WBTabBarController 继承UITabBarController 在appdelegate中

    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.window.rootViewController = [[WBTabBarController alloc] init];

    kvo的形式添加自定义的tabbar

     //kvo形式添加自定义的 UITabBar
        SamTabBar *tab = [SamTabBar instanceCustomTabBarWithType:SamItemUIType_Five];
        [self setValue:tab forKey:@"tabBar"];

    具体的代码:

    @interface WBTabBarController ()<SamTabBarDelegate>
    @end
    
    @implementation WBTabBarController
    
    - (void)awakeFromNib {
        [super awakeFromNib];
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self setupUI];
    }
    
    -(void)setupUI{
        [self setupVC];
        [[UITabBar appearance] setShadowImage:[UIImage new]];
        //kvo形式添加自定义的 UITabBar
        SamTabBar *tab = [SamTabBar instanceCustomTabBarWithType:SamItemUIType_Five];
        tab.centerBtnTitle = @"发布";
        tab.centerBtnIcon = @"摄影机图标_点击后";
        tab.tabDelegate = self;
        [self setValue:tab forKey:@"tabBar"];
    }
    
    - (void)setupVC{
        [self addChildVc:[[LoginViewController alloc] init] title:@"首页" image:@"TabMessage" selectedImage:@"TabMessage_HL"];
        [self addChildVc:[[LoginViewController alloc] init] title:@"发现" image:@"TabMessage" selectedImage:@"TabMessage_HL"];
        [self addChildVc:[[LoginViewController alloc] init] title:@"消息" image:@"TabMessage" selectedImage:@"TabMessage_HL"];
        [self addChildVc:[[LoginViewController alloc] init] title:@"个人中心" image:@"TabMessage" selectedImage:@"TabMessage_HL"];
    }
    
    - (void)addChildVc:(UIViewController *)childVc title:(NSString *)title image:(NSString *)image selectedImage:(NSString *)selectedImage{
        // 设置子控制器的文字(可以设置tabBar和navigationBar的文字)
        childVc.title = title;
        // 设置子控制器的tabBarItem图片
        childVc.tabBarItem.image = [UIImage imageNamed:image];
        // 禁用图片渲染
        childVc.tabBarItem.selectedImage = [[UIImage imageNamed:selectedImage] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
        // 设置文字的样式
        [childVc.tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor blackColor]} forState:UIControlStateNormal];
        [childVc.tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor redColor]} forState:UIControlStateSelected];
        // 为子控制器包装导航控制器
        WBBaseNC *navigationVc = [[WBBaseNC alloc] initWithRootViewController:childVc];
        // 添加子控制器
        [self addChildViewController:navigationVc];
    }
    
    -(void)tabBar:(SamTabBar *)tabBar clickCenterButton:(UIButton *)sender{
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"点击了中间按钮" preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
    
        }];
        [alert addAction:action];
        [self presentViewController:alert animated:YES completion:nil];
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    /*
    #pragma mark - Navigation
    
    // In a storyboard-based application, you will often want to do a little preparation before navigation
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
        // Get the new view controller using [segue destinationViewController].
        // Pass the selected object to the new view controller.
    }
    */
    
    @end
    

    效果如图:
    图片

    gif效果如图:
    gif效果

    修改tabbar上那条很丑的分割线

    -(void)setupUI{
        [self setupVC];
        //kvo形式添加自定义的 UITabBar
        SamTabBar *tab = [SamTabBar instanceCustomTabBarWithType:SamItemUIType_Five];
        tab.centerBtnTitle = nil;
        tab.centerBtnIcon = @"menu_diary_pr";
        tab.tabDelegate = self;
        [self setValue:tab forKey:@"tabBar"];
    
        //去除顶部很丑的border
        [[UITabBar appearance] setShadowImage:[UIImage new]];
        [[UITabBar appearance] setBackgroundImage:[[UIImage alloc]init]];
    
        //自定义分割线颜色
        UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(self.tabBar.bounds.origin.x-0.5, self.tabBar.bounds.origin.y, self.tabBar.bounds.size.width+1, self.tabBar.bounds.size.height+2)];
        bgView.layer.borderColor = COLOR_SEPERATOR.CGColor;
        bgView.layer.borderWidth = 0.5;
        [tab insertSubview:bgView atIndex:0];
        tab.opaque = YES;
    }

    效果:
    这里写图片描述

    展开全文
  • 效果: PS:这里需要用到UIView一个分类的一些属性,参考...最后在StoryBoard中选择TabBarController对应下面自定义的TabBarController即可   自定义TabBar:  MyTab

    效果:

    PS:这里需要用到UIView一个分类的一些属性,参考http://blog.csdn.net/doubleface999/article/details/79085764,图标素材等自行上网找或者自己设计,这里就不提供了。最后在StoryBoard中选择TabBarController对应下面自定义的TabBarController即可

     

    自定义TabBar

     MyTabBar.h

    复制代码
     1 #import <UIKit/UIKit.h>
     2 
     3 @class MyTabBar;
     4 
     5 //MyTabBar的代理必须实现addButtonClick,以响应中间“+”按钮的点击事件
     6 @protocol MyTabBarDelegate <NSObject>
     7 
     8 -(void)addButtonClick:(MyTabBar *)tabBar;
     9 
    10 @end
    11 
    12 @interface MyTabBar : UITabBar
    13 
    14 //指向MyTabBar的代理
    15 @property (nonatomic,weak) id<MyTabBarDelegate> myTabBarDelegate;
    16 
    17 @end
    复制代码

     

    MyTabBar.m

    复制代码
      1 #import "MyTabBar.h"
      2 #import "UIView+Category.h"
      3 
      4 #define AddButtonMargin 10
      5 
      6 @interface MyTabBar()
      7 
      8 //指向中间“+”按钮
      9 @property (nonatomic,weak) UIButton *addButton;
     10 //指向“添加”标签
     11 @property (nonatomic,weak) UILabel *addLabel;
     12 
     13 @end
     14 
     15 @implementation MyTabBar
     16 
     17 /*
     18 // Only override drawRect: if you perform custom drawing.
     19 // An empty implementation adversely affects performance during animation.
     20 - (void)drawRect:(CGRect)rect {
     21     // Drawing code
     22 }
     23 */
     24 
     25 -(instancetype)initWithFrame:(CGRect)frame
     26 {
     27     if(self = [super initWithFrame:frame])
     28     {
     29         //创建中间“+”按钮
     30         UIButton *addBtn = [[UIButton alloc] init];
     31         //设置默认背景图片
     32         [addBtn setBackgroundImage:[UIImage imageNamed:@"AddButtonIcon"] forState:UIControlStateNormal];
     33         //设置按下时背景图片
     34         [addBtn setBackgroundImage:[UIImage imageNamed:@"AddButtonIcon-Active"] forState:UIControlStateHighlighted];
     35         //添加响应事件
     36         [addBtn addTarget:self action:@selector(addBtnDidClick) forControlEvents:UIControlEventTouchUpInside];
     37         //将按钮添加到TabBar
     38         [self addSubview:addBtn];
     39         
     40         self.addButton = addBtn;
     41     }
     42     return self;
     43 }
     44 
     45 //响应中间“+”按钮点击事件
     46 -(void)addBtnDidClick
     47 {
     48     if([self.myTabBarDelegate respondsToSelector:@selector(addButtonClick:)])
     49     {
     50         [self.myTabBarDelegate addButtonClick:self];
     51     }
     52 }
     53 
     54 -(void)layoutSubviews
     55 {
     56     [super layoutSubviews];
     57     
     58     //去掉TabBar上部的横线
     59     for (UIView *view in self.subviews)
     60     {
     61         if ([view isKindOfClass:[UIImageView class]] && view.bounds.size.height <= 1)   //横线的高度为0.5
     62         {
     63             UIImageView *line = (UIImageView *)view;
     64             line.hidden = YES;
     65         }
     66     }
     67     
     68     //设置“+”按钮的位置
     69     self.addButton.centerX = self.centerX;
     70     self.addButton.centerY = self.height * 0.5 - 1.5 * AddButtonMargin;
     71     //设置“+”按钮的大小为图片的大小
     72     self.addButton.size = CGSizeMake(self.addButton.currentBackgroundImage.size.width, self.addButton.currentBackgroundImage.size.height);
     73     
     74     //创建并设置“+”按钮下方的文本为“添加”
     75     UILabel *addLbl = [[UILabel alloc] init];
     76     addLbl.text = @"添加";
     77     addLbl.font = [UIFont systemFontOfSize:10];
     78     addLbl.textColor = [UIColor grayColor];
     79     [addLbl sizeToFit];
     80 
     81     //设置“添加”label的位置
     82     addLbl.centerX = self.addButton.centerX;
     83     addLbl.centerY = CGRectGetMaxY(self.addButton.frame) + 0.5 * AddButtonMargin + 0.5;
     84     
     85     [self addSubview:addLbl];
     86     
     87     self.addLabel = addLbl;
     88     
     89     int btnIndex = 0;
     90     //系统自带的按钮类型是UITabBarButton,找出这些类型的按钮,然后重新排布位置,空出中间的位置
     91     Class class = NSClassFromString(@"UITabBarButton");
     92     for (UIView *btn in self.subviews) {//遍历TabBar的子控件
     93         if ([btn isKindOfClass:class]) {//如果是系统的UITabBarButton,那么就调整子控件位置,空出中间位置
     94             //每一个按钮的宽度等于TabBar的三分之一
     95             btn.width = self.width / 3;
     96             
     97             btn.x = btn.width * btnIndex;
     98             
     99             btnIndex++;
    100             //如果索引是1(即“+”按钮),直接让索引加一
    101             if (btnIndex == 1) {
    102                 btnIndex++;
    103             }
    104             
    105         }
    106     }
    107     //将“+”按钮放到视图层次最前面
    108     [self bringSubviewToFront:self.addButton];
    109 }
    110 
    111 //重写hitTest方法,去监听"+"按钮和“添加”标签的点击,目的是为了让凸出的部分点击也有反应
    112 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    113     
    114     //这一个判断是关键,不判断的话push到其他页面,点击“+”按钮的位置也是会有反应的,这样就不好了
    115     //self.isHidden == NO 说明当前页面是有TabBar的,那么肯定是在根控制器页面
    116     //在根控制器页面,那么我们就需要判断手指点击的位置是否在“+”按钮或“添加”标签上
    117     //是的话让“+”按钮自己处理点击事件,不是的话让系统去处理点击事件就可以了
    118     if (self.isHidden == NO)
    119     {
    120         
    121         //将当前TabBar的触摸点转换坐标系,转换到“+”按钮的身上,生成一个新的点
    122         CGPoint newA = [self convertPoint:point toView:self.addButton];
    123         //将当前TabBar的触摸点转换坐标系,转换到“添加”标签的身上,生成一个新的点
    124         CGPoint newL = [self convertPoint:point toView:self.addLabel];
    125         
    126         //判断如果这个新的点是在“+”按钮身上,那么处理点击事件最合适的view就是“+”按钮
    127         if ( [self.addButton pointInside:newA withEvent:event])
    128         {
    129             return self.addButton;
    130         }
    131         //判断如果这个新的点是在“添加”标签身上,那么也让“+”按钮处理事件
    132         else if([self.addLabel pointInside:newL withEvent:event])
    133         {
    134             return self.addButton;
    135         }
    136         else
    137         {//如果点不在“+”按钮身上,直接让系统处理就可以了
    138             
    139             return [super hitTest:point withEvent:event];
    140         }
    141     }
    142     else
    143     {
    144         //TabBar隐藏了,那么说明已经push到其他的页面了,这个时候还是让系统去判断最合适的view处理就好了
    145         return [super hitTest:point withEvent:event];
    146     }
    147 }
    148 
    149 @end
    复制代码

     

    自定义TabBarController

    MyTabBarController.h

    1 #import <UIKit/UIKit.h>
    2 
    3 @interface MyTabBarController : UITabBarController
    4 
    5 @end

     

     

    MyTabBarController.m

    复制代码
     1 #import "MyTabBarController.h"
     2 #import "MyTabBar.h"
     3 
     4 
     5 @interface MyTabBarController () <MyTabBarDelegate> //实现自定义TabBar协议
     6 
     7 @end
     8 
     9 @implementation MyTabBarController
    10 
    11 - (void)viewDidLoad {
    12     [super viewDidLoad];
    13     // Do any additional setup after loading the view.
    14     
    15     //设置TabBar上第一个Item(明细)选中时的图片
    16     UIImage *listActive = [UIImage imageNamed:@"ListIcon - Active(blue)"];
    17     UITabBarItem *listItem = self.tabBar.items[0];
    18     //始终按照原图片渲染
    19     listItem.selectedImage = [listActive imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    20     
    21     
    22     //设置TabBar上第二个Item(报表)选中时的图片
    23     UIImage *chartActive = [UIImage imageNamed:@"ChartIcon - Active(blue)"];
    24     UITabBarItem *chartItem = self.tabBar.items[1];
    25     //始终按照原图片渲染
    26     chartItem.selectedImage = [chartActive imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    27     
    28     //创建自定义TabBar
    29     MyTabBar *myTabBar = [[MyTabBar alloc] init];
    30     myTabBar.myTabBarDelegate = self;
    31     
    32     //利用KVC替换默认的TabBar
    33     [self setValue:myTabBar forKey:@"tabBar"];
    34 }
    35 
    36 
    37 -(void)viewDidLayoutSubviews
    38 {
    39     [super viewDidLayoutSubviews];
    40     //设置TabBar的TintColor
    41     self.tabBar.tintColor = [UIColor colorWithRed:89/255.0 green:217/255.0 blue:247/255.0 alpha:1.0];
    42 }
    43 
    44 - (void)didReceiveMemoryWarning {
    45     [super didReceiveMemoryWarning];
    46     // Dispose of any resources that can be recreated.
    47 }
    48 
    49 
    50 
    51 #pragma mark - MyTabBarDelegate
    52 -(void)addButtonClick:(MyTabBar *)tabBar
    53 {
    54     //测试中间“+”按钮是否可以点击并处理事件
    55     UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"test" message:@"Test" preferredStyle:UIAlertControllerStyleAlert];
    56     UIAlertAction *action = [UIAlertAction actionWithTitle:@"test" style:UIAlertActionStyleDefault handler:nil];
    57     [controller addAction:action];
    58     [self presentViewController:controller animated:YES completion:nil];
    59     
    60 }
    61 
    62 @end
    复制代码

     原文链接:https://www.cnblogs.com/guitarandcode/p/5759208.html

    展开全文
  • 前言 最近的项目中有需求在tabbar中间添加凸起按钮,并且点击时按钮要旋转,看...tabbar有5个item,每个对应一个页面 中间item为凸起按钮 中间按钮点击后旋转 效果实现 设置5个item 我们一步步来解决这个问题,

    前言

    最近的项目中有需求在tabbar中间添加凸起按钮,并且点击时按钮要旋转,看了仿闲鱼的凸起,点击后是present出来View,而不是像常规的tabbar上添加一个页面(亲测,闲鱼的超出Tabbar部分点击是没有反应的,这是bug啊,下文对这个问题有详解),所以不符合要求,经过一段摸索最后得的一个比较好的效果,下面看效果图

    效果图.gif

    (本文简书地址:https://www.jianshu.com/p/5160a1b48679)

    使用方法

    1、支持Cocoapods
    OC版本 pod ‘MCTabBarController’
    Swift版本 pod ‘MCTabBarControllerSwift’
    2、将demo下载,MCTabBarController文件的内容拖入到项目中,直接创建自己的XXTabBarController 继承自MCTabBarController即可,具体的可参考demo中的例子 MCTabBarController ,如果对你要帮助,不要吝啬你的star哦?。

    需求分析 (本文以Bulge效果为例)

    • tabbar有5个item,每个对应一个页面
    • 中间item为凸起按钮
    • 中间按钮点击后旋转

    实现思路

    创建MCTabBar 继承自UITabBar,重写了中间按钮,并开放了中间按钮的各种属性

    typedef NS_ENUM(NSUInteger, MCTabBarCenterButtonPosition){
        MCTabBarCenterButtonPositionCenter, // 居中
        MCTabBarCenterButtonPositionBulge // 凸出一半
    };
    
    @interface MCTabBar : UITabBar
    /**
     中间按钮
     */
    @property (nonatomic, strong) UIButton *centerBtn;
    
    /**
      中间按钮图片
     */
    @property (nonatomic, strong) UIImage *centerImage;
    /**
     中间按钮选中图片
     */
    @property (nonatomic, strong) UIImage *centerSelectedImage;
    
    /**
     中间按钮偏移量,两种可选,也可以使用centerOffsetY 自定义
     */
    @property (nonatomic, assign) MCTabBarCenterButtonPosition position;
    
    /**
      中间按钮偏移量,默认是居中
     */
    @property (nonatomic, assign) CGFloat centerOffsetY; 
    
    /**
      中间按钮的宽和高,默认使用图片宽高
    */
    @property (nonatomic, assign) CGFloat centerWidth, centerHeight;
    
    • 添加凸起按钮
      我们可以在MCTabBar上添加我们的凸起按钮,让他的位置在没有设置的中间按钮偏上,按钮的点击和中间按钮点击绑定,但是会有下面的问题
      1、因为凸起按钮的frame超出了MCTabBar的frame,这样超出的区域点击按钮会没有响应(图二红框区域),原因和解决办法详情参考我的这篇iOS UIButton 点击无响应的解决办法,所以要处理点击无效的问题

    图二

    2、由于UITabBar是readonly的,所以我们不能直接对他进行赋值,这里利用KVC访问私有变量将MCTabBar赋值给"tabBar"
    具体实现
    MCTabBar

    #import "MCTabBar.h"
    #import "UIView+MCExtension.h"
    
    #define MCTabBarItemHeight    49.0f
    
    @interface MCTabBar()
    @end
    @implementation MCTabBar
    - (instancetype)init{
        if (self = [super init]){
            [self initView];
        }
        return self;
    }
    
    - (void)initView{
        _centerBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        //去除选择时高亮
        _centerBtn.adjustsImageWhenHighlighted = NO;
        [self addSubview:_centerBtn];
    }
    
    // 设置layout
    - (void)layoutSubviews {
        [super layoutSubviews];
        switch (self.position) {
            case MCTabBarCenterButtonPositionCenter:
                _centerBtn.frame = CGRectMake(([UIScreen mainScreen].bounds.size.width - _centerWidth)/2.0, (MCTabBarItemHeight - _centerHeight)/2.0 + self.centerOffsetY, _centerWidth, _centerHeight);
                break;
            case MCTabBarCenterButtonPositionBulge:
                 _centerBtn.frame = CGRectMake(([UIScreen mainScreen].bounds.size.width - _centerWidth)/2.0, -_centerHeight/2.0 + self.centerOffsetY, _centerWidth, _centerHeight);
                break;
            default:
                break;
        }
        
        _centerBtn.originX = ([UIScreen mainScreen].bounds.size.width - _centerBtn.width)/2.0;
    }
    
    - (void)setCenterImage:(UIImage *)centerImage {
        _centerImage = centerImage;
        // 如果设置了宽高则使用设置的大小
        if (self.centerWidth <= 0 && self.centerHeight <= 0){
            //根据图片调整button的位置(默认居中,如果图片中心在tabbar的中间最上部,这个时候由于按钮是有一部分超出tabbar的,所以点击无效,要进行处理)
            _centerWidth = centerImage.size.width;
            _centerHeight = centerImage.size.height;
        }
        [_centerBtn setImage:centerImage forState:UIControlStateNormal];
    }
    
    - (void)setCenterSelectedImage:(UIImage *)centerSelectedImage {
        _centerSelectedImage = centerSelectedImage;
        [_centerBtn setImage:centerSelectedImage forState:UIControlStateSelected];
    }
    
    //处理超出区域点击无效的问题
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
        if (self.hidden){
            return [super hitTest:point withEvent:event];
        }else {
            //转换坐标
            CGPoint tempPoint = [self.centerBtn convertPoint:point fromView:self];
            //判断点击的点是否在按钮区域内
            if (CGRectContainsPoint(self.centerBtn.bounds, tempPoint)){
                //返回按钮
                return _centerBtn;
            }else {
                return [super hitTest:point withEvent:event];
            }
        }
    }
    

    利用KVC赋值

    //MCTabBarController.m
    - (void)viewDidLoad {
        [super viewDidLoad];
        _mcTabbar = [[MCTabBar alloc] init];
        [_mcTabbar.centerBtn addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
        //利用KVC 将自己的tabbar赋给系统tabBar
        [self setValue:_mcTabbar forKeyPath:@"tabBar"];
        self.delegate = self;
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
    }
    
    - (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
        
        _mcTabbar.centerBtn.selected = (tabBarController.selectedIndex == self.viewControllers.count/2);
        
        if (self.mcDelegate){
            [self.mcDelegate mcTabBarController:tabBarController didSelectViewController:viewController];
        }
    }
    
    - (void)buttonAction:(UIButton *)button{
        NSInteger count = self.viewControllers.count;
        self.selectedIndex = count/2;//关联中间按钮
        [self tabBarController:self didSelectViewController:self.viewControllers[self.selectedIndex]];
    }
    
    • 点击旋转(自定义效果)
      在中间按钮的点击事件执行时旋转第二个index,然后执行旋转动画,
      在tabbar的代理事件中监听旋中中间按钮的事件,然后执行旋转动画,其他按钮则移除动画,代码如下
    @interface BulgeTabBarController ()<MCTabBarControllerDelegate>
    
    @end
    
    @implementation BulgeTabBarController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        //选中时的颜色
        self.mcTabbar.tintColor = [UIColor colorWithRed:251.0/255.0 green:199.0/255.0 blue:115/255.0 alpha:1];
        //透明设置为NO,显示白色,view的高度到tabbar顶部截止,YES的话到底部
        self.mcTabbar.translucent = NO;
        
        self.mcTabbar.position = MCTabBarCenterButtonPositionBulge;
        self.mcTabbar.centerImage = [UIImage imageNamed:@"tabbar_add_yellow"];
        self.mcDelegate = self;
        [self addChildViewControllers];
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        
    }
    
    //添加子控制器
    - (void)addChildViewControllers{
        //图片大小建议32*32
        [self addChildrenViewController:[[ViewController alloc] init] andTitle:@"首页" andImageName:@"tab1"];
        [self addChildrenViewController:[[ViewController alloc] init] andTitle:@"应用" andImageName:@"tab2"];
        //中间这个不设置东西,只占位
        [self addChildrenViewController:[[ViewController alloc] init] andTitle:@"发布" andImageName:@""];
        [self addChildrenViewController:[[ViewController alloc] init] andTitle:@"消息" andImageName:@"tab3"];
        [self addChildrenViewController:[[ViewController alloc] init] andTitle:@"我的" andImageName:@"tab4"];
    }
    
    - (void)addChildrenViewController:(UIViewController *)childVC andTitle:(NSString *)title andImageName:(NSString *)imageName{
        childVC.tabBarItem.image = [UIImage imageNamed:imageName];
        // 选中的颜色由tabbar的tintColor决定
        childVC.tabBarItem.selectedImage =  [UIImage imageNamed:imageName];
        childVC.title = title;
        
        BaseNavigationController *baseNav = [[BaseNavigationController alloc] initWithRootViewController:childVC];
        [self addChildViewController:baseNav];
    }
    
    - (void)mcTabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
        if (tabBarController.selectedIndex == 2){
            [self rotationAnimation];
        }else {
            [self.mcTabbar.centerBtn.layer removeAllAnimations];
        }
    }
    
    //旋转动画
    - (void)rotationAnimation{
        if ([@"key" isEqualToString:[self.mcTabbar.centerBtn.layer animationKeys].firstObject]){
            return;
        }
        CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
        rotationAnimation.toValue = [NSNumber numberWithFloat:M_PI*2.0];
        rotationAnimation.duration = 3.0;
        rotationAnimation.repeatCount = HUGE;
        [self.mcTabbar.centerBtn.layer addAnimation:rotationAnimation forKey:@"key"];
    }
    
    
    • 其他
      这里写了BaseNavigationController继承自UINavigationController,处理了push后隐藏底部UITabBar的情况,并解决了iPhonX上push时UITabBar上移的问题。

    最后,再次附上Demo地址,如果对你有所帮助,不要吝啬你的Star✨哦!MCTabBarController

    展开全文
  • iOS 自定义tabbar的高度和item。如何做啊,跪求大神告知!!!急急急
  • iOS之高度自定义TabBar的优雅实现需求的由来传统的实现更巧妙的实现总结遇见的问题记录 需求的由来 日常开发里,有时候产品经理会走过来丢给你一个无厘头的需求,App的底部TabBar 需要支持后台配置数量和动态替换...

    需求的由来

    日常开发里,有时候产品经理会走过来丢给你一个无厘头的需求,App的底部TabBar 需要支持后台配置数量和动态替换位置,还可以支持显示gif,还可以支持凸起效果,我的天,提我的40米大刀来,产品你先跑39米。对于这样的开发需求,有时候是很崩溃的,因为涉及到的业务代码改动可能就很大了。

    传统的实现

    传统实现自定义TabBar 的方式通过setValue:forKey:的方式给TabController赋值一个自定义的tab,因为这样我们能做的事毕竟也有限,因为自定义的TabBar归根于低依然是UITabBar类,能用api依然有限。

    如何做到完全让开发者随意去布局这个tabBar,思考想到了自定义view就好了,你需要什么样的效果就往上面加,需要注意的是做好约束相关变化监听。

    更巧妙的实现

    实现的一套TabBarItem-TabBar组合,通过addSubview:的方式添加到原生的TabBar上即可。
    相关实现如下:

    自定义TabBarItem的.h
    基本的UI控件

    @property (nonatomic, strong) UITabBarItem *tabBarItem;             //关联的原生TabBarItem
    @property (nonatomic, assign, getter=isSelected) BOOL selected;     //选择状态
    @property (nonatomic, strong) FLAnimatedImageView *imageView;       //图标
    @property (nonatomic, strong) UILabel *titleLabel;                  //文字
    @property (nonatomic, strong) UIColor *itemTitleColor;              //文字默认颜色
    @property (nonatomic, strong) UIColor *selectedItemTitleColor;      //文字选中颜色
    @property (nonatomic, strong) UIFont *itemTitleFont;                //文字字体
    @property (nonatomic, strong) UIFont *badgeTitleFont;               //Badge字体
    /**
     *  初始化,默认文字和图标间距参数,接近官方数据ratio为5pt
     */
    - (instancetype)initWithItemImageRatio:(CGFloat)itemImageRatio;
    

    自定义TabBarItem的.m
    需要监听原生的TabbarItem的相关值得变化,更新到自己的自定义item。

    [tabBarItem addObserver:self forKeyPath:@"image" options:NSKeyValueObservingOptionNew context:nil];
    [tabBarItem addObserver:self forKeyPath:@"selectedImage" options:NSKeyValueObservingOptionNew context:nil];
    [tabBarItem addObserver:self forKeyPath:@"badgeValue" options:NSKeyValueObservingOptionNew context:nil];
    [tabBarItem addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil];
    

    基类BaseTabBarController
    基类BaseTabBarController的主要工作有以下几个:

    1. loadView时添加自定义的tabBar到原生的TabBar上,设置事件代理和做好约束
    2. 在BaseTabBarController自身的生命相关周期函数里需要把原生的tabBarItem设置隐藏
    3. 重写 setViewControllers:函数,并启动监听,需要注意的是添加到导航控制器的方式不能使用addChildViewController:方式 添加到导航控制器的方式不能使用addChildViewController:方式
    4. 重写 setSelectedIndex:触发点击,让自定义的item监听到相关变化,从而更新状态和值。
    5. 如下方法展示

    隐藏原生item:

    #self.tabBar原生
    [self.tabBar.subviews enumerateObjectsUsingBlock:^(__kindof UIView * obj, NSUInteger idx, BOOL * stop) {
          if ([obj isKindOfClass:[UIControl class]]) {
              [obj setHidden:YES];
          }
    }];
    

    重写setViewControllers:

    #self.gtTabBar自定view
    // 1.赋值nav的方式只能选[setViewControllers:]
    - (void)setViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers{
       
        [self.gtTabBar.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
        self.gtTabBar.tabBarItems = [NSMutableArray array];
        
        for (UINavigationController *nav in viewControllers) {
            
            // 2.为了启动KVO,赋值和关联的tabBarItem需要相同
            NSString *title = nav.tabBarItem.title;
            nav.tabBarItem.title = title;
            [self.gtTabBar addTabBarItem:nav.tabBarItem];
        }
    
        [super setViewControllers:viewControllers];
    }
    

    重写setSelectedIndex:

    - (void)setSelectedIndex:(NSUInteger)selectedIndex {
        [super setSelectedIndex:selectedIndex];
        
        # 因为自定义的item监听有原生item的selected属性,当这里状态改变的同时,状态会传递到自定义的组合上。
        self.gtTabBar.selectedItem.selected = NO;
        self.gtTabBar.selectedItem = self.gtTabBar.tabBarItems[selectedIndex];
        self.gtTabBar.selectedItem.selected = YES;
    }
    

    最后自定义点击事件通过代理传递给外部

    #pragma mark - XXTabBarDelegate Method
    
    - (void)tabBar:(GTTabBar *)tabBarView didSelectedItemFrom:(NSInteger)from to:(NSInteger)to {
        
        self.selectedIndex = to;
    }
    

    总结

    1. 通过自定义一套组合的tabBar和item实现高度自定义的假tabBar,对于需要更高自定义的需求几乎可以很好支持,维护和扩展都很方便
    2. 目前也用在项目项目中,虽然遇见过一两个小问题,最后都解决了,算是完善该框架的实践代价

    遇见的问题记录

    Bug描述:
    记得有个bug-jira,测试小姐姐是这么描述的,在启动app过程中,退到后台再进去app偶发的自定义Tab上子控件位置显示位置不对或错乱,后来经过大量的测试,确实属实。

    出现的原因:
    因为在启动但未进入app首页的过程中,把app退出到后台时,某一些ios系统版本上TabBarController的部分生命周期函数不会走,这导致添加上去的自定义假Tab的生命周期函数也跟着不准,从而引出这个偶发的bug。

    解决途径:
    监听程序从后台回到前台的系统通知UIApplicationDidBecomeActiveNotification,从而再次检查TabBarController和定义的tabBar的相关约束,走一次layoutIfNeed就好了。

    展开全文
  • 这是一个自定义TabBar样式,实现TabBar中间凸起“ ”按钮
  • IOS 自定义UITabBar ,中间按钮凸出 很多项目中都有中间凸出的UI设计,这个不规则的设计才坑爹,必须要自定义。在安卓上 做这个也是坑,现在只说ios的实现。 示意图:  问题和难点: 横线,凸出...

    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);
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    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];
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304

    补一个图,这个是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{
    
    
    }
    展开全文
  • iOS TabBar中间凸起实践

    2018-10-16 15:02:07
    tabbar的话也是遵循主流,自定义一个继承自系统UITabbar的HQTabbar,然后用KVC和系统的进行替换中间的凸起按钮和tabbar内部的子控件不是同一类型,是一个UIButton而已,根据tabbar内部子控件的类型去调整内部子控件...
  • 代码实现 这里我借鉴了上文作者的代码,针对我的需要进行了封装,下面放代码:   ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ...2
  • 大多数应用使用系统自带的Tabbar就能够满足需求 通常情况都是在AppDelegate.m里创建一个UITabBarController将其它的控制器用UINavigationController包装一层,再添加到UITabBarController的viewControllers里。再将...
  • ⊙ 支持自定义tabBar动画 ⊙ 支持自定义tabBar样式 ⊙ 支持自定义badgeValue动画 ⊙ 支持自定义badgeValue样式 ⊙ 完美支持横竖屏 ⊙ 支持CocoaPods 更多说明请移步github github地址: ...
  • 【原】ios的hitTest方法以及不规则区域内触摸事件处理方法 概述 在正常的使用场景中,我们处理了比较多的矩形区域内触摸事件,比如UIButton、UIControl。一般来说,这些控件的图形以及触摸区域都是...
  • iOS Tabbar凸起效果

    2020-06-24 14:44:48
    之前没有研究过凸起这种效果,知道项目用到了 才来仔细研究,之前看似高大上的效果其实实现起来还是挺简单的。 自定义UITabbar: 只要代码都写在了layoutSubviews方法里,为了让拿到系统“UITabBarButton”的frame `...
  • 使用贝塞尔曲线来画一个tabbar的背景图,自定义一个view 重写view的drawRect方法,代码如下: -(void)drawRect:(CGRect)rect{  CGFloat lineY = 0;  CGFloat radiu = 0;  CGFloat lineWidth
  • iOS自定义TabBar

    2019-05-08 17:13:39
    自定义效果: 实现方法: 1、继承UITabBar并自定义样式 .h 文件 #import <UIKit/UIKit.h> @interface KYCustomTabBar : UITabBar @end 自定义实现部分代码: #import "KYCustomTabBar.h...
  • demo :http://download.csdn.net/detail/knowingnow/9447891
  • 前一段微博上很火的tabbar封装大赛想必大家都知道吧,各位大神尽其所能自己正在仿写闲鱼,看了网上一些朋友写的关于tabbar中间按钮的处理,发现关于处理中间按钮的点击这块有点模糊个人估计是大家在写这一块的时候...
  • 本文主要针对底部凸起TabBar 这种特殊需求,不感兴趣的可以直接绕过~ 最近做的一个项目需要底部凸起TabBar,效果如下: 考虑到 iOS 原生 UITableBar 的定制比较麻烦,所以决定先找一下第三方的解决方案,...
1 2 3 4 5 ... 9
收藏数 180
精华内容 72