UITabBarController 仿钉钉 tabbar 上下滑动自定义更多操作

最近公司的OA项目,产品要求按照钉钉实现此功能,具体请查看IOS端的钉钉app,上下滑动tabbar,可以拉出更多的操作按钮。

这个比较高级。实现思路无非两个:

1、自己写一个基于UIViewController的tabbar控制器

2、对UITabBarController视图组织进行重构

实现效果:

在这里,我使用的是第二种方式。请按照以下步骤添加代码即可:

1、先自定义一个UITabBar,注意此处必须自定义,因为我们滑动调整tabbar坐标的时候,会出现抖动,为避免抖动,我们需要处理其setFrame方法。

@interface  UISlideTabBar : UITabBar
@end

@interface UISlideTabBar ()

@end

@implementation UISlideTabBar
- (void)setFrame:(CGRect)frame
{
    CGFloat bottomHeight = [[UIApplication sharedApplication] delegate].window.safeAreaInsets.bottom;
    CGFloat maxY = [UIScreen mainScreen].bounds.size.height - 49 - bottomHeight;
    
    if (frame.size.height == 49 && frame.origin.y>= maxY && bottomHeight>0)
    {
        NSLog(@"return");
    }
    else
    {
        [super setFrame:frame];
    }
}
@end

2、 定义一个UITabViewController 基于UITabBarController并添加此block方法后面要用到,这个就是一个插槽VIEW,用于对外暴露一个视图容器,添加更多的操作。


@interface UITabViewController : UITabBarController

- (void)addSlotterViewWithConfigBlock:(UIView* _Nullable (^)(void))setupBlock;
@end

3、在UITabViewController.m文件中,添加以下代码:

typedef UIView* _Nullable (^UITabbarSlotterViewBlock)(void);

@interface UITabViewController ()<UITabBarControllerDelegate>
{
    NSInteger tabbarIndex;
    BOOL fromTop;
    CGFloat lineY;
}

@property (nonatomic, strong) UIView *slotterView;
@property (nonatomic, strong) UIButton *maskView;
@property (nonatomic,copy) UITabbarSlotterViewBlock slotterViewBlock;

@end



- (void)viewDidLayoutSubviews {
    [self.tabBar layoutSubviews];//Fix issue #93 #392
    CYLTabBar *tabBar =  (CYLTabBar *)self.tabBar;
    CGFloat bottomHeight = [[UIApplication sharedApplication] delegate].window.safeAreaInsets.bottom;
    
    for (UIView *view in self.tabBar.subviews)
    {
        if ([view isKindOfClass:NSClassFromString(@"UITabBarButton")])
        {
            [view removeFromSuperview];
        }
    }
    
    CGFloat tabBarHeight = self.tabBarHeight;
    if (self.slotterViewBlock)
    {
        if (!self.slotterView)
        {
            UIView *cntView = self.slotterViewBlock();
            CGRect fm = cntView.frame;
            fm.origin.y += bottomHeight;
            [cntView setFrame:fm];
            
            CGRect rt = CGRectMake(0, 0, self.view.bounds.size.width, fm.size.height+fm.origin.y);
            UIView *view = [[UIView alloc] initWithFrame:rt];
            [view setBackgroundColor:cntView.backgroundColor];
            [view addSubview:cntView];
            
            self.slotterView = view;
            [self.view addSubview:self.slotterView];
            
            //阴影层
            rt = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height-tabBarHeight);
            self.maskView = [UIButton buttonWithType:UIButtonTypeCustom];
            [self.maskView setFrame:rt];
            [self.maskView addTarget:self action:@selector(mmiSetViewToActive) forControlEvents:UIControlEventTouchUpInside];
            [self.maskView setBackgroundColor:[UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:0.35]];
            [self.maskView setAlpha:0.0];
            [self.view insertSubview:self.maskView belowSubview:self.tabBar];
            [self.view sendSubviewToBack:self.maskView];
            
            NSInteger idx = 0;
            CGFloat x = 0;
            CGFloat w = self.view.bounds.size.width/self.tabBar.items.count;
            CGFloat spacing = 3;
            UIFont *font = [UIFont systemFontOfSize:10];
            
            while (idx<self.tabBar.items.count)
            {
                CGRect rt = CGRectMake(x, 0, w, self.tabBarHeight);
                UIView *view = [[UIView alloc] initWithFrame:rt];
                [view setBackgroundColor:[UITabBar appearance].backgroundColor];
                [self.tabBar addSubview:view];
                
                UITabBarItem *i = [[self.tabBar items] objectAtIndex:idx];
                [i setDataObject:view];
                
                CGSize imageSize = i.image.size;
                CGSize titleSize = [self stringSizeWithFont:font strText:i.title];
                rt = CGRectMake(0, 0, rt.size.width, rt.size.height);
                UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
                [button setFrame:rt];
                button.titleEdgeInsets = UIEdgeInsetsMake(0, - imageSize.width, - (imageSize.height + spacing), 0);
                button.imageEdgeInsets = UIEdgeInsetsMake(- (titleSize.height + spacing), 0, 0, - titleSize.width);
                [button setTitle:i.title forState:UIControlStateNormal];
                [button setImage:i.image forState:UIControlStateNormal];
                button.imageView.contentMode = UIViewContentModeScaleAspectFit;
                [button setImage:i.selectedImage forState:UIControlStateSelected];
                [button.titleLabel setFont:font];
                [button setSelected:idx==0];
                [button setTag:-900-idx];
                [button setTitleColor:[UIColor colorWithRed:102.0/255.0 green:102.0/255.0 blue:102.0/255.0 alpha:1] forState:UIControlStateNormal];
                [button setTitleColor:[UIColor colorWithRed:2.0/255.0 green:134.0/255.0 blue:224.0/255.0 alpha:1] forState:UIControlStateSelected];
                [button addTarget:self action:@selector(tabbarItemSelectedAction:) forControlEvents:UIControlEventTouchUpInside];
                
                [view addSubview:button];
                
                idx ++;
                x += w;
            }
            
            w = self.tabBar.bounds.size.width/20;
            rt = CGRectMake((self.view.bounds.size.width-w)/2, 7, w, 3);
            if (![self.tabBar viewWithTag:2022])
            {
                UIView *iview = [[UIView alloc] initWithFrame:rt];
                [iview setBackgroundColor:[UIColor colorWithRed:153.0/255.0 green:153.0/255.0 blue:153.0/255.0 alpha:0.5]];
                [iview setTag:2022];
                [iview.layer setMasksToBounds:YES];
                [iview.layer setCornerRadius:1.5];
                [self.tabBar addSubview:iview];
                
                UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureAct:)];
                [self.tabBar setUserInteractionEnabled:YES];
                [self.tabBar addGestureRecognizer:panGesture];
            }
            [[self.tabBar viewWithTag:2022] setFrame:rt];
            
            rt = self.slotterView.frame;
            rt.origin.y = self.tabBar.frame.origin.y + self.tabBar.frame.size.height+bottomHeight;
            [self.slotterView setFrame:rt];
        }
    }
}


- (void)mmiSetViewToActive
{
    CGFloat maxY = [UIScreen mainScreen].bounds.size.height - self.tabBarHeight;
    
    CGFloat alpha = 1.0;
    [UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^
    {
        [self.maskView setAlpha:1-alpha];
    } completion:^(BOOL finished) {
        [self.view sendSubviewToBack:self.maskView];
    }];
    
    [UIView transitionWithView:self.tabBar duration:0.15 options:UIViewAnimationOptionCurveLinear animations:^{
        CGRect fm = self.tabBar.frame;
        fm.origin.y = maxY;
        fm.size.height = self.tabBarHeight;
        [self.tabBar setFrame:fm];
    } completion:^(BOOL finished) {
        
    }];
    
    [UIView transitionWithView:self.tabBar duration:0.2 options:UIViewAnimationOptionCurveLinear animations:^{
        CGRect rt = self.slotterView.frame;
        rt.origin.y = self.view.bounds.size.height;
        [self.slotterView setFrame:rt];
    } completion:^(BOOL finished) {
        
    }];
}


- (void)panGestureAct: (UIPanGestureRecognizer *)recognizer
{
    CGPoint touchPoint = [recognizer translationInView:self.view];
    CGFloat bottomHeight = [[UIApplication sharedApplication] delegate].window.safeAreaInsets.bottom;
    CGFloat maxY = [UIScreen mainScreen].bounds.size.height - self.tabBarHeight;
    CGFloat minY = maxY-self.slotterView.frame.size.height;
    CGFloat hm = (maxY-minY)/2;
    CGRect frame = self.tabBar.frame;
    NSTimeInterval interval = 0.0;
    
    if ([self.view.subviews indexOfObject:self.maskView] != 1)
    {
        [self.view exchangeSubviewAtIndex:1 withSubviewAtIndex:0];
    }
    
    if (touchPoint.y>=0 && frame.origin.y>=maxY && !self->fromTop)
    {
        return;
    }
    if (recognizer.state == UIGestureRecognizerStateBegan)
    {
        if (frame.origin.y == minY)
        {
            self->fromTop = YES;
        }
        else
        {
            self->fromTop = NO;
        }
    }
    //-1向上没去 0未动  1向下滑动
    NSInteger ifUp = touchPoint.y==self->lineY?0:touchPoint.y<self->lineY?-1:1;
    self->lineY = touchPoint.y;
    
    if (self->fromTop)
    {
        if (frame.origin.y >= maxY)
        {
            self->fromTop = NO;
        }
        frame.origin.y = MAX(minY+touchPoint.y, minY);
        frame.origin.y = MIN(frame.origin.y, maxY);
    }
    else
    {
        if (ifUp == -1)
        {
            CGFloat ofy = 0;
            frame.origin.y = MAX(maxY+touchPoint.y, minY);
            frame.origin.y -= ofy;
            frame.origin.y = MIN(frame.origin.y, maxY);
        }
        else if (ifUp == 1)
        {
            frame.origin.y = MIN(maxY+touchPoint.y, maxY);
            frame.origin.y = MAX(frame.origin.y, minY);
        }
    }
    self.tabBar.frame = frame;

    CGRect rt = self.slotterView.frame;
    rt.origin.y = frame.origin.y + frame.size.height;
    [self.slotterView setFrame:rt];
    
    CGFloat alpha = (frame.origin.y-minY)/(maxY-minY);
    [UIView animateWithDuration:0.05 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^
    {
        [self.maskView setAlpha:1-alpha];
    } completion:^(BOOL finished) {

    }];
    
    if (recognizer.state == UIGestureRecognizerStateEnded)
    {
        self->lineY = 0;
        self->fromTop = NO;
        CGRect frame = self.tabBar.frame;
        if (frame.origin.y <= minY+hm)
        {
            frame.origin.y = minY;
        }
        else
        {
            frame.origin.y = maxY;
        }
        interval = 0.25;

        [UIView animateWithDuration:interval delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
            [self.tabBar setFrame:frame];

            CGRect rt = self.slotterView.frame;
            rt.origin.y = self.tabBar.frame.origin.y+ self.tabBar.frame.size.height;
            [self.slotterView setFrame:rt];
        } completion:^(BOOL finished) {

        }];
        
        CGFloat alpha = (frame.origin.y-minY)/(maxY-minY);
        [UIView animateWithDuration:0.05 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^
        {
            [self.maskView setAlpha:1-alpha];
        } completion:^(BOOL finished) {
            if (alpha == 1.0)
            {
                [self.view sendSubviewToBack:self.maskView];
            }
        }];
    }
}

- (void)tabbarItemSelectedAction:(UIButton *)btn
{
    NSInteger tag = labs(btn.tag+900);
    UIViewController *controller = [self selectedViewController];
    NSArray *array = [controller childViewControllers];
    UIViewController *rootController = [array firstObject];
    [self setSelectedIndex:tag];
    [self mmiSetViewToActive];
}

- (void)setSelectedIndex:(NSUInteger)selectedIndex {
    [super setSelectedIndex:selectedIndex];
    if (self.slotterViewBlock)
    {
        for (NSInteger idx=0; idx<self.tabBar.items.count; idx++)
        {
            UIButton *button = (UIButton *)[self.tabBar viewWithTag:-900-idx];
            [button setSelected:idx==selectedIndex?YES:NO];
        }
    }
}

4、如何使用呢?

在tabbarcontroller初始化的地方:通过对外暴露的插槽block返回你要下拉显示的更多的操作视图。

    self.tabBarController = [[UITabViewController alloc] init];
    [self.tabBarController addSlotterViewWithConfigBlock:^UIView * _Nullable
    {
        CGRect rt = CGRectMake(0, 0, KScreenSize.width, 100);
        UIView *view = [[UIView alloc] initWithFrame:rt];
        [view setBackgroundColor:[UIColor whiteColor]];
        
        return view;
    }];
    self.window.rootViewController = self.tabBarController;

到此,此功能已经实现,同学们可以进行参考。

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhaocarbon

你的鼓励是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值