仿閑魚自定義Tabbar(純代碼)

效果圖:

閑魚TabBar

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é),不足之處還望大家見諒,并歡迎指正!
愿每一個人都能學有所成!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,050評論 4 61
  • 一、UITabBarController以其相關(guān)控件之間的關(guān)系 @interface UITabBarContro...
    西門淋雨閱讀 3,300評論 0 1
  • 在某些項目的初期我們經(jīng)常會選擇使用UITabbarController或者是UINavigationControl...
    趙永洪閱讀 3,211評論 2 1
  • 文/一覺醒來不是夢 近些年,各種視頻主播真的像是雨后春筍搬一涌而出。不管是游戲(dota、爐石、魔獸爭霸、lol等...
    一覺醒來不是夢閱讀 210評論 0 0
  • 起因是道一句晚安啦,你給我發(fā)了好長一篇我自以為的小說,還在抱怨好長,耐著脾氣給看完,好像有點不解氣,還想看,因為...
    Masha迪閱讀 213評論 0 0

友情鏈接更多精彩內(nèi)容