自定义tabbar

tabbar本身的barbuttonitem(bbi)在我看来有很多不需要用到的属性变量,而且在开发中有时候会需要用到自定义的bbi,网上普遍做法是隐藏原有的tabbar然后在其原来的位置创建一个新的uiview加上一堆按钮,但是这种方法在我们使用导航控制器需要隐藏tabbar的时候非常的不方便。笔者的做法是在初始化子控制器数组后移除tabbar上面所有的按钮对象,然后在上面加上自定义的所有按钮。其中,自定义按钮对象继承自uiview,原因是如果继承自uibutton或者bbi会有很多不需要的属性变量。

自定义类LXDTabBarButtonItem.h

<span style="font-size:14px;">#import <UIKit/UIKit.h>

/**
 *  view的点击状态枚举
 */
typedef NS_ENUM(NSUInteger, LXDViewState){
    
    ViewStateNormal = 0,        //正常状态
    ViewStateSelected            //选中状态
};




@class LXDTabBarButtonItem;
/**
 *  点击回调函数块
 */
typedef void(^LXDClickViewHandler)(LXDTabBarButtonItem * barItem);




/**
 *  自定义的tabbarItem
 */
@interface LXDTabBarButtonItem : UIView


/**
 *  当前view是否处于选中状态
 */
@property (nonatomic, readonly, getter=isSelected)BOOL selected;


/**
 *  设置view的选中状态
 *
 *  @param selected     新的状态
 */
- (void)setSelected:(BOOL)selected;


/**
 *  设置显示在view上面的文本内容
 *
 *  @param title     要显示的文本内容
 *  @param state    显示的状态
 */
- (void)setTitle: (NSString *)title forState: (LXDViewState)state;


/**
 *  设置view在不同状态下的图片
 *
 *  @param image     要显示的图片
 *  @param state     显示的状态
 */
- (void)setImage: (UIImage *)image forState: (LXDViewState)state;


/**
 *  增加view的点击回调函数
 *
 *  @param clickHandler     回调函数块
 */
- (void)addClickHandler: (LXDClickViewHandler)clickHandler;


@end</span>
虽然我们的bbi是自定义的,但是在命名上尽可能的使用button相关的函数名称,方便我们操作。

对比原有的bbi,自定义的bbi明显要更加的灵活。灵活度可以表现在下面两点:


1、我们可以在手势点击的回调函数中给按钮加入CA框架下的动画效果,使得自定义的tabbar在交互中的体验更加良好

2、通过block回调我们可以更加灵活的处理点击事件,完成更多的功能

LXDTabBarButtonItem.m

<span style="font-size:14px;">#import "LXDTabBarButtonItem.h"
#import "LXDGlobalDefine.h"


@interface LXDTabBarButtonItem ()

/**
 *  用来存储不同状态的显示图片
 */
@property (nonatomic, strong) NSMutableDictionary * images;


/**
 *  用来存储不同状态下的文本内容
 */
@property (nonatomic, strong) NSMutableDictionary * titles;


/**
 *  显示的图片
 */
@property (nonatomic, strong) UIImageView * itemImage;


/**
 *  当前view的状态
 */
@property (nonatomic, assign) LXDViewState viewState;


/**
 *  点击屏幕的回调事件
 */
@property (nonatomic, copy) LXDClickViewHandler clickHandler;


/**
 *  显示文本内容
 */
@property (nonatomic, strong) UILabel * titleLabel;


@end


@implementation LXDTabBarButtonItem


- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame: frame]) {
        
        /**
         *  点按手势
         */
        UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(clickView)];
        [self addGestureRecognizer: tapGesture];
        _images = [NSMutableDictionary new];
    }
    return self;
}




/**
 *  设置view的选中状态
 *
 *  @param selected     新的状态
 */
- (void)setSelected:(BOOL)selected
{
    _selected = selected;
    _viewState = selected;
    
    /**
     *  取出对应状态的图片显示
     */
    NSString * stateKey = [NSString stringWithFormat: @"%lu", _viewState];
    if (_images[stateKey]) {
        
        _itemImage.image = _images[stateKey];
    }
    
    /**
     *  取出对应状态的文本内容
     */
    if (_titles[stateKey]) {
        
        _titleLabel.text = _titles[stateKey];
    }
    [self resetTitleColor];
}




/**
 *  设置显示在view上面的文本内容
 *
 *  @param title     要显示的文本内容
 *  @param state    显示的状态
 */
- (void)setTitle:(NSString *)title forState:(LXDViewState)state
{
    /**
     *  惰性初始化
     */
    if (!_titleLabel) {
        
        _titleLabel = [[UILabel alloc] initWithFrame: CGRectMake(20, LXD_TABBAR_HEIGHT - 13, self.frame.size.width - 40, 8)];
        _titleLabel.font = [UIFont systemFontOfSize: 9];
        _titleLabel.textAlignment = NSTextAlignmentCenter;
        
        [self addSubview: _titleLabel];
        [self resetTitleColor];
    }
    
    [_titles setValue: title forKey: [NSString stringWithFormat: @"%lu", (unsigned long)state]];
    if (_viewState == state) {
        
        _titleLabel.text = title;
    }
}




/**
 *  设置view在不同状态下的图片
 *
 *  @param image     要显示的图片
 *  @param state     显示的状态
 */
- (void)setImage:(UIImage *)image forState:(LXDViewState)state
{
    [_images setValue: image forKey: [NSString stringWithFormat: @"%lu", (unsigned long)state]];
    
    /**
     *  惰性初始化
     */
    if (!_itemImage) {
        
        _itemImage = [[UIImageView alloc] initWithFrame: self.bounds];
        [self addSubview: _itemImage];
        [self sendSubviewToBack: _itemImage];
    }
    
    if (state == _viewState) {
        
        _itemImage.image = image;
    }
}




/**
 *  增加view的点击回调函数
 *
 *  @param clickHandler     回调函数块
 */
- (void)addClickHandler:(LXDClickViewHandler)clickHandler
{
    self.clickHandler = clickHandler;
}




#pragma mark -- 私有方法 -- Private methods
/**
 *  点按view时回调
 */
- (void)clickView
{
    if (self.selected) {
        
        return;
    }
    
    [self setSelected: !self.selected];
    [self resetTitleColor];
    
    /**
     *  如果有回调函数,那么执行
     */
    if (_clickHandler) {
        
        _clickHandler(self);
    }
}




/**
 *  重新设置文本的颜色
 */
- (void)resetTitleColor
{
    if (_viewState) {
        
        _titleLabel.textColor = [UIColor orangeColor];
    } else {
        
        _titleLabel.textColor = [UIColor whiteColor];
    }
}</span>

在实现文件中,我们对存储图片跟文本信息的字典进行了惰性初始化(延迟创建),这么做有两个好处。一是当将部分操作延后执行可以提高视图切换的速度。二是如果用户不需要相关属性,可以减少内存的损耗。

自定义部分到这里就结束了,接着是怎么删除tabbar上面的按钮控件,然后替换成自定义的按钮操作。必须要注意的是这部分操作保证在viewControllers的数组创建结束后才能执行删除的操作。

删除加上替换的代码:

<span style="font-size:14px;">- (void)createCustomTabBar
{
    /**
     *  先移除系统所有在tabbar上的子视图
     */
    for (id subview in self.tabBar.subviews) {
        
        if ([subview isKindOfClass: NSClassFromString(@"UITabBarButton")]) {
            
            [subview removeFromSuperview];
        }
    }
    
    
    NSArray * images = @[@"tab_cookbook", @"tab_explore", @"tab_plaza", @"tab_aboutme"];
    NSArray * titles = @[@"菜单", @"发现", @"卖汤汤", @"我的"];
    /**
     *  添加自定义的tabbarItem
     */
    NSInteger count = self.viewControllers.count;
    CGFloat itemWidth = LXD_SCREEN_WIDTH / count;
    for (int i = 0; i < count; i++) {
        
        LXDTabBarButtonItem * barItem = [[LXDTabBarButtonItem alloc] initWithFrame: CGRectMake(i * itemWidth, 0, itemWidth, LXD_TABBAR_HEIGHT)];
        barItem.tag = i;
        
        
        /**
         *  设置item的普通状态图片跟选中状态图片
         */
        [barItem setImage: [UIImage imageNamed: images[i]] forState: ViewStateNormal];
        [barItem setImage: [UIImage imageNamed: [images[i] stringByAppendingString: @"_hl"]] forState: ViewStateSelected];
        
        
        /**
         *  设置item的文本信息
         */
        [barItem setTitle: titles[i] forState: ViewStateNormal];
        
        
        /**
         *  添加点击时切换状态事件
         */
        __weak typeof(self) weakSelf = self;
        [barItem addClickHandler: ^(LXDTabBarButtonItem * barItem){
           
            
            [_selectedItem setSelected: NO];
            _selectedItem = barItem;
            
            weakSelf.selectedViewController = self.viewControllers[barItem.tag];
        }];
        
        
        if (i == 0) {
            
            [barItem setSelected: YES];
            _selectedItem = barItem;
        }
        
        
        [self.tabBar addSubview: barItem];
    }
}</span>

还要注意的是在写block回调函数块的时候要防止循环引用(尤其是引用了自己),其中变量_selectedItem的声明是 __weak LXDTabBarButtonItem * _selectedItem。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值