前言
最近的項目中有需求在tabbar中間添加凸起按鈕矢赁,并且點擊時按鈕要旋轉(zhuǎn),看了仿閑魚的凸起,點擊后是present出來View,而不是像常規(guī)的tabbar上添加一個頁面(親測唠叛,閑魚的超出Tabbar部分點擊是沒有反應(yīng)的,這是bug啊沮稚,下文對這個問題有詳解)艺沼,所以不符合要求,經(jīng)過一段摸索最后得的一個比較好的效果蕴掏,下面看效果圖
效果圖.gif
(本文簡書地址:http://www.reibang.com/p/5160a1b48679)
使用方法
1障般、支持Cocoapods
OC版本 pod 'MCTabBarController'
Swift版本 pod 'MCTabBarControllerSwift'
2、將demo下載囚似,MCTabBarController文件的內(nèi)容拖入到項目中,直接創(chuàng)建自己的XXTabBarController 繼承自MCTabBarController即可线得,具體的可參考demo中的例子 MCTabBarController 饶唤,如果對你要幫助,不要吝嗇你的star哦??贯钩。
需求分析 (本文以Bulge效果為例)
- tabbar有5個item募狂,每個對應(yīng)一個頁面
- 中間item為凸起按鈕
- 中間按鈕點擊后旋轉(zhuǎn)
實現(xiàn)思路
創(chuàng)建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;
/**
中間按鈕偏移量性穿,默認(rèn)是居中
*/
@property (nonatomic, assign) CGFloat centerOffsetY;
/**
中間按鈕的寬和高,默認(rèn)使用圖片寬高
*/
@property (nonatomic, assign) CGFloat centerWidth, centerHeight;
- 添加凸起按鈕
我們可以在MCTabBar上添加我們的凸起按鈕雷滚,讓他的位置在沒有設(shè)置的中間按鈕偏上需曾,按鈕的點擊和中間按鈕點擊綁定,但是會有下面的問題
1祈远、因為凸起按鈕的frame超出了MCTabBar的frame呆万,這樣超出的區(qū)域點擊按鈕會沒有響應(yīng)(圖二紅框區(qū)域),原因和解決辦法詳情參考我的這篇iOS UIButton 點擊無響應(yīng)的解決辦法车份,所以要處理點擊無效的問題
圖二
2谋减、由于UITabBar是readonly的,所以我們不能直接對他進(jìn)行賦值扫沼,這里利用KVC訪問私有變量將MCTabBar賦值給"tabBar"
具體實現(xiàn)
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];
}
// 設(shè)置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;
// 如果設(shè)置了寬高則使用設(shè)置的大小
if (self.centerWidth <= 0 && self.centerHeight <= 0){
//根據(jù)圖片調(diào)整button的位置(默認(rèn)居中出爹,如果圖片中心在tabbar的中間最上部,這個時候由于按鈕是有一部分超出tabbar的缎除,所以點擊無效严就,要進(jìn)行處理)
_centerWidth = centerImage.size.width;
_centerHeight = centerImage.size.height;
}
[_centerBtn setImage:centerImage forState:UIControlStateNormal];
}
- (void)setCenterSelectedImage:(UIImage *)centerSelectedImage {
_centerSelectedImage = centerSelectedImage;
[_centerBtn setImage:centerSelectedImage forState:UIControlStateSelected];
}
//處理超出區(qū)域點擊無效的問題
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
if (self.hidden){
return [super hitTest:point withEvent:event];
}else {
//轉(zhuǎn)換坐標(biāo)
CGPoint tempPoint = [self.centerBtn convertPoint:point fromView:self];
//判斷點擊的點是否在按鈕區(qū)域內(nèi)
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賦給系統(tǒng)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;//關(guān)聯(lián)中間按鈕
[self tabBarController:self didSelectViewController:self.viewControllers[self.selectedIndex]];
}
- 點擊旋轉(zhuǎn)(自定義效果)
在中間按鈕的點擊事件執(zhí)行時旋轉(zhuǎn)第二個index,然后執(zhí)行旋轉(zhuǎn)動畫伴找,
在tabbar的代理事件中監(jiān)聽旋中中間按鈕的事件盈蛮,然后執(zhí)行旋轉(zhuǎn)動畫,其他按鈕則移除動畫技矮,代碼如下
@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];
//透明設(shè)置為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:@"應(yīng)用" andImageName:@"tab2"];
//中間這個不設(shè)置東西袒炉,只占位
[self addChildrenViewController:[[ViewController alloc] init] andTitle:@"發(fā)布" 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];
}
}
//旋轉(zhuǎn)動畫
- (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