Some time ago, our product classmate raised another demand. You want the server to dynamically control tabBar images and text, and to accommodate the fact that the image is full without text, and the image display range is fixed. However, I have tried the tabBarItem of the system, which cannot fix the display range of pictures. It is adapted to the size of pictures. So I have a custom set, the final effect is as follows (at the end of the demo address) :

1. Customize tabBarItem

@interface CYXTabBarItem: UIView /* Unselected image */ @property (nonatomic,strong) UIImage *image; /* selectedImage */ @property (nonatomic,strong) UIImage *selectedImage; /* title */ @property (nonatomic,copy) NSString *title; /* select */ @property (nonatomic,assign) BOOL selected; /* Maximum image size */ @property (nonatomic,assign) CGSize maxImageSize; /* Minimum image size */ @property (nonatomic,assign) CGSize minImageSize; /* Text color */ @property (nonatomic,strong) UIColor *titleColor; /* The selected text color */ @property (nonatomic,strong) UIColor *selectedTitleColor; /* click */ @property (nonatomic,strong) void(^selectBlock)(void); /* After setting the layout method, call */ -(void)updateImageAndTitle; @endCopy the code

implementation:

@interface CYXTabBarItem() /* image */ @property (nonatomic,strong) UIImageView; /* text */ @property (nonatomic,strong) UILabel *titleLabel; @end @implementation CYXTabBarItem - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame];if(self) { [self addSubview:self.imageView]; [self addSubview:self.titleLabel]; [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.height.mas_equalTo(11);  make.left.and.right.equalTo(self); make.top.equalTo(self).offset(35); }]; __weak __typeof(self) _self = self; [selfsetTapActionWithBlock:^{
            if(_self.selectBlock) { _self.selectBlock(); }}]; }returnself; } /* Call */ -(void)updateImageAndTitle{self.titlelabel.text = self.title;ifTitlelabel. font = [UIFont systemFontOfSize:10.0]; (self.selected) {self.titlelabel. font = [UIFont systemFontOfSize:10.0]; self.titleLabel.textColor = self.selectedTitleColor;if(self.selectedImage) { self.imageView.image = self.selectedImage; }}else{the self. The titleLabel. The font = [UIFont boldSystemFontOfSize: 10.0]; self.titleLabel.textColor = self.titleColor;if(self.image) { self.imageView.image = self.image; }}if ([self.title length]) {
        [self.imageView mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.height.and.width.mas_equalTo(22);
            make.centerX.equalTo(self);
            make.top.equalTo(self).offset(5);
        }];
    }else{
        [self.imageView mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.height.and.width.mas_equalTo(40);
            make.centerX.equalTo(self);
            make.top.equalTo(self).offset(5);
        }];
    }
}
#pragma mark ---G
-(UIImageView*)imageView{
    if(! _imageView){ _imageView = [[UIImageView alloc] init]; }return _imageView;
}
-(UILabel*)titleLabel{
    if(! _titleLabel){ _titleLabel = [[UILabel alloc] init]; _titleLabel.font = [UIFont systemFontOfSize:10]; _titleLabel.textColor = [UIColor grayColor]; _titleLabel.textAlignment = NSTextAlignmentCenter; }return _titleLabel;
}
Copy the code

2. Customize tabBarView

@interface CYXBarView : UIView initialization / * button * / - (void) initButtonWithViewControllers: (NSArray viewControllers < > UIViewController * *); /* Maximum image size */ @property (nonatomic,assign) CGSize maxImageSize; /* Minimum image size */ @property (nonatomic,assign) CGSize minImageSize; /* Text color */ @property (nonatomic,strong) UIColor *titleColor; /* The selected text color */ @property (nonatomic,strong) UIColor *selectedTitleColor; /* click */ @property (nonatomic,strong) void(^selectBlock)(NSInteger index); @property (nonatomic, assign) NSInteger selectIndex; @endCopy the code

implementation:

@interface CYXBarView()


@property (nonatomic,strong) NSMutableArray<CYXTabBarItem *> *items;
@end
@implementation CYXBarView
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.maxImageSize = CGSizeMake(40, 40);
        self.minImageSize = CGSizeMake(20, 20);
        self.titleColor = [UIColor grayColor];
        self.selectedTitleColor = [UIColor redColor];
        self.items = [NSMutableArray new];
    }
    
    return self;
}

-(void)initButtonWithViewControllers:(NSArray<UIViewController *> * )viewControllers{
    [self.items removeAllObjects];
    
    for (UIView * view in self.subviews) {
        [view removeFromSuperview];
    }
    CGFloat  itemWidth =screenWidth/viewControllers.count;
    for(int i= 0; i<viewControllers.count; i++) { CYXTabBarItem * item = [[CYXTabBarItem alloc] init]; item.maxImageSize = self.maxImageSize; item.minImageSize = self.minImageSize; item.titleColor = self.titleColor; item.selectedTitleColor = self.selectedTitleColor; UIViewController * viewController = viewControllers[i]; item.title = [viewController.tabBarItem.title length]? viewController.tabBarItem.title:viewController.title; item.selectedImage = viewController.tabBarItem.selectedImage; item.image = viewController.tabBarItem.image; [self addSubview:item]; [item mas_makeConstraints:^(MASConstraintMaker *make) { make.width.mas_equalTo(itemWidth); make.height.equalTo(self);  make.top.equalTo(self); make.left.mas_equalTo(i*itemWidth); }]; [self.items addObject:item]; __weak __typeof(self) _self = self; item.selectBlock = ^{ _self.selectIndex = i;if(_self.selectBlock) { _self.selectBlock(_self.selectIndex); }}; [item updateImageAndTitle]; } self.selectIndex = 0; } - (void)setSelectIndex:(NSInteger)selectIndex
{
    if(! [self.items count]||selectIndex>=[self.items count]) {return;}
    // 先把上次选择的item设置为可用
    CYXTabBarItem *lastItem = self.items[_selectIndex];
    lastItem.selected = NO;
    // 再把这次选择的item设置为不可用
    CYXTabBarItem *item = self.items[selectIndex];
    item.selected = YES;
    _selectIndex = selectIndex;
    [lastItem updateImageAndTitle];
    [item updateImageAndTitle];
}
@end
Copy the code

2. Customize tabBar

@class CYXBarView;
@interface CYXTabBar : UITabBar

@property (nonatomic,strong) CYXBarView *tabBarView;

@end

Copy the code

implementation:

@interface CYXTabBar ()

@end
@implementation CYXTabBar
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self addSubview:self.tabBarView];
        [self.tabBarView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.and.right.and.left.and.bottom.equalTo(self);
        }];
        
    }
    
    returnself; } - (void)layoutSubviews { [super layoutSubviews]; / / take tabBarView to the front, covering the content of the tabBar [self bringSubviewToFront: self. TabBarView]; /* Hide the original */for (UIView *view in self.subviews) {
        if ([view isKindOfClass:NSClassFromString(@"UITabBarButton")]) { view.hidden = YES; - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {if (self.clipsToBounds || self.hidden || (self.alpha == 0.f)) {
        returnnil; } UIView *result = [super hitTest:point withEvent:event]; // If the event occurred in tabbar, return it directlyif (result) {
        returnresult; } // It's ok to iterate over the exceeding part, but this is more general.for (UIView *subview inSelf.tabbarview.subviews) {// Convert this coordinate from tabbar's coordinate system to subView's coordinate system CGPoint subPoint = [subView convertPoint:point fromView:self]; result = [subview hitTest:subPoint withEvent:event]; // Return if the event occurred in the subViewif (result) {
            returnresult; }}return nil;
}
#pragma mark ---G
-(CYXBarView*)tabBarView{
    if(! _tabBarView){ _tabBarView = [[CYXBarView alloc] init]; }return _tabBarView;
}
Copy the code

2. Customize UITabBarController

@interface CYXTabBarViewController : UITabBarController

@end
Copy the code

implementation:

@interface CYXTabBarViewController ()
@property (nonatomic,strong) CYXTabBar *customTabBar;
@end

@implementation CYXTabBarViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self setValue:self.customTabBar forKey:@"tabBar"];
    
    [self initViewControllers];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.selectedIndex = 3;
    });
}
-(void)initViewControllers{
    NSMutableArray * viewControllers = [NSMutableArray new];
    UIViewController *homeVC = [[UIViewController alloc] init];
    homeVC.view.backgroundColor = [UIColor redColor];
    [viewControllers addObject:[self addChildViewController:homeVC title:@"Home page" imageNamed:@"tabBar_home"]];
    
    UIViewController *expoVC = [[UIViewController alloc] init];
    expoVC.view.backgroundColor = [UIColor yellowColor];
    [viewControllers addObject:[self addChildViewController:expoVC title:@"Home Expo" imageNamed:@"tabBar_activity"]];
    
    UIViewController *activityVC = [[UIViewController alloc] init];
    activityVC.view.backgroundColor = [UIColor yellowColor];
    [viewControllers addObject:[self addChildViewController:activityVC title:@"" imageNamed:@"tabBar_activity"]];
    
    UIViewController *findVC = [[UIViewController alloc] init];
    findVC.view.backgroundColor = [UIColor blueColor];
    [viewControllers addObject:[self addChildViewController:findVC title:@"Discovered" imageNamed:@"tabBar_find"]];
    
    UIViewController *mineVC = [[UIViewController alloc] init];
    mineVC.view.backgroundColor = [UIColor greenColor];
    [viewControllers addObject:[self addChildViewController:mineVC title:@"I" imageNamed:@"tabBar_mine"]]. self.viewControllers = viewControllers; } // Add some childViewController - (UINavigationController *)addChildViewController (UIViewController *)vc title (NSString) *)title imageNamed:(NSString *)imageNamed { UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc]; NavigationItem. Title = title; // navigationItem = title; nav.tabBarItem.title = title; nav.tabBarItem.image = [UIImage imageNamed:imageNamed]; nav.tabBarItem.selectedImage = [UIImage imageNamed:@"jmtIconBg"];
    return nav;
}

-(void)setViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers{
    [super setViewControllers:viewControllers];
    [self.customTabBar.tabBarView initButtonWithViewControllers:viewControllers];
}
-(void)setSelectedIndex:(NSUInteger)selectedIndex{
    [super setSelectedIndex:selectedIndex];
    self.customTabBar.tabBarView.selectIndex = selectedIndex;
}
#pragma mark ---G
-(CYXTabBar*)customTabBar{
    if(! _customTabBar){ _customTabBar = [[CYXTabBar alloc] init]; __weak __typeof(self) _self = self; _customTabBar.tabBarView.selectBlock = ^(NSInteger index) { _self.selectedIndex = index; }; }return _customTabBar;
}
Copy the code

Appdelegate:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point forcustomization after application launch. self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; self.window.backgroundColor = [UIColor whiteColor]; self.window.rootViewController = [[CYXTabBarViewController alloc] init]; // Set this window to have the main window and display [self.window makeKeyAndVisible];return YES;
}
Copy the code

The result is a high degree of customization and can be modified at will. Welcome to discuss and teach demo: github.com/SionChen/CY…