TabBar自定义Button按钮

实现效果如下:

实现效果.png

*首先介绍一下组成部分:
1.有一个UITabBarController用来控制基本的四个页面(四个页面又作为NavigationController的根视图: 方便跳转)
2.有一个UITabBar视图, 就是我们要自定义的tabBar视图. 我们在上面进行布局


*视图的层次结构:(上为根的根视图)
(上)UIViewController--> UINavigationController--> UITabBarController(根)


*工程结构

工程结构.png

第一步: 首先在AppDelegate文件中, 将TabBarController 设置为window的根视图控制器

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.backgroundColor = [UIColor whiteColor];
    
    //创建Tabbar
    LBTabBarController *tabBarVc = [[LBTabBarController alloc] init];
    
    
    //添加转场动画
    CATransition *anim = [[CATransition alloc] init];
    anim.type = @"rippleEffect";
    anim.duration = 1.0;
    
    [self.window.layer addAnimation:anim forKey:nil];
    
    
    # 将TabBar指定根视图控制器
    self.window.rootViewController = tabBarVc;
    [self.window makeKeyAndVisible];
    
    return YES;
}

第二步: 创建TabBarController控制器,在TabBarController.m中设置被管理的子视图控制器

#import "LBTabBarController.h"
#import "LBNavigationController.h"

//四个基本的视图控制器页面
#import "LBMessageVC.h"
#import "LBFishVC.h"
#import "LBHomeVC.h"
#import "LBMineVC.h"

//自定义的tabBar
#import "LBTabBar.h"

@interface LBTabBarController ()<LBTabBarDelegate>

@end

@implementation LBTabBarController

#pragma mark - 第一次使用当前类的时候对设置UITabBarItem的主题
/*
 + (void)initialize
{
    UITabBarItem *tabBarItem = [UITabBarItem appearanceWhenContainedInInstancesOfClasses:@[self]];
    
    NSMutableDictionary *dictNormal = [NSMutableDictionary dictionary];
    dictNormal[NSForegroundColorAttributeName] = [UIColor grayColor];
    dictNormal[NSFontAttributeName] = [UIFont systemFontOfSize:11];
    
    NSMutableDictionary *dictSelected = [NSMutableDictionary dictionary];
    dictSelected[NSForegroundColorAttributeName] = [UIColor darkGrayColor];
    dictSelected[NSFontAttributeName] = [UIFont systemFontOfSize:11];
    
    [tabBarItem setTitleTextAttributes:dictNormal forState:UIControlStateNormal];
    [tabBarItem setTitleTextAttributes:dictSelected forState:UIControlStateSelected];
    
}
 */

- (void)viewDidLoad {
    [super viewDidLoad];
    
    #第一步:
    [self setUpAllChildVC];                       //调用该类的私有方法, 初始化设置tabBar上的所有子视图
    
    #第二步:
    LBTabBar *tabBar = [[LBTabBar alloc] init];   //初始化自定义的tabBar视图
    tabBar.MyDelegate = self;                     //设置代理
    [self setValue:tabBar forKey:@"tabBar"];      //替换原有的tabBar视图

}

#第一步方法:   初始化tabBar上除了中间按钮之外所有的按钮

- (void)setUpAllChildVC{
    
    LBHomeVC *HomeVC = [LBHomeVC new];
    [self setUpOneChildVcWithVc:HomeVC Image:@"home_normal" selectedImage:@"home_highlight" title:@"首页"];
    
    
    LBFishVC *FishVC = [LBFishVC new];
    [self setUpOneChildVcWithVc:FishVC Image:@"fish_normal" selectedImage:@"fish_highlight" title:@"鱼塘"];
    
    
    LBMessageVC *MessageVC = [[LBMessageVC alloc] init];
    [self setUpOneChildVcWithVc:MessageVC Image:@"message_normal" selectedImage:@"message_highlight" title:@"消息"];
    
    
    LBMineVC *MineVC = [[LBMineVC alloc] init];
    [self setUpOneChildVcWithVc:MineVC Image:@"account_normal" selectedImage:@"account_highlight" title:@"我的"];
    
}

#pragma mark ------------ 具体的赋值方法 ----------------
/*为每一个视图控制器指定对应的tabBarButton样式

 1. 设置每个按钮对应的VC
 2. 设置每个按钮对应的普通状态下的图片
 3. 设置每个按钮对应的选中状态下的图片
 4. 设置每个按钮对应的标题
 
 */
- (void)setUpOneChildVcWithVc:(UIViewController *)Vc Image:(NSString *)image selectedImage:(NSString *)selectedImage title:(NSString *)title{
    # 当然实现该方法的时候, 需要去创建NavigationController了
    LBNavigationController *nav = [[LBNavigationController alloc] initWithRootViewController:Vc];
    Vc.view.backgroundColor = [self randomColor];
    
    UIImage *MyImage = [UIImage imageNamed:image];
    MyImage = [MyImage imageWithRenderingMode:(UIImageRenderingModeAlwaysOriginal)];
    Vc.tabBarItem.image = MyImage;
    
    UIImage *selImage = [UIImage imageNamed:selectedImage];
    selImage = [selImage imageWithRenderingMode:(UIImageRenderingModeAlwaysOriginal)];
    Vc.tabBarItem.selectedImage = selImage;
    
    
    Vc.tabBarItem.title = title;
    Vc.navigationItem.title = title;
    
    [self addChildViewController:nav];
    
}

#pragma mark - LBTabBarDelegate
//点击中间按钮的代理方法
- (void)tabBarPlusBtnClick:(LBTabBar *)tabBar
{

    NSLog(@"AAAAAAAAAAAAAAA");

}

#pragma mark - 随机颜色的实现方法
- (UIColor *)randomColor
{
    CGFloat r = arc4random_uniform(256);
    CGFloat g = arc4random_uniform(256);
    CGFloat b = arc4random_uniform(256);
    return [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1.0];
    
}

@end

第三步: 文件三NavigationController.m文件


#import "LBNavigationController.h"
#import "UIImage+Image.h"

//黄色导航栏
#define NavBarColor [UIColor colorWithRed:250/255.0 green:227/255.0 blue:111/255.0 alpha:1.0]
@interface LBNavigationController ()

@end

@implementation LBNavigationController

- (void)viewDidLoad {
    [super viewDidLoad];

}

+ (void)load{
    
    //设置tabbar的文字属性
    UIBarButtonItem *item = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[self]];
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    dic[NSFontAttributeName] = [UIFont systemFontOfSize:15];
    dic[NSForegroundColorAttributeName] = [UIColor blackColor];
    [item setTitleTextAttributes:dic forState:UIControlStateNormal];
    
    
    
    //设置navigationBar的属性
    UINavigationBar *navBar = [UINavigationBar appearanceWhenContainedInInstancesOfClasses:@[self]];
    [navBar setBackgroundImage:[UIImage imageWithColor:NavBarColor] forBarMetrics:UIBarMetricsDefault];
    NSMutableDictionary *navDic = [NSMutableDictionary dictionary];
    navDic[NSFontAttributeName] = [UIFont systemFontOfSize:15];
    [navBar setTitleTextAttributes:navDic];
    
}

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
    
    if (self.viewControllers.count > 0) {
        
        //隐藏tabBar
        viewController.hidesBottomBarWhenPushed = YES;
    }
    
    return [super pushViewController:viewController animated:YES];
}

@end

第四步: 自定义TabBar的具体实现文件了
tabBar.h文件

#import <UIKit/UIKit.h>

@class LBTabBar;

//声明一个协议 + 协议方法
@protocol LBTabBarDelegate <NSObject>
@optional
- (void)tabBarPlusBtnClick:(LBTabBar *)tabBar;
@end


@interface LBTabBar : UITabBar
//设置代理属性
@property (weak, nonatomic) id<LBTabBarDelegate>  MyDelegate;
@end

tabBar.m文件

#import "LBTabBar.h"
#import "UIImage+Image.h"
#import "UIView+LBExtension.h"

#define LBMagin 10

@interface LBTabBar ()

//按钮
@property (nonatomic, weak) UIButton *plusBtn;

@end

@implementation LBTabBar

- (instancetype)initWithFrame:(CGRect)frame{
    
    if (self = [super initWithFrame:frame]) {
        
        self.backgroundColor = [UIColor whiteColor];
        [self setShadowImage:[UIImage imageWithColor:[UIColor clearColor]]];
        
        
        //设置按钮不同状态时的图片
        UIButton *plusBtn = [[UIButton alloc] init];
        [plusBtn setBackgroundImage:[UIImage imageNamed:@"post_normal"] forState:UIControlStateNormal];
        
        [plusBtn setBackgroundImage:[UIImage imageNamed:@"post_normal"] forState:UIControlStateHighlighted];
        
        //指定按钮
        self.plusBtn = plusBtn;
        
        
        //给按钮添加事件
        [self.plusBtn addTarget: self action:@selector(plusBtnDidClick) forControlEvents:UIControlEventTouchUpInside];
        
        //添加到视图上
        [self addSubview:plusBtn];
        
    }
    return self;
}

//点击发布按钮事件实现
- (void)plusBtnDidClick{
    
    //如果tabbar的代理实现了对应的代理方法, 那么就调用代理的方法
    if ([self.delegate respondsToSelector:@selector(tabBarPlusBtnClick:)]) {
        
        //实现代理方法
        [self.MyDelegate tabBarPlusBtnClick:self];
    }
    
}

- (void)layoutSubviews{
    
    [super layoutSubviews];
    
    //这里需要调用一个延展类的方法(文章下面说明内部实现)
    self.plusBtn.centerX = self.centerX;
    
    //调整发布按钮的中线点Y值
    self.plusBtn.centerY = self.height * 0.5 - 2 *LBMagin;
    
    self.plusBtn.size = CGSizeMake(self.plusBtn.currentBackgroundImage.size.width, self.plusBtn.currentBackgroundImage.size.height);
    
    
    //文字
    UILabel *label = [[UILabel alloc] init];
    label.text = @"发布";
    label.font = [UIFont systemFontOfSize:11];
    [label sizeToFit];
    label.textColor = [UIColor grayColor];
    [self addSubview:label];
    label.centerX = self.plusBtn.centerX;
    label.centerY = CGRectGetMaxY(self.plusBtn.frame) + LBMagin ;
    
    
    //系统自带的按钮类型是UITabBarButton, 找出这些类型的按钮, 然后重新排布位置, 空出中间的位置
    Class class = NSClassFromString(@"UITabBarButton");
    
    int btnIndex = 0;
    for (UIView *btn in self.subviews) {//遍历tabBar的子控件
        
        //判断是系统自带的视图
        if ([btn isKindOfClass:class]) {
            
            //么就调整子控件位置,空出中间位置
            //每个按钮的宽度 == tabBar的五分之一
            btn.width = self.width / 5;
            btn.x = btn.width * btnIndex;
            
            btnIndex++;
            
            //如果索引是2 (从0)开始) , 则直接让索引++(目的就是让消息按钮的位置向右移动,空出来发布按钮的位置)
            if (btnIndex == 2) {
                
                btnIndex++;
            }
            
        
        }
    }
    
    [self bringSubviewToFront:self.plusBtn];
    
    
}

//重写hitTest方法, 去监听发布按钮的点击, 目的是为了让凸出的部分也能响应点击事件
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    
    //这是一个判断的关键, 不判断的话push到其他页面, 点击发布按钮的位置也是会有反应的, 这样就不好了
    //self.isHidden == NO 说明当前页面是有tabbar的,那么肯定是在导航控制器的根控制器页面
    //在导航控制器根控制器页面,那么我们就需要判断手指点击的位置是否在发布按钮身上
    //是的话让发布按钮自己处理点击事件,不是的话让系统去处理点击事件就可以了
    if (self.isHidden == NO) {
        
        //将当前tabbar的触摸点转换坐标系,转换到发布按钮的身上,生成一个新的点
        CGPoint newP = [self convertPoint:point toView:self.plusBtn];
        
        //判断如果这个新的点是在发布按钮身上,那么处理点击事件最合适的view就是发布按钮
        if ( [self.plusBtn pointInside:newP withEvent:event]) {
            return self.plusBtn;
        }else{//如果点不在发布按钮身上,直接让系统处理就可以了
            
            return [super hitTest:point withEvent:event];
        }
    }
    
    else {//tabbar隐藏了,那么说明已经push到其他的页面了,这个时候还是让系统去判断最合适的view处理就好了
        return [super hitTest:point withEvent:event];
    }

}

@end

两个延展类的实现
UIImage的延展实现:

#----------------------------UIImage+image.h文件
@interface UIImage (Image)

/*
 根据颜色生成一张图片
 @param imageName提供的颜色
 
 */

+(UIImage *)imageWithColor:(UIColor *)color;

@end


#---------------------------UIImage+image.m文件
#import "UIImage+Image.h"

@implementation UIImage (Image)

/*
 根据颜色生成一张图片
 @param imageName提供的颜色
 
 */

+(UIImage *)imageWithColor:(UIColor *)color{
    
    //描述一个矩形
    CGRect rect = CGRectMake(0, 0, 1, 1);
    
    //开始图形上下文
    UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
    
    //获得图形上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    
    //使用color填充山下文
    CGContextSetFillColorWithColor(ctx, [color CGColor]);
    
    //渲染上下文
    CGContextFillRect(ctx, rect);
    
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    
    //关闭上下文
    UIGraphicsEndImageContext();
    
    return image;
    
    
}

@end

UIView类的延展

#UIView+LBExtension.h-------------------------
#import <UIKit/UIKit.h>
IB_DESIGNABLE
@interface UIView (LBExtension)
@property (nonatomic, assign)CGFloat x;
@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

#UIView+LBExtension.m-------------------------
#import "UIView+LBExtension.h"
@implementation UIView (LBExtension)
- (void)setX:(CGFloat)x
{
    CGRect frame = self.frame;
    frame.origin.x = x;
    self.frame = frame;
}
- (CGFloat)x
{
    return self.frame.origin.x;
}
- (void)setWidth:(CGFloat)width
{
    CGRect frame = self.frame;
    frame.size.width = width;
    self.frame = frame;
}
- (CGFloat)width
{
    return self.frame.size.width;
}
- (void)setHeight:(CGFloat)height
{
    CGRect frame = self.frame;
    frame.size.height = height;
    self.frame= frame;
}
- (CGFloat)height
{
    return self.frame.size.height;
}
- (void)setSize:(CGSize)size
{
    CGRect frame = self.frame;
    frame.size = size;
    self.frame = frame;
}
- (CGSize)size
{
    return self.frame.size;
}
- (void)setCenterX:(CGFloat)centerX
{
    CGPoint center = self.center;
    center.x = centerX;
    self.center = center;
}
- (CGFloat)centerX
{
    return self.center.x;
}
- (void)setCenterY:(CGFloat)centerY
{
    CGPoint center = self.center;
    center.y = centerY;
    self.center = center;
}
- (CGFloat)centerY
{
    return self.center.y;
}
@end

代码部分完成 !

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • *7月8日上午 N:Block :跟一个函数块差不多,会对里面所有的内容的引用计数+1,想要解决就用__block...
    炙冰阅读 2,477评论 1 14
  • 在iOS原生的tabBar中,能够实现按钮的点击事件,能够实现视图控制器的切换等,但是在实际工程中,对于tabBa...
    请输入账号名阅读 22,166评论 9 11
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • 废话不多说,直接上干货 ---------------------------------------------...
    小小赵纸农阅读 3,343评论 0 15
  • 日子仿佛停止了呼吸,我和叶子躲在地底下,透过雪隙窥探到的阳光是米黄色的。那是我最爱的颜色。 很想换个大书架,好多书...
    陈旧啊阅读 234评论 10 3