UITabBarController的使用


UITabBarController的使用

  • 前言:
    蘋果開發的小伙伴都知道,項目中只要用到了UITabBarController,UITabBarController就是APP的骨架。所以熟練掌握UITabBarController的使用方法才能編寫出健壯的APP。

在此介紹UITabBarController在項目中的實現的兩種方式,一種使用系統自帶的tabbar,一種使用自定義的tabbar。

demo下載地址

使用系統自帶的tabbar

UITabBarController由兩部分組成,一個是UITabBarController包含的子視圖,一個是tabbar。

.h文件
#import <UIKit/UIKit.h>
@interface HSP_tabbar_VC : UITabBarController
@end
.m文件

#import "HSP_tabbar_VC.h"
#import "HHTabBar.h"
#import "AppDelegate.h"

#define isIPhoneX ScreenHeight==812

@interface HSP_tabbar_VC ()

@end

#pragma - mark - 使用系統自帶tabbar 的方式
@implementation HSP_tabbar_VC

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    [self loadControllers];
}

- (void)loadControllers {
    //創建tabBarController
    UIViewController *vcA = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"firstVC"];
    UIViewController *vcB = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"secondVC"];
    UIViewController *vcC = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"thiredVC"];
    UIViewController *vcD = [[UIViewController alloc]init];
    UIViewController *vcE = [[UIViewController alloc]init];
    UIViewController *vcF = [[UIViewController alloc]init];
    UIViewController *vcG = [[UIViewController alloc]init];

    
    UINavigationController *nav1 = [[UINavigationController alloc]initWithRootViewController:vcA];
    
    //添加控制器
    self.viewControllers = @[nav1,vcB,vcC,vcD,vcE,vcF,vcG];
    
    
    //設置tabBarButton
    nav1.tabBarItem = [[UITabBarItem alloc]initWithTitle:@"首頁" image:[UIImage imageNamed:@"home_normal"] selectedImage:[UIImage imageNamed:@"home_highlight"]];
    vcB.tabBarItem = [[UITabBarItem alloc]initWithTitle:@"導覽" image:[[UIImage imageNamed:@"topics_normal"]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] selectedImage:[[UIImage imageNamed:@"topics_highlight"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
    vcC.tabBarItem = [[UITabBarItem alloc]initWithTitle:@"資訊" image:[UIImage imageNamed:@"service_normal"] selectedImage:[UIImage imageNamed:@"service_highlight"]];
    vcD.tabBarItem = [[UITabBarItem alloc]initWithTitle:@"資訊" image:[UIImage imageNamed:@"service_normal"] selectedImage:[UIImage imageNamed:@"service_highlight"]];
    vcE.tabBarItem = [[UITabBarItem alloc]initWithTitle:@"資訊" image:[UIImage imageNamed:@"service_normal"] selectedImage:[UIImage imageNamed:@"service_highlight"]];
    vcF.tabBarItem = [[UITabBarItem alloc]initWithTitle:@"資訊" image:[UIImage imageNamed:@"service_normal"] selectedImage:[UIImage imageNamed:@"service_highlight"]];
    vcG.tabBarItem = [[UITabBarItem alloc]initWithTitle:@"資訊" image:[UIImage imageNamed:@"service_normal"] selectedImage:[UIImage imageNamed:@"service_highlight"]];
    
    vcB.tabBarItem.imageInsets = UIEdgeInsetsMake(-20, 0, 0, 0);
    
    vcC.tabBarItem.badgeValue = @"2";
    vcC.tabBarItem.badgeColor = [UIColor redColor];
    
    self.tabBar.tintColor = [UIColor orangeColor];
    
    self.tabBar.backgroundColor = [UIColor redColor];
    self.tabBar.backgroundImage = [[UIImage alloc]init];
}



@end
	

以上使用系統自帶tabbar應當注意的問題

1. 為標簽設置圖片時,增加顯示原圖的方法,否則尺寸不對會出現圖片顯示不出來的情況。
[[UIImage imageNamed:@"topics_normal"]
imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] 
2. 標簽頁是大圖片時,設置imageInsets屬性避免文字和圖片重疊
vcB.tabBarItem.imageInsets = UIEdgeInsetsMake(-20, 0, 0, 0);
3. 通過設置背景圖片去除系統自帶的模糊效果
 self.tabBar.backgroundImage = [[UIImage alloc]init];

自定義tabbar

自定義tabbar的實現原理:將自定義的View 添加到系統的tabbar上,通過全局的 UITabBarController 類來完成UIViewController之間的切換。

- (void)setSelectedIndex:(NSInteger)index {
	for (HHTabBarItem *item in self.tabBarItems) {
		if (item.tag == index) {
			item.selected = YES;
		} else {
			item.selected = NO;
		}
	}
	
    AppDelegate *dele = (AppDelegate *)[UIApplication sharedApplication].delegate;
	UITabBarController *tabBarController = dele.tabVC;
	if (tabBarController) {
		tabBarController.selectedIndex = index;
	}
}

對tabbar的封裝分為兩層,HHTabBar 以及 HHTabBarItem

MacDown logo

HHTabBar類的主要功能是為每個標簽分配frame,然后通過接受HHTabBarItem類的點擊事件(HHTabBarItem類繼承自UIButton)來切換UIViewController。

.h文件


#import <UIKit/UIKit.h>
#import "HHTabBarItem.h"
#import "UIColor+HexColor.h"

#define ScreenWidth [UIScreen mainScreen].bounds.size.width
#define ScreenHeight [UIScreen mainScreen].bounds.size.height
#define NewDefaultColor hexColorAlpha(@"#c77a3a", 1)




@protocol LLTabBarDelegate <NSObject>

- (void)tabBarDidSelectedRiseButton;

@end

@interface HHTabBar : UIView

@property (nonatomic, copy) NSArray<NSDictionary *> *tabBarItemAttributes;
@property (nonatomic, weak) id <LLTabBarDelegate> delegate;

@end



.m 文件

#import "HHTabBar.h"
#import "AppDelegate.h"

@interface HHTabBar ()

@property (strong, nonatomic) NSMutableArray *tabBarItems;

@end

@implementation HHTabBar

#pragma mark - Lifecycle

- (instancetype)initWithFrame:(CGRect)frame {
	self = [super initWithFrame:frame];
	
	if (self) {
		[self config];
	}
	
	return self;
}

#pragma mark - Private Method

- (void)config {
	UIImageView *topLine = [[UIImageView alloc] initWithFrame:CGRectMake(0, -5, ScreenWidth, 5)];
	topLine.image = [UIImage imageNamed:@"tapbar_top_line"];
	[self addSubview:topLine];
}

- (void)setSelectedIndex:(NSInteger)index {
	for (HHTabBarItem *item in self.tabBarItems) {
		if (item.tag == index) {
			item.selected = YES;
		} else {
			item.selected = NO;
		}
	}
	
    AppDelegate *dele = (AppDelegate *)[UIApplication sharedApplication].delegate;
	UITabBarController *tabBarController = dele.tabVC;
	if (tabBarController) {
		tabBarController.selectedIndex = index;
	}
}

#pragma mark - Touch Event

- (void)itemSelected:(HHTabBarItem *)sender {
    [self setSelectedIndex:sender.tag];
}

#pragma mark - Setter

- (void)setTabBarItemAttributes:(NSArray<NSDictionary *> *)tabBarItemAttributes {
    _tabBarItemAttributes = tabBarItemAttributes.copy;
    
    CGFloat itemWidth = ScreenWidth / _tabBarItemAttributes.count;
    CGFloat tabBarHeight = CGRectGetHeight(self.frame);
    NSInteger itemTag = 0;
    BOOL passedRiseItem = NO;
    
    _tabBarItems = [NSMutableArray arrayWithCapacity:_tabBarItemAttributes.count];
    for (id item in _tabBarItemAttributes) {
        if ([item isKindOfClass:[NSDictionary class]]) {
            NSDictionary *itemDict = (NSDictionary *)item;
            
            HHTabBarItemType type = [itemDict[kHHTabBarItemAttributeType] integerValue];
            CGRect frame = CGRectMake(itemTag * itemWidth + (passedRiseItem ? itemWidth : 0), 0, itemWidth, tabBarHeight);
            
            HHTabBarItem *tabBarItem = [self tabBarItemWithFrame:frame
                                                           title:itemDict[kHHTabBarItemAttributeTitle]
                                                 normalImageName:itemDict[kHHTabBarItemAttributeNormalImageName]
                                               selectedImageName:itemDict[kHHTabBarItemAttributeSelectedImageName] tabBarItemType:type];
            if (itemTag == 0) {
                tabBarItem.selected = YES;
                [tabBarItem setTitleColor:NewDefaultColor forState:UIControlStateSelected];
            }
            
            [tabBarItem addTarget:self action:@selector(itemSelected:) forControlEvents:UIControlEventTouchUpInside];
            
            tabBarItem.tag = itemTag;
            itemTag++;

            
            [_tabBarItems addObject:tabBarItem];
            [self addSubview:tabBarItem];
        }
    }
}

- (HHTabBarItem *)tabBarItemWithFrame:(CGRect)frame title:(NSString *)title normalImageName:(NSString *)normalImageName selectedImageName:(NSString *)selectedImageName tabBarItemType:(HHTabBarItemType)tabBarItemType {
    
    HHTabBarItem *item = [[HHTabBarItem alloc] initWithFrame:frame];
    [item setTitle:title forState:UIControlStateNormal];
    [item setTitle:title forState:UIControlStateSelected];
    item.titleLabel.font = [UIFont systemFontOfSize:10];
    UIImage *normalImage = [UIImage imageNamed:normalImageName];
    UIImage *selectedImage = [UIImage imageNamed:selectedImageName];
    [item setImage:normalImage forState:UIControlStateNormal];
    [item setImage:selectedImage forState:UIControlStateSelected];
    [item setTitleColor:[UIColor colorWithWhite:1 alpha:0.6] forState:UIControlStateNormal];
    [item setTitleColor:NewDefaultColor forState:UIControlStateSelected];
    item.tabBarItemType = tabBarItemType;
    
    return item;
}


@end

HHTabBarItem類的功能是保持Label的位置不變,寬度隨着文本信息的多少變化,同時圖片保持與Label的距離恆定,這需要根據圖片的大小計算imageView的中心點的位置。

另外傳遞標簽的文字和圖片時用到的常量字符串也在HHTabBarItem類中定義。

.h文件

//

#import <UIKit/UIKit.h>

typedef NS_ENUM(NSUInteger, HHTabBarItemType) {
	HHTabBarItemNormal = 0,
	HHTabBarItemRise,
};

extern NSString *const kHHTabBarItemAttributeTitle ;// NSString
extern NSString *const kHHTabBarItemAttributeNormalImageName;// NSString
extern NSString *const kHHTabBarItemAttributeSelectedImageName;// NSString
extern NSString *const kHHTabBarItemAttributeType;// NSNumber, HHTabBarItemType

@interface HHTabBarItem : UIButton


@end


.m文件


#import "HHTabBarItem.h"

static float labelBottom = 3.0;
static float imageLabelDis = 5.0;
static float defaultLabelWidth = 18.0;

NSString *const kHHTabBarItemAttributeTitle = @"HHTabBarItemAttributeTitle";
NSString *const kHHTabBarItemAttributeNormalImageName = @"HHTabBarItemAttributeNormalImageName";
NSString *const kHHTabBarItemAttributeSelectedImageName = @"HHTabBarItemAttributeSelectedImageName";
NSString *const kHHTabBarItemAttributeType = @"HHTabBarItemAttributeType";

@implementation HHTabBarItem

- (instancetype)initWithFrame:(CGRect)frame {
	self = [super initWithFrame:frame];
	
	if (self) {
		[self config];
	}
	
	return self;
}

- (instancetype)init {
	self = [super init];
	
	if (self) {
		[self config];
	}
	
	return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
	self = [super initWithCoder:aDecoder];
	
	if (self) {
		[self config];
	}
	
	return self;
}

- (void)config {
	//self.adjustsImageWhenHighlighted = NO;  網上說有選擇后出現灰色背景的情況,目前沒有發現。
	//self.imageView.contentMode = UIViewContentModeScaleAspectFit;
}

- (void)layoutSubviews {
	[super layoutSubviews];
	
	[self.titleLabel sizeToFit];
	CGSize titleSize = self.titleLabel.frame.size;

	CGSize imageSize = [self imageForState:UIControlStateNormal].size;
	if (imageSize.width != 0 && imageSize.height != 0) {
		CGFloat imageViewCenterY = CGRectGetHeight(self.frame) - labelBottom - titleSize.height - imageSize.height / 2 - imageLabelDis;
		self.imageView.center = CGPointMake(CGRectGetWidth(self.frame) / 2, imageViewCenterY);
	} else {
		CGPoint imageViewCenter = self.imageView.center;
		imageViewCenter.x = CGRectGetWidth(self.frame) / 2;
		imageViewCenter.y = (CGRectGetHeight(self.frame) - titleSize.height) / 2;
		self.imageView.center = imageViewCenter;
	}

	CGPoint labelCenter = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) - labelBottom - titleSize.height / 2);
    self.titleLabel.frame = CGRectMake(0, 0, titleSize.width, defaultLabelWidth);
	self.titleLabel.center = labelCenter;
}
    
// 還有一種實現方式是設置 Edge Insets,Xcode 7.0.1 好像有點不開心,在 IB 里面更改一下屬性的時候,經常崩潰。。。
/* 位置還有一點不准確,推薦用上面的代碼來設置
 
 [self.titleLabel sizeToFit];
 CGSize titleSize = self.titleLabel.frame.size;
 CGSize imageSize = [self imageForState:UIControlStateNormal].size;
 NSInteger titleTopInset = CGRectGetHeight(self.frame) - 3 - titleSize.height;
 CGFloat titleRightInset = (CGRectGetWidth(self.frame) - titleSize.width) / 2 + titleSize.width;
 [self setTitleEdgeInsets:UIEdgeInsetsMake(titleTopInset, 0, 3, titleRightInset)];
 CGFloat imageViewLeftRightInset = (CGRectGetWidth(self.frame) - imageSize.width) / 2;
 [self setImageEdgeInsets:UIEdgeInsetsMake(CGRectGetHeight(self.frame) - 3 - 5 - titleSize.height - imageSize.height, imageViewLeftRightInset, 3 + 5 + titleSize.height, imageViewLeftRightInset)];
 
 */

@end


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM