自定义tabbar

作者: ZYiDa | 来源:发表于2017-08-07 15:23 被阅读159次

    先上一张效果图:


    lALPACOG82h0uBDNCKDNBNo_1242_2208.png_620x10000q90g.jpg
    下面开始说一下思路:

    第一步;先对UIView进行扩展,方便我们获取它子类的一下属性。代码如下

    #import <UIKit/UIKit.h>
    
    @interface UIView (Extension)
    
    @property (nonatomic,assign) CGFloat x;
    @property (nonatomic,assign) CGFloat y;
    @property (nonatomic,assign) CGFloat width;
    @property (nonatomic,assign) CGFloat height;
    @property (nonatomic,assign) CGFloat centerX;
    @property (nonatomic,assign) CGFloat centerY;
    @property (nonatomic,assign) CGSize size;
    
    @end
    
    #import "UIView+Extension.h"
    
    @implementation UIView (Extension)
    
    #pragma mark 重写set get 方法
    #pragma mark x
    - (void)setX:(CGFloat)x
    {
        CGRect frame = self.frame;
        frame.origin.x = x;
        self.frame = frame;
    }
    - (CGFloat)x
    {
        return self.frame.origin.x;
    }
    
    #pragma mark y
    - (void)setY:(CGFloat)y
    {
        CGRect frame = self.frame;
        frame.origin.y = y;
        self.frame = frame;
    }
    - (CGFloat)y
    {
        return self.frame.origin.y;
    }
    
    #pragma mark width
    - (void)setWidth:(CGFloat)width
    {
        CGRect frame = self.frame;
        frame.size.width = width;
        self.frame = frame;
    }
    - (CGFloat)width
    {
        return self.frame.size.width;
    }
    
    #pragma mark height
    - (void)setHeight:(CGFloat)height
    {
        CGRect frame = self.frame;
        frame.size.height = height;
    }
    - (CGFloat)height
    {
        return self.frame.size.height;
    }
    
    #pragma mark centerX
    - (void)setCenterX:(CGFloat)centerX
    {
        CGPoint center = self.center;
        center.x = centerX;
        self.center = center;
    }
    - (CGFloat)centerX
    {
        return self.center.x;
    }
    
    #pragma mark centerY
    - (void)setCenterY:(CGFloat)centerY
    {
        CGPoint center = self.center;
        center.y = centerY;
        self.center = center;
    }
    - (CGFloat)centerY
    {
        return self.center.y;
    }
    
    #pragma mark size
    - (void)setSize:(CGSize)size
    {
        CGRect frame = self.frame;
        frame.size = size;
        self.frame = frame;
    }
    - (CGSize)size
    {
        return self.frame.size;
    }
    
    @end
    
    第二步,新建一个类ZLTabbar,继承自UITabBar

    1、.h文件

    #import <UIKit/UIKit.h>
    
    typedef void(^IrrBtnSelectedBlock)();
    @interface ZLTabbar : UITabBar
    
    //用于监听自定义tabbarButton的点击事件
    @property (nonatomic,copy) IrrBtnSelectedBlock selectedIrrBtn;
    - (void)didselectedIrrBtnWithBlock:(IrrBtnSelectedBlock)selectedIrrBtn;
    
    @end
    
    

    这里解释一下,我习惯用block,所以这里声明了一个block类型。你也可以根据个人习惯,来使用观察者或者代理。
    2、.m文件

    #import "ZLTabbar.h"
    #import "UIView+Extension.h"
    
    @interface ZLTabbar ()
    
    @property (nonatomic,strong) UIButton *irregularItem;//不规则的按钮,可以放在在中间或者其它任意一个地方
    
    @end
    
    @implementation ZLTabbar
    
    - (instancetype)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self)
        {
            //TODO:加载子视图
            [self createChildrenViews];
        }
        return self;
    }
    
    #pragma mark 创建子视图
    - (void)createChildrenViews
    {
        self.backgroundColor = [UIColor whiteColor];
    
        //TODO:去掉tabbar的分割线
        [self setBackgroundImage:[UIImage new]];
        [self setShadowImage:[UIImage new]];
    
        self.irregularItem = [UIButton buttonWithType:UIButtonTypeCustom];
        [self.irregularItem setBackgroundImage:[UIImage imageNamed:@"midBtn"] forState:UIControlStateNormal];
        [self.irregularItem setBackgroundImage:[UIImage imageNamed:@"midBtn"] forState:UIControlStateHighlighted];
        self.irregularItem.size = self.irregularItem.currentBackgroundImage.size;
        self.irregularItem.layer.masksToBounds = YES;
        self.irregularItem.layer.cornerRadius = self.irregularItem.width/2;
        [self.irregularItem addTarget:self action:@selector(irregularItemSelcted) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:self.irregularItem];
    }
    
    #pragma mark 执行和监听不规则按钮的点击事件
    - (void)irregularItemSelcted
    {
        if (self.selectedIrrBtn)
        {
            self.selectedIrrBtn();
        }
    }
    
    - (void)didselectedIrrBtnWithBlock:(IrrBtnSelectedBlock)selectedIrrBtn
    {
        self.selectedIrrBtn = selectedIrrBtn;
    }
    
    #pragma mark layoutSubviews
    - (void)layoutSubviews
    {
        [super layoutSubviews];
    
        //TODO:重新排布系统按钮的位置,空出需要自定义按钮的位置,系统按钮的类型是UITabBarButton
        Class class = NSClassFromString(@"UITabBarButton");
    
        //TODO:这里设置自定义tabbarButton的位置
        self.irregularItem.centerX = (self.width * 0.75 + self.irregularItem.width * 0.75);
        self.irregularItem.centerY = self.height - self.irregularItem.height/2;
    
        NSInteger btnIndex = 0;
        for (UIView *btn in self.subviews)
        {
            if ([btn isKindOfClass:class])
            {
                //TODO:如果是系统的UITabBarButton,调整子控件位置,空出自定义UITabBarButton的位置
                //TODO:按钮宽度为Tabbar宽度平分4块
                btn.width = self.width/4;
                if (btnIndex < 3)
                {
                    //TODO: -3- 在这里为irregularItem的索引值
                    btn.x = btn.width * btnIndex;
                }
                else
                {
                    btn.x = btn.width * btnIndex + self.irregularItem.width;
                }
                btnIndex ++;
    
                if (btnIndex == 0)
                {
                    btnIndex ++;
                }
            }
        }
        [self bringSubviewToFront:self.irregularItem];
    }
    
    #pragma mark 重写hitTest方法,去监听irregularItem的点击,目的是为了让突出在外面的部分 在点击时也有反应
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    {
        /**判断当前手指是否点击到了irregularItem。如果是,则相应按钮点击;如果是其它,则由系统处理**/
        //当前view是否被隐藏?如果隐藏,就不做其他处理了。
        if (self.isHidden == NO)
        {
            //TODO:将当前tabbar的触摸点转换成坐标系,转换到irregularItem的身上,生成一个新的点
            CGPoint new_point = [self convertPoint:point toView:self.irregularItem];
    
            //TODO:如果这个新的点是在irregularItem上,那么处理点点击事件最合适的view就是irregularItem
            if ([self.irregularItem pointInside:new_point withEvent:event])
            {
                return self.irregularItem;
            }
        }
        return [super hitTest:point withEvent:event];
    }
    
    @end
    

    说明:

    1.在layoutSubviews方法中,重设自定义以及系统的tabbarButton的位置。
    2.如果不重写hitTest方法,点击突出在外面的button会无事件响应。
    3.当调整自定义tabbarButton的位置时,还有可能需要调整它的索引值。此时,它的索引值为3

    第三步,创建tabbarController

    .m文件

    #import "ZLTabbarController.h"
    #import "LeftViewController.h"
    #import "RightViewController.h"
    #import "MidViewController.h"
    #import "ResourceViewController.h"
    #import "ZLTabbar.h"
    @interface ZLTabbarController ()
    
    @end
    
    @implementation ZLTabbarController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self setupTabbar];
    }
    
    #pragma mark 设置tabbar
    - (void)setupTabbar
    {
        LeftViewController *left = [[LeftViewController alloc]init];
        [self createChildrenVC:left
               childrenVCTitle:@"首页"
                         image:[UIImage imageNamed:@"首页"]
                 selectedImage:[UIImage imageNamed:@"首页_S"]];
        ResourceViewController *resource = [[ResourceViewController alloc]init];
        [self createChildrenVC:resource
               childrenVCTitle:@"资源"
                         image:[UIImage imageNamed:@"资源"]
                 selectedImage:[UIImage imageNamed:@"资源_S"]];
    
        RightViewController *right = [[RightViewController alloc]init];
        [self createChildrenVC:right
               childrenVCTitle:@"个人中心"
                         image:[UIImage imageNamed:@"个人中心"]
                 selectedImage:[UIImage imageNamed:@"个人中心_S"]];
    
        ZLTabbar *tabbar = [[ZLTabbar alloc]init];
        tabbar.selectedItem = left.tabBarItem;
        MidViewController *mid = [[MidViewController alloc]init];
        [tabbar didselectedIrrBtnWithBlock:^{
            [self presentViewController:mid animated:YES completion:nil];
        }];
        [self setValue:tabbar forKey:@"tabBar"];
    }
    
    
    #pragma mark 添加子控制器
    - (void)createChildrenVC:(UIViewController *)childViewController
             childrenVCTitle:(NSString *)title
                       image:(UIImage *)image
               selectedImage:(UIImage *)selectedImg
    {
        //设置选中时item的字体颜色
        UIColor *selectedTinColor = [UIColor colorWithRed:60.0/255
                                                    green:160.0/255
                                                     blue:220.0/255
                                                    alpha:1.0f];
        [[UITabBarItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObject:NSForegroundColorAttributeName
                                                                                      forKey:selectedTinColor]
                                                 forState:UIControlStateSelected];
    
        //设置未选中的image
        UIImage *deselectedImage = image;
        deselectedImage = [deselectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
        childViewController.tabBarItem.image = deselectedImage;
    
        //设置选中的image
        UIImage *selectedImage = selectedImg;
        selectedImage = [selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
        childViewController.tabBarItem.selectedImage = selectedImage;
    
        //设置tabbarItem文字和图标 之间的距离
        childViewController.tabBarItem.title = title;
    //    childViewController.tabBarItem.titlePositionAdjustment = UIOffsetMake(0, MAXFLOAT);
    
        //添加控制器对象
        UINavigationController *childNavigationContorller  = [[UINavigationController alloc]initWithRootViewController:childViewController];
        [self addChildViewController:childNavigationContorller];
    }
    @end
    

    说明:

    1.我们可通过tabBarItem.titlePositionAdjustment来设置文字与图表之间的距离,当值为MAXFLOAT时,这个方法也起到了隐藏文字的作用。当然,你可以直接tabBarItem.title设置为空字符串对象。
    2.我们可以通过[tabbar didselectedIrrBtnWithBlock:^{ /**在这里做一些操作**/ }];来响应一些操作。

    3、最后把tabbarController的对象设置为window的根视图控制器就可以使用了。详细的代码都在上面了,注释也写的比较清晰。如果有不懂的地方可以留言。代码不足的地方,还望各位大神多多指教。

    相关文章

      网友评论

      本文标题:自定义tabbar

      本文链接:https://www.haomeiwen.com/subject/ikcalxtx.html