最新項(xiàng)目中,遇到定制標(biāo)簽的需求亥鸠,類試于『閑魚』,于是找網(wǎng)上找了幾個Demo學(xué)習(xí)识啦,發(fā)現(xiàn)實(shí)現(xiàn)的方法大概有兩種
1负蚊、創(chuàng)建一個UIView覆蓋在原來的tabBar上方,在UIView中定義一個協(xié)議颓哮,并且通過這個協(xié)議方法回調(diào)來設(shè)置當(dāng)前tabBar的index盖桥,從而實(shí)現(xiàn)視圖的切換。當(dāng)然這也能實(shí)現(xiàn)同樣的效果题翻,不過不推薦使用這種方法揩徊,畢竟這始終是一種土方法,后期添加功能不方便嵌赠,例如添加紅點(diǎn)塑荒。
2、通過繼承重寫的方法姜挺,修改原生tabBar的布局齿税,中間的『加號』是通過創(chuàng)建一個按鈕,添加原生tabBar上的炊豪,并且通過協(xié)議方法回調(diào)加號按鈕的點(diǎn)擊事件凌箕。
詳細(xì)請看代碼:
tabBarViewController子類
#import "MZTabBarViewController.h"
#import "OneViewController.h"
#import "TwoViewController.h"
#import "ThreeViewController.h"
#import "FoureViewController.h"
#import "MZTabBar.h"
#import "MZNavigationController.h"
@interface MZTabBarViewController ()<MZTabBarDelegate>
@end
@implementation MZTabBarViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self addViewController:[OneViewController new] title:@"閑魚" ItemImage:[UIImage imageNamed:@"home_normal@2x.png"] ItemSelectedImage:[UIImage imageNamed:@"home_highlight@2x.png"]];
[self addViewController:[OneViewController new] title:@"魚塘" ItemImage:[UIImage imageNamed:@"fish_normal@2x.png"] ItemSelectedImage:[UIImage imageNamed:@"fish_highlight@2x.png"]];
[self addViewController:[OneViewController new] title:@"消息" ItemImage:[UIImage imageNamed:@"message_normal@2x.png"] ItemSelectedImage:[UIImage imageNamed:@"message_highlight@2x.png"]];
[self addViewController:[OneViewController new] title:@"我的" ItemImage:[UIImage imageNamed:@"account_normal@2x.png"] ItemSelectedImage:[UIImage imageNamed:@"account_highlight@2x.png"]];
MZTabBar *tabBar = [[MZTabBar alloc]init];
tabBar.delegate = self;
//重點(diǎn):因?yàn)橄到y(tǒng)的tabBar的屬性是只讀的,所以只能通過KVC方式替換系統(tǒng)的tabBar
//替換tabBar的目的:1词渤、創(chuàng)建"發(fā)布按鈕" 2牵舱、重新布局item的位置
[self setValue:tabBar forKey:@"tabBar"];
}
- (void)addViewController:(UIViewController *)vc title:(NSString *)title ItemImage:(UIImage *)image ItemSelectedImage:(UIImage *)selectedImage{
vc.title = title;
vc.tabBarItem.image = image;
//設(shè)置item選中圖片,前提是要設(shè)置圖片的模式『原圖』展示
vc.tabBarItem.selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
NSDictionary *dicNor = @{
NSForegroundColorAttributeName:[UIColor colorWithRed:123/255.0 green:123/255.0 blue:123/255.0 alpha:1.0]
};
[vc.tabBarItem setTitleTextAttributes:dicNor forState:UIControlStateNormal];
NSDictionary *dicSelected = @{
NSForegroundColorAttributeName:[UIColor orangeColor]
};
[vc.tabBarItem setTitleTextAttributes:dicSelected forState:UIControlStateSelected];
MZNavigationController *nac = [[MZNavigationController alloc]initWithRootViewController:vc];
[self addChildViewController:nac];
}
#pragma mark - MZTabBar Delegate
- (void)tabBarDidClickPlusButton:(MZTabBar *)tabBar{
NSLog(@"中間加號按鈕點(diǎn)擊");
}
NavigationCtroller 子類
#import "MZNavigationController.h"
@interface MZNavigationController ()
@end
@implementation MZNavigationController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
+ (void)initialize{
UIBarButtonItem *barItem = [UIBarButtonItem appearance];
//設(shè)置普通狀態(tài)
NSDictionary *dicNormal = @{NSForegroundColorAttributeName:[UIColor orangeColor],NSFontAttributeName:[UIFont systemFontOfSize:13]};
[barItem setTitleTextAttributes:dicNormal forState:UIControlStateNormal];
//設(shè)置不可用狀態(tài)
NSDictionary *dicDisabled = @{NSForegroundColorAttributeName:[UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:0.7],NSFontAttributeName:[UIFont systemFontOfSize:13]};
[barItem setTitleTextAttributes:dicDisabled forState:UIControlStateDisabled];
}
//重寫這個方法缺虐,目的是攔截所有push進(jìn)來的控制器
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
if (self.viewControllers.count>0) {
//這是push進(jìn)來的控制器不是第一個控制器
viewController.hidesBottomBarWhenPushed = YES;
}
[super pushViewController:viewController animated:animated];
}
@end
tabBar的子類
#import <UIKit/UIKit.h>
@class MZTabBar;
@protocol MZTabBarDelegate<UITabBarDelegate>
- (void)tabBarDidClickPlusButton:(MZTabBar *)tabBar;
@end
@interface MZTabBar : UITabBar
@property (nonatomic,weak) id<MZTabBarDelegate>delegate;
@end
#import "MZTabBar.h"
@interface MZTabBar()
@property (nonatomic,strong) UIButton *plusBtn;
@end
@implementation MZTabBar
- (instancetype)init{
self = [super init];
if (self) {
UIButton *plusBtn = [[UIButton alloc]init];
[plusBtn setBackgroundImage:[UIImage imageNamed:@"post_normal@2x.png"] forState:UIControlStateNormal];
[plusBtn addTarget:self action:@selector(plusBtnClick:) forControlEvents:UIControlEventTouchUpInside];
CGSize newSize = plusBtn.currentBackgroundImage.size;
plusBtn.frame = CGRectMake(0, 0, newSize.width, newSize.height);
[self addSubview:plusBtn];
_plusBtn = plusBtn;
}
return self;
}
- (void)plusBtnClick:(UIButton *)sender{
[self.delegate tabBarDidClickPlusButton:self];
}
- (void)layoutSubviews{
[super layoutSubviews];
CGFloat width = self.frame.size.width;
CGFloat height = self.frame.size.height;
//設(shè)置發(fā)布按鈕的位置
_plusBtn.center = CGPointMake(width/2, height/2-20);
//遍歷tabBar的所有控件芜壁,并重新布局,中間的位置空出來
//系統(tǒng)自帶的按鈕類型是UITabBarButton
Class class = NSClassFromString(@"UITabBarButton");
int index = 0;
for (UIView *btn in self.subviews) {
if ([btn isKindOfClass:class]) {
CGRect rect = btn.frame;
rect.origin.x = width/5 * index;
rect.size.width = width/5;
btn.frame = rect;
index++;
//如果是中間位置,則直接跳過高氮,空出來
if (index == 2) {
index++;
}
}
}
}
//重寫hitTest方法慧妄,去監(jiān)聽發(fā)布按鈕的點(diǎn)擊,目的按時為了讓凸出部分點(diǎn)擊也有反應(yīng)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
/*
這個判斷是關(guān)鍵剪芍,不判斷的話push到其他頁面塞淹,點(diǎn)擊發(fā)布按鈕的位置也是會有反應(yīng)的,這樣就不好了
self.isHidden == NO 說明當(dāng)前頁面是有tabBar的罪裹,那么肯定是再導(dǎo)航控制器的根控制器頁面
在導(dǎo)航控制器根控制器頁面饱普,那么我們就需要判斷手指點(diǎn)擊的位置是否再發(fā)布按鈕身上
是的話运挫,讓發(fā)布按鈕自己處理點(diǎn)擊事件,不是的話讓系統(tǒng)去處理點(diǎn)擊事件就可以了
這里有一個理解的關(guān)鍵點(diǎn):傳動鏈?zhǔn)菑南峦系姆驯耍簿褪菑淖畹讓娱_始往頂層遍歷UIResporter的子類
因?yàn)檫@個框架是UITabBar -- UINavigation -- ViewController -- view,所以Window首先
是把UIEvent事件傳遞給UITabBar的口芍,這時重寫hitTest方法箍铲,攔截事件并返回plusBtn,系統(tǒng)就會繼續(xù)調(diào)用
plusBtn的hitTest方法遍歷其所有的子類,確定事件的第一響應(yīng)者鬓椭。
*/
if (self.isHidden == NO) {
//將當(dāng)前tabBar的觸摸點(diǎn)轉(zhuǎn)換坐標(biāo)系颠猴,轉(zhuǎn)換到發(fā)布按鈕的身上,生成一個新的點(diǎn)
CGPoint newPoint = [self convertPoint:point toView:self.plusBtn];
//判斷這個新的點(diǎn)是否在發(fā)布按鈕身上小染,若是翘瓮,那么處理點(diǎn)擊事件的最合適的view就是發(fā)布按鈕
if ([self.plusBtn pointInside:newPoint withEvent:event]) {
return self.plusBtn;
}else{
//如果不在發(fā)布按鈕身上,直接讓系統(tǒng)處理就好
return [super hitTest:point withEvent:event];
}
}else{
//tabBar隱藏了裤翩,那么說明已經(jīng)push到其他的頁面了资盅,這個時候還是讓系統(tǒng)去判斷最合適的view處理就好了
return [super hitTest:point withEvent:event];
}
}