iOS Tabbar中間添加凸起可旋轉(zhuǎn)按鈕(定制按鈕)

前言

最近的項目中有需求在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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末沉衣,一起剝皮案震驚了整個濱河市郁副,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌豌习,老刑警劉巖存谎,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拔疚,死亡現(xiàn)場離奇詭異,居然都是意外死亡既荚,警方通過查閱死者的電腦和手機(jī)稚失,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來恰聘,“玉大人句各,你說我怎么就攤上這事『┝眨” “怎么了诫钓?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長篙螟。 經(jīng)常有香客問我菌湃,道長,這世上最難降的妖魔是什么遍略? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任惧所,我火速辦了婚禮,結(jié)果婚禮上绪杏,老公的妹妹穿的比我還像新娘下愈。我一直安慰自己,他們只是感情好蕾久,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布势似。 她就那樣靜靜地躺著,像睡著了一般僧著。 火紅的嫁衣襯著肌膚如雪履因。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天盹愚,我揣著相機(jī)與錄音栅迄,去河邊找鬼。 笑死皆怕,一個胖子當(dāng)著我的面吹牛毅舆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播愈腾,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼憋活,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了虱黄?” 一聲冷哼從身側(cè)響起悦即,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后盐欺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡仅醇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年冗美,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片析二。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡粉洼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出叶摄,到底是詐尸還是另有隱情属韧,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布蛤吓,位于F島的核電站宵喂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏会傲。R本人自食惡果不足惜锅棕,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淌山。 院中可真熱鬧裸燎,春花似錦、人聲如沸泼疑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽退渗。三九已至移稳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間氓辣,已是汗流浹背秒裕。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留钞啸,地道東北人几蜻。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像体斩,于是被迫代替她去往敵國和親梭稚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容