• 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
    
    
  • 相关阅读:
    第二十一章流 1流的操作 简单
    第二十章友元类与嵌套类 1友元类 简单
    第十九章 19 利用私有继承来实现代码重用 简单
    第二十章友元类与嵌套类 2嵌套类 简单
    第十九章 8链表类Node 简单
    第二十一章流 3用cin输入 简单
    第十九章 10 图书 药品管理系统 简单
    第十九章 11图书 药品管理系统 简单
    第二十一章流 4文件的输入和输出 简单
    第十九章 12 什么时候使用私有继承,什么时候使用包含 简单
  • 原文地址:https://www.cnblogs.com/ceasar/p/8781788.html
Copyright © 2020-2023  润新知