在小編整理過(guò)的文章iOS項(xiàng)目基本框架搭建中,我們?cè)敿?xì)說(shuō)明了如何對(duì)TabBarItem的圖片屬性以及文字屬性進(jìn)行一些自定義配置。但是,很多時(shí)候,我們需要修改TabBarItem的圖片和文字屬性之外,還需要自定義TabBarItem的位置,這樣系統(tǒng)自帶的TabBar的樣式并不能滿足我們的項(xiàng)目需求,所以我們需要對(duì)系統(tǒng)的UITabBar進(jìn)行自定義,以達(dá)到我們的項(xiàng)目需求。例如新浪微博App的底部tab的item就無(wú)法用自帶的TabBarItem進(jìn)行實(shí)現(xiàn),最中間那個(gè)【+】發(fā)布微博并不是用來(lái)切換tab的,而是在當(dāng)前的頁(yè)面上覆蓋一個(gè)編輯發(fā)布頁(yè)面,發(fā)布完成或者取消發(fā)布之后又回到之前的頁(yè)面,并沒(méi)有進(jìn)行切換,這時(shí)候我們就需要對(duì)TabBar進(jìn)行自定義,在最中間空出一個(gè)TabBar的空間進(jìn)行布置這個(gè)【+】發(fā)布按鈕。
我們的項(xiàng)目是仿寫(xiě)“百思不得姐”App的功能模塊進(jìn)行學(xué)習(xí)和提高,其TabBar的樣式與微博的樣式基本相似(如上圖右邊的圖),最中間的Tab按鈕也是發(fā)帖功能,也是在直接當(dāng)前的頁(yè)面上覆蓋一個(gè)編輯發(fā)布頁(yè)面,發(fā)布完成或者取消發(fā)布之后又回到之前的頁(yè)面,并沒(méi)有進(jìn)行切換。
解決方案
對(duì)于類似新浪微博和我們項(xiàng)目中這種情況有兩種解決思路:
定義5個(gè)TabBarItem,然后在TabBar上添加一個(gè)與TabBarItem等大小的發(fā)布按鈕在最中間,并添加點(diǎn)擊事件,這樣因?yàn)榇笮∠嗟?,所以新按鈕完全覆蓋了最中間的TabBarItem,最中間的TabBarItem的響應(yīng)事件也會(huì)被屏蔽,因?yàn)榘粹o會(huì)先響應(yīng)自定義TabBar,重寫(xiě)其 layoutSubviews 方法,將所有4個(gè)TabBarItem的布局和大小進(jìn)行修改,將中間空出來(lái),然后添加一個(gè)自定義的【發(fā)布】按鈕,實(shí)現(xiàn)其點(diǎn)擊事件即可 1 覆蓋控件實(shí)現(xiàn)方案
這種方案的思路在上面已經(jīng)說(shuō)到了,就是先占一個(gè)位置,然后用一個(gè)按鈕覆蓋到其上面。主要缺點(diǎn)就是需要先申請(qǐng)一個(gè)位置和控制器來(lái)占位比較浪費(fèi),而且這種也只適用于各控件的大小是均勻的情況,當(dāng)我們需求中每個(gè)TabBarItem的規(guī)格和尺寸不一樣時(shí),我們就無(wú)法使用這種方案實(shí)現(xiàn)。
有幾點(diǎn)值得說(shuō)明一下:
設(shè)置所有UITabBarItem的文字屬性在上一篇文章iOS項(xiàng)目——基本框架搭建中已經(jīng)提到了,這里就不詳細(xì)介紹了【發(fā)布】按鈕的初始化應(yīng)該使用單例模式進(jìn)行創(chuàng)建,因?yàn)槲覀冺?xiàng)目中只有一個(gè)【發(fā)布】按鈕,所以使用單例模式更合理,本文采用懶加載的方式進(jìn)行單例模式的創(chuàng)建在 viewWillAppear: 中添加【發(fā)布】按鈕 [self.tabBar addSubview:self.publishButton]; 。至于為什么要在 viewWillAppear: 中添加【發(fā)布】按鈕而不是在 viewDidLoad 中添加?根本原因就是TabBarItem加載到TabBar上是在 viewDidLoad 之后執(zhí)行的,后面在第2部分中有驗(yàn)證這一點(diǎn), 在上一文章我們就說(shuō)過(guò),tabbarcontroller是在一創(chuàng)建控制器的時(shí)候就進(jìn)行加載viewdidLoad。所以,如果添加【發(fā)布】按鈕在viewDidLoad中會(huì)造成【發(fā)布】按鈕在TabBar中是第一個(gè)添加的,這樣會(huì)導(dǎo)致【發(fā)布】按鈕會(huì)被TabBarItem覆蓋了,這樣我們就達(dá)到我們的目的。
#import "XMGTabBarController.h"@interface XMGTabBarController ()/** 中間的發(fā)布按鈕 */@property (nonatomic, strong) UIButton *publishButton;@end@implementation XMGTabBarController#pragma mark - 初始化- (void)viewDidLoad { [super viewDidLoad]; /**** 設(shè)置所有UITabBarItem的文字屬性 ****/ UITabBarItem *item = [UITabBarItem appearance]; // 普通狀態(tài)下的文字屬性 NSMutableDictionary *normalAttrs = [NSMutableDictionary dictionary]; normalAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:14]; normalAttrs[NSForegroundColorAttributeName] = [UIColor grayColor]; [item setTitleTextAttributes:normalAttrs forState:UIControlStateNormal]; // 選中狀態(tài)下的文字屬性 NSMutableDictionary *selectedAttrs = [NSMutableDictionary dictionary]; selectedAttrs[NSForegroundColorAttributeName] = [UIColor darkGrayColor]; [item setTitleTextAttributes:normalAttrs forState:UIControlStateSelected]; /**** 添加子控制器 ****/ [self setupOneChildViewController:[[UITableViewController alloc] init] title:@"精華" image:@"tabBar_essence_icon" selectedImage:@"tabBar_essence_click_icon"]; [self setupOneChildViewController:[[UITableViewController alloc] init] title:@"新帖" image:@"tabBar_new_icon" selectedImage:@"tabBar_new_click_icon"]; // 中間用來(lái)占位的子控制器 [self setupOneChildViewController:[[UIViewController alloc] init] title:nil image:nil selectedImage:nil]; [self setupOneChildViewController:[[UIViewController alloc] init] title:@"關(guān)注" image:@"tabBar_friendTrends_icon" selectedImage:@"tabBar_friendTrends_click_icon"]; [self setupOneChildViewController:[[UITableViewController alloc] init] title:@"我" image:@"tabBar_me_icon" selectedImage:@"tabBar_me_click_icon"];}/** * 為什么要在viewWillAppear:方法中添加發(fā)布按鈕? * 當(dāng)viewWillAppear:方法被調(diào)用的時(shí)候, tabBar內(nèi)部已經(jīng)添加了5個(gè)UITabBarButton * 就可以實(shí)現(xiàn)一個(gè)效果 : [發(fā)布按鈕]蓋在其他UITabBarButton上面 */- (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; /**** 增加一個(gè)發(fā)布按鈕 ****/ [self.tabBar addSubview:self.publishButton];}#pragma mark - 懶加載/** 發(fā)布按鈕 */- (UIButton *)publishButton{ if (!_publishButton) { _publishButton = [UIButton buttonWithType:UIButtonTypeCustom]; _publishButton.backgroundColor = XMGRandomColor; [_publishButton setImage:[UIImage imageNamed:@"tabBar_publish_icon"] forState:UIControlStateNormal]; [_publishButton setImage:[UIImage imageNamed:@"tabBar_publish_click_icon"] forState:UIControlStateHighlighted]; _publishButton.frame = CGRectMake(0, 0, self.tabBar.frame.size.width / 5, self.tabBar.frame.size.height); _publishButton.center = CGPointMake(self.tabBar.frame.size.width * 0.5, self.tabBar.frame.size.height * 0.5); [_publishButton addTarget:self action:@selector(publishClick) forControlEvents:UIControlEventTouchUpInside]; } return _publishButton;}#pragma mark - 監(jiān)聽(tīng)/** * 發(fā)布按鈕點(diǎn)擊 */- (void)publishClick{ XMGLogFunc XMGTestViewController *test = [[XMGTestViewController alloc] init]; [self presentViewController:test animated:YES completion:nil];}@end
2 自定義TabBar
自定義TabBar可以完全按照我們的需求來(lái)布局和配置TabBar中各子控件的屬性和布局。
@interface XMGTabBarController ()@end@implementation XMGTabBarController#pragma mark - 初始化- (void)viewDidLoad { [super viewDidLoad]; /**** 設(shè)置所有UITabBarItem的文字屬性 ****/ //省略 /**** 添加子控制器 ****/ [self setupOneChildViewController:[[UITableViewController alloc] init] title:@"精華" image:@"tabBar_essence_icon" selectedImage:@"tabBar_essence_click_icon"]; [self setupOneChildViewController:[[UITableViewController alloc] init] title:@"新帖" image:@"tabBar_new_icon" selectedImage:@"tabBar_new_click_icon"]; [self setupOneChildViewController:[[UIViewController alloc] init] title:@"關(guān)注" image:@"tabBar_friendTrends_icon" selectedImage:@"tabBar_friendTrends_click_icon"]; [self setupOneChildViewController:[[UITableViewController alloc] init] title:@"我" image:@"tabBar_me_icon" selectedImage:@"tabBar_me_click_icon"]; /**** 更換TabBar ****/ [self setValue:[[XMGTabBar alloc] init] forKeyPath:@"tabBar"];}@end
下面的代碼是我們自定義TabBar的.m文件的主要內(nèi)容,主要是重寫(xiě)其 layoutSubviews 方法,在該方法中我們是將四個(gè)按鈕的大小和布局進(jìn)行了調(diào)整,然后在最中間添加一個(gè)【發(fā)布】按鈕。同樣的,也有幾點(diǎn)需要注意的:
【發(fā)布】按鈕的初始化還是和上面一樣,應(yīng)該采用單例模式進(jìn)行初始化,具體就不展開(kāi);重寫(xiě) layoutSubviews 方法時(shí),應(yīng)該先調(diào)用其父類的此方法 [super layoutSubviews]; ,這樣可以先對(duì)TabBarItem進(jìn)行布局,然后在此布局的基礎(chǔ)上進(jìn)行布局調(diào)整。調(diào)用父類布局方法的語(yǔ)句不能放在后面,更不能省略,因?yàn)榇朔椒ǔ藢?duì)TabBarItem進(jìn)行布局之外還有很多其他的配置;通過(guò) self.subviews 來(lái)獲取當(dāng)前的子控件,我們可以先進(jìn)行打印了解當(dāng)前子控件的類型和數(shù)量,然后進(jìn)行適當(dāng)?shù)暮Y選出我們需要修改的控件進(jìn)行布局,我們一般這里采用KVC的方法進(jìn)行獲取和修改,例如上面我們修改當(dāng)前的TabBar [self setValue:[[XMGTabBar alloc] init] forKeyPath:@"tabBar"]; ,關(guān)于如何獲取屬性和成員變量可以參見(jiàn):runtime獲取屬性和成員變量
#import "XMGTabBar.h"@interface XMGTabBar()/** 中間的發(fā)布按鈕 */@property (nonatomic, weak) UIButton *publishButton;@end@implementation XMGTabBar#pragma mark - 懶加載/** 發(fā)布按鈕 */- (UIButton *)publishButton{ if (!_publishButton) { UIButton *publishButton = [UIButton buttonWithType:UIButtonTypeCustom]; publishButton.backgroundColor = XMGRandomColor; [publishButton setImage:[UIImage imageNamed:@"tabBar_publish_icon"] forState:UIControlStateNormal]; [publishButton setImage:[UIImage imageNamed:@"tabBar_publish_click_icon"] forState:UIControlStateHighlighted]; [publishButton addTarget:self action:@selector(publishClick) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:publishButton]; _publishButton = publishButton; } return _publishButton;}#pragma mark - 初始化/** * 布局子控件 */- (void)layoutSubviews{ [super layoutSubviews]; /**** 設(shè)置所有UITabBarButton的frame ****/ // 按鈕的尺寸 CGFloat buttonW = self.frame.size.width / 5; CGFloat buttonH = self.frame.size.height; CGFloat buttonY = 0; // 按鈕索引 int buttonIndex = 0; for (UIView *subview in self.subviews) { // 過(guò)濾掉非UITabBarButton// if (![@"UITabBarButton" isEqualToString:NSStringFromClass(subview.class)]) continue; if (subview.class != NSClassFromString(@"UITabBarButton")) continue; // 設(shè)置frame CGFloat buttonX = buttonIndex * buttonW; if (buttonIndex >= 2) { // 右邊的2個(gè)UITabBarButton buttonX += buttonW; } subview.frame = CGRectMake(buttonX, buttonY, buttonW, buttonH); // 增加索引 buttonIndex++; } /**** 設(shè)置中間的發(fā)布按鈕的frame ****/ self.publishButton.frame = CGRectMake(0, 0, buttonW, buttonH); self.publishButton.center = CGPointMake(self.frame.size.width * 0.5, self.frame.size.height * 0.5);}#pragma mark - 監(jiān)聽(tīng)- (void)publishClick{ XMGLogFunc}@end
3 添加紅點(diǎn)提示
現(xiàn)在很多App的TabBarItem在有新消息時(shí)在右上角會(huì)有一個(gè)紅點(diǎn)提示,有的甚至還會(huì)有具體數(shù)目的提醒,類似我們常用的QQ、微信、微博、頭條等都會(huì)有類似的功能,這個(gè)提示在iOS中的學(xué)名叫做badge(其實(shí)是一般都這么命名而已)。在iOS的TabBarItem是自帶該屬性和控件的,我們可以根據(jù)自己的需求進(jìn)行配置,下圖是iOS11中的配置文檔,可以對(duì)提示數(shù)量、顏色進(jìn)行自定義設(shè)置,還可以對(duì)提示文字的屬性進(jìn)行不同狀態(tài)下的配置。
據(jù)說(shuō)在iOS10之前對(duì)badge的提示顏色是不能進(jìn)行配置的,這時(shí)候如果需要,我們就只能進(jìn)行自定義TabBarItem,然后對(duì)自定義的badge進(jìn)行配置。本文就不對(duì)這一點(diǎn)進(jìn)行詳細(xì)說(shuō)明了,有需要的小伙伴可以自行求助度娘。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注