效果圖:

demo下載地址:https://github.com/jiangcr/XianYuTabBar
Demo中的圖片資源均從閑魚APP中獲取,具體獲取方法可參考iOS-獲取其他APP的圖片資源
一、思路
1.UITabBarItem可以看做是一種特殊的button,首先可以創(chuàng)建自定義的button.
2.UITabBar是繼承UIView的,可以創(chuàng)建一個自定義的tabbar繼承UIView,方便高度自定義。
3.創(chuàng)建自定義的tabBarController繼承UITabBarController。
4.通過按鈕的點擊方法,代理等建立三者的關(guān)系。
二、自定義Tabbar的主要過程
1.創(chuàng)建自定義的CustomButton
@interface CustomButton : UIButton
@property(nonatomic, strong)UITabBarItem *tabBarItem;
@end
由于系統(tǒng)的tabBar的圖片,標題是通過UITabBarItem的賦值的,這里給CustomButton加個tabBarItem的屬性,便于賦值,且更符合思維習慣。
初始化的時候設(shè)置image,title的一些公共屬性。
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
//只需要設(shè)置一次的放置在這里
self.imageView.contentMode = UIViewContentModeBottom;
self.titleLabel.textAlignment = NSTextAlignmentCenter;
self.titleLabel.font = [UIFont systemFontOfSize:12];
[self setTitleColor:[UIColor colorWithRed:117/255.0f green:117/255.0f blue:117/255.0f alpha:1.0] forState:UIControlStateNormal];
}
return self;
}
通過下面兩個方法可以設(shè)置image,title的frame信息。
-(CGRect)imageRectForContentRect:(CGRect)contentRect;
-(CGRect)titleRectForContentRect:(CGRect)contentRect;
最后利用tabBarItem的set方法,給button的image,title賦值
- (void)setTabBarItem:(UITabBarItem *)tabBarItem
{
_tabBarItem = tabBarItem;
[self setTitle:self.tabBarItem.title forState:UIControlStateNormal];
[self setImage:self.tabBarItem.image forState:UIControlStateNormal];
[self setImage:self.tabBarItem.selectedImage forState:UIControlStateSelected];
}
2.創(chuàng)建自定義的CustomTabBar
@interface CustomTabBar : UIView
@property (nonatomic, weak)id <CustomTabBarDelegate>delegate;
- (void)addTabBarButtonWithTabBarItem:(UITabBarItem *)tabBarItem;
@end
這里CustomTabBar有兩個作用:
1.CustomButton的一個背景;
2.把CustomButton和tabBarController的viewControllers關(guān)聯(lián)起來
//方法一
- (void)addTabBarButtonWithTabBarItem:(UITabBarItem *)tabBarItem {
CustomButton * tabBarBtn = [CustomButton new];
[self addSubview:tabBarBtn];
tabBarBtn.tabBarItem = tabBarItem;
[tabBarBtn addTarget:self action:@selector(tabBarBtnClick:) forControlEvents:UIControlEventTouchDown];
[self.tabbarBtnArray addObject:tabBarBtn];
//default selected first one
if (self.tabbarBtnArray.count == 1) {
[self tabBarBtnClick:tabBarBtn];
}
}
方法一主要就是把CustomButton添加到customTabbar上,CustomButton的數(shù)量是與tabBarController的viewControllers有關(guān)的,應(yīng)在創(chuàng)建tabBarController的viewControllers時調(diào)用此方法。
要把CustomButton的點擊與tabBarController的viewControllers關(guān)聯(lián)起來,需要一個代理方法。在代理方法中直接設(shè)置tabBarController的selectedIndex即可
@protocol CustomTabBarDelegate <NSObject>
- (void)tabBar:(CustomTabBar *)tabBar didSelectedButtonFrom:(long)fromBtnTag to:(long)toBtnTag;
@end
#pragma mark --------------------mainTabBar delegate
- (void)tabBar:(CustomTabBar *)tabBar didSelectedButtonFrom:(long)fromBtnTag to:(long)toBtnTag{
self.selectedIndex = toBtnTag;
}
3.創(chuàng)建自定義的CustomTabBarController
@interface CustomTabBarController : UITabBarController
@end
這部分有兩個關(guān)鍵點
1.移除系統(tǒng)的tabBar
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
for (UIView *child in self.tabBar.subviews) {
if ([child isKindOfClass:[UIControl class]]) {
[child removeFromSuperview];
}
}
}
2.viewControllers與CustomButton關(guān)聯(lián)
childVc.tabBarItem.image = [UIImage imageNamed:imageName];
childVc.tabBarItem.selectedImage = [UIImage imageNamed:selectedImageName];
childVc.tabBarItem.title = title;
[self.mainTabBar addTabBarButtonWithTabBarItem:childVc.tabBarItem];
[self addChildViewController:childVc];
以上是自定義tabBar的一個主要過程,下面說一些可能要注意到的問題。
三、自定義tabBar過程中需要注意的問題
1.中間的Button是個特殊的button.
這種情況大多數(shù)和閑魚都比較類似,點擊會present一個viewController。這種情況我們可以單獨添加一個按鈕,單獨設(shè)置點擊方法。調(diào)整其frame即可。
- (void)setupPostButton {
UIButton * postBtn = [UIButton new];
postBtn.adjustsImageWhenHighlighted = NO;
[postBtn setBackgroundImage:[UIImage imageNamed:@"post_normal"] forState:UIControlStateNormal];
[postBtn addTarget:self action:@selector(postGoodAction) forControlEvents:UIControlEventTouchUpInside];
[postBtn setTitle:@"發(fā)布" forState:UIControlStateNormal];
postBtn.titleLabel.font = [UIFont systemFontOfSize:12];
[postBtn setTitleColor:[UIColor colorWithRed:117/255.0f green:117/255.0f blue:117/255.0f alpha:1.0] forState:UIControlStateNormal];
postBtn.bounds = CGRectMake(0, 0, postBtn.currentBackgroundImage.size.width, postBtn.currentBackgroundImage.size.height);
[postBtn setTitleEdgeInsets:UIEdgeInsetsMake(78, 0, 0, 0)];
[self addSubview:postBtn];
self.postBtn = postBtn;
}
2.導航欄頂部陰影效果
導航欄頂部原本是有一條線的,并不是陰影效果,達到這種效果有兩張方案:
1.加一張陰影效果的image.
self.tabBar.shadowImage = [UIImage imageNamed:@"tapbar_top_line"];
2.代碼繪制。
這里講一下第二種方法
- (void)dropShadowWithOffset:(CGSize)offset
radius:(CGFloat)radius
color:(UIColor *)color
opacity:(CGFloat)opacity {
// Creating shadow path for better performance
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, self.tabBar.bounds);
self.tabBar.layer.shadowPath = path;
CGPathCloseSubpath(path);
CGPathRelease(path);
self.tabBar.layer.shadowColor = color.CGColor;
self.tabBar.layer.shadowOffset = offset;
self.tabBar.layer.shadowRadius = radius;
self.tabBar.layer.shadowOpacity = opacity;
// Default clipsToBounds is YES, will clip off the shadow, so we disable it.
self.tabBar.clipsToBounds = NO;
}
3.popToRootViewController時tabBar重疊的問題
當項目中出現(xiàn)popToRootViewController回到tabBarController的childViewController時,會出現(xiàn)tabBar重疊的情況,我們之前在tabBarController的viewWillAppear移除系統(tǒng)tabBar此時無效,此時可以通過通知的方法解決此問題。
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(removeTabBarBtn) name:@"removeTabBarBtn" object:nil];
for (UIView *tabBar in self.tabBar.subviews) {
if ([tabBar isKindOfClass:[UIControl class]]) {
[tabBar removeFromSuperview];
}
}
}
//返回根視圖時移除原有的按鈕
- (void)removeTabBarBtn
{
for (UIView *tabBar in self.tabBar.subviews) {
if ([tabBar isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
[tabBar removeFromSuperview];
}
}
}
** 注意:使用通知記得在合適的時機remove **
有關(guān)UITabBarController更詳細的內(nèi)容可參考iOS-UITabBarController詳細總結(jié)。
結(jié)束語:
此文是我在學習過程中的探索與總結(jié),不足之處還望大家見諒,并歡迎指正!
愿每一個人都能學有所成!