iOS开发笔记2 - 自定义tabbar

在开发过程中,TabBarController是几乎每个APP都需要用到的,其内部默认包含一个UITabBar,但这个TabBar并不是很好用,所以我们需要自定义TabBar及上面的Button,以实现我们自己想要的效果。

接下来我们开始自定义。
首先是TabBar的.h文件:

#import <UIKit/UIKit.h>
@class DYHTabbar;

@protocol DYHTabbarDelegate<NSObject>
@optional
-(void)tabBar:(DYHTabbar *)tabBar didSelectButtonFrom:(int)from To:(int)to;
@end


@interface DYHTabbar : UIView
@property (nonatomic,weak) id<DYHTabbarDelegate> delegate;
-(void)addButtonWithATabbarItem:(UITabBarItem* )item;
@end




分析:
1.自定义的TabBar只需要能够在上面放置按钮即可,故我们继承自UIView即可。
2.自定义的TabBar上面的按钮有几个,内容如何,应该由控制器决定,故我们只需要提供API: addButtonWithATabbarItem
让控制器传递一个系统自带的TabBarItem模型给Tabbar来添加按钮
3.很明显控制器需要监听TabBar上按钮的点击,来切换子控制器,故我们定义一个代理协议,由控制器实现

接下来是TabBar的.m文件

#import "DYHTabbar.h"
#import "DYHTabbarButton.h"
@interface DYHTabbar()
@property (nonatomic,strong) NSMutableArray* buttons;
@property (nonatomic,weak) DYHTabbarButton* selectedButton;
@end
@implementation DYHTabbar
-(NSMutableArray *)buttons
{
    if (_buttons == nil) {
        _buttons = [NSMutableArray array];
    }
    return _buttons;
}

-(void)addButtonWithATabbarItem:(UITabBarItem *)item
{

    DYHTabbarButton* button = [[DYHTabbarButton alloc]init];
    [self addSubview:button];
    
    button.item = item;
    
    [button addTarget:self action:@selector(buttonClick:)forControlEvents:UIControlEventTouchDown];
    
    [self.buttons addObject:button];
    
    if (self.buttons.count == 1) {
        [self buttonClick:button];
    }

}

-(void)buttonClick:(DYHTabbarButton *)button
{
    NSLog(@"buttonClick:");
    if ([self.delegaterespondsToSelector:@selector(tabBar:didSelectButtonFrom:To:)]) {
        [self.delegate tabBar:selfdidSelectButtonFrom:self.selectedButton.tag To:button.tag];
    }
    self.selectedButton.selected = NO;
    button.selected = YES;
    self.selectedButton = button;
}

-(void)layoutSubviews
{
    [super layoutSubviews];
    CGFloat tabBarH = self.frame.size.height;
    CGFloat tabBarW = self.frame.size.width;
    
    
    CGFloat buttonW = tabBarW / self.buttons.count;
    CGFloat buttonH = tabBarH;
    CGFloat buttonY = 0;
    
    for (int i = 0; i<self.buttons.count ; i++) {
        //取出按钮
        DYHTabbarButton* button = self.buttons[i];
        //设置按钮的frame
        CGFloat buttonX = i*buttonW;
        button.frame = CGRectMake(buttonX, buttonY, buttonW, buttonH);
        //绑定TAG
        button.tag = i;
        
    }
}

@end



分析:
1.tabbar需要访问内部的按钮,故有数组buttons
2.tabbar需要知道当前被选中的按钮,故有属性selectedButton
3.buttons是mutableArray,故进行懒加载
4.addbutton,添加按钮,接收UITabBarItem模型以设置按钮属性,默认点击第一个按钮,并且每个按钮被点击通知Tabbar
5.buttonClick:按钮被点击的回调方法,由于Tabbar本身没有改变控制器的能力,故必须通知其控制器,执行代理方法,整个消息路径是 button被点击--(通知)-->Tabbar--(通知)-->控制器->执行切换控制器操作。另外,在这个方法中需要设置按钮的点击状态(样式变化)以及Tabbar的selectedButton
6.layoutSubviews,在TabBar加载时自动调用,算出按钮的frame,很简单的算法,要注意的是这里需要set一下按钮的tag值,用来标记这是第几个按钮。


接下来我们来看看自定义的button,由于我们自定义的整个Tabbar本身是透明的,故实际显示的效果全看我们自定义的Button。

.h文件

#import <UIKit/UIKit.h>

@interface DYHTabbarButton : UIButton
@property (nonatomic,strong) UITabBarItem* item;
@end



分析:
1.没什么好说的,一个模型属性来接收模型

.m文件

#import "DYHTabbarButton.h"

//图标比例
#define DYHTabBarButtonImageRatio 0.7
//按钮默认文字颜色
#define DYHTabBarButtonTitleColor (iOS7 ? [UIColor blackColor] : [UIColor whiteColor])
//选中文字颜色
#define DYHTabBarButtonTitleSlectedColor (iOS7 ? DYHColor(234,103,0) : DYHColor(248,139,0))
@implementation DYHTabbarButton

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.imageView.contentMode =UIViewContentModeCenter;
        self.titleLabel.textAlignment = NSTextAlignmentCenter;
        self.titleLabel.font = [UIFont systemFontOfSize:10];
        [self setTitleColor:DYHTabBarButtonTitleColorforState:UIControlStateNormal];
        [self setTitleColor:DYHTabBarButtonTitleSlectedColorforState:UIControlStateSelected];
        
    }
    return self;
}

-(void)setItem:(UITabBarItem *)item
{
    _item = item;
    //KVO 监听属性
    [item addObserver:self forKeyPath:@"badgeValue"options:0 context:nil];
    [item addObserver:self forKeyPath:@"title" options:0context:nil];
    [item addObserver:self forKeyPath:@"image" options:0context:nil];
    [item addObserver:self forKeyPath:@"selectedImage"options:0 context:nil];
    
    
    [self observeValueForKeyPath:nil ofObject:nil change:nilcontext:nil];

}
//监听到某个对象的属性改变了就会调用
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    
    //设置文字和图片
    [self setTitle:self.item.title forState:UIControlStateNormal];
    [self setImage:self.item.imageforState:UIControlStateNormal];
    [self setImage:self.item.selectedImageforState:UIControlStateSelected];

    
}
-(void)dealloc
{
    [self removeObserver:self forKeyPath:@"badgeValue"];
    [self removeObserver:self forKeyPath:@"title"];
    [self removeObserver:self forKeyPath:@"image"];
    [self removeObserver:self forKeyPath:@"selectedImage"];
}
-(CGRect)titleRectForContentRect:(CGRect)contentRect
{
    CGFloat titleY =contentRect.size.height*DYHTabBarButtonImageRatio;
    CGFloat titleW =contentRect.size.width;
    return CGRectMake(0, titleY, titleW , contentRect.size.height - titleY);
    
}
-(CGRect)imageRectForContentRect:(CGRect)contentRect
{
    CGFloat imageW = contentRect.size.width;
    CGFloat imageH = contentRect.size.height*DYHTabBarButtonImageRatio;
    return CGRectMake(0, 0, imageW, imageH);
}
@end


分析: 1.init没什么好说的,设置一些颜色字体,根据需求来
2.setItem,读取模型数据的方法,需要注意的是这里我们使Item监听自己的值改变,为的是完善逻辑,使用button.item.属性同样也能更改button的样式;另外我们默认调用一次值改变回调方法,初始化。
3.值改变回调方法,没什么好说的,根据值改变设置按钮属性
4.dealloc方法,在这个对象被销毁时停止监听
        5,6用来设置按钮上的文字和图片的显示样式


至此我们的自定义Tabbar完成了,不过controller在使用的时候还有一些要注意的(我们默认使用UITabBarController及其子类):
1.需要写如下代码
-(void)viewWillAppear:(BOOL)animated{
    
    [super viewWillAppear:animated];
    
    for (UIView *child in self.tabBar.subviews) {
        if ([child isKindOfClass:[UIControl class]]) {
            [child removeFro
}mSuperview];
        }
    }

因为tabBarController内部本身有一个TabBar,执行addChildController操作后默认tabbar也会加上按钮,需要移除这些按钮,否则会造成显示错误。

2.实现代理方法:

	-(void)tabBar:(DYHTabbar *)tabBar didSelectButtonFrom:(int)from To:(int)to
{
    self.selectedIndex = to;

}


由于tabBarController本身重写了selectedIndex的set方法,并且我们传的值恰好与子控制器顺序相对应,故只需要这一句代码即可完成切换


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值