zoukankan      html  css  js  c++  java
  • 关于tabbarViewController的左右滑动切换

    在我们开发的过程中,有时会有左右侧滑tabbarViewController切换控制器的需求,在我自己做项目的时候遇到了此类需求,现在就在此记录一下我当时的做法,废话不多说,直接上代码:

    在iOS7.0以前,要实现这样的效果,只有自定义TabBar了,但这很麻烦。而在iOS7.0以后,苹果在UITabBarControllerDelegate中增加了下面两个代理方法:

    - (nullable id <UIViewControllerInteractiveTransitioning>)tabBarController:(UITabBarController *)tabBarController  interactionControllerForAnimationController: (id<UIViewControllerAnimatedTransitioning>)animationController;

    - (nullable id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController  animationControllerForTransitionFromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC;

    自定义的滑动代理,在此实现tabbarViewController的两个新添加的滑动的代理方法

    //  ScrollTabBarDelegate.h

    #import <Foundation/Foundation.h>

    #import <UIKit/UIKit.h>

    @interface ScrollTabBarDelegate : NSObject <UITabBarControllerDelegate>

    @property (nonatomic, assign) BOOL interactive;

    @property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactionController;

    @end

    //

    //  ScrollTabBarDelegate.m

    #import "ScrollTabBarDelegate.h"

    #import "ScrollTabBarAnimator.h"

    @interface ScrollTabBarDelegate ()

    @property (nonatomic, strong) ScrollTabBarAnimator *tabBarAnimator;

    @end

    @implementation ScrollTabBarDelegate

    - (instancetype)init {

        if (self = [super init]) {

            _interactive = NO;

            _interactionController = [[UIPercentDrivenInteractiveTransition alloc] init];

            _tabBarAnimator = [[ScrollTabBarAnimator alloc] init];

        }

        return self;

    }

    - (nullable id <UIViewControllerInteractiveTransitioning>)tabBarController:(UITabBarController *)tabBarController

                                   interactionControllerForAnimationController: (id <UIViewControllerAnimatedTransitioning>)animationController {

        return self.interactive ? self.interactionController : nil;

    }

    - (nullable id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController

                         animationControllerForTransitionFromViewController:(UIViewController *)fromVC

                                                           toViewController:(UIViewController *)toVC {

        

        NSInteger fromIndex = [tabBarController.viewControllers indexOfObject:fromVC];

        NSInteger toIndex = [tabBarController.viewControllers indexOfObject:toVC];

        self.tabBarAnimator.tabScrollDirection = (toIndex < fromIndex) ? TabLeftDirection: TabRightDirection;

        return self.tabBarAnimator;

    }

    @end

    在自定义一个动画的类,实现滑动切换tabbar时加载动画效果:

    //  ScrollTabBarAnimator.h

    #import <Foundation/Foundation.h>

    #import <UIKit/UIKit.h>

    typedef NS_ENUM(NSInteger,TabOperationDirection) {

        TabLeftDirection,

        TabRightDirection

    };

    @interface ScrollTabBarAnimator : NSObject <UIViewControllerAnimatedTransitioning>

    @property (nonatomic, assign) TabOperationDirection tabScrollDirection;

    @end

    //  ScrollTabBarAnimator.m

    #import "ScrollTabBarAnimator.h"

    @implementation ScrollTabBarAnimator

    //动画持续时间

    - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {

        return 0.3;

    }

    //动画执行效果

    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {

        

        // 获取 toView fromView

        UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

        UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

        UIView *containerView = [transitionContext containerView];

        if (!toViewController || !fromViewController || !containerView) return;

        

        // 给 toView fromView 设定相应的值

        toViewController.view.transform = CGAffineTransformIdentity;

        fromViewController.view.transform = CGAffineTransformIdentity;

        CGFloat translation = containerView.frame.size.width;

        switch (self.tabScrollDirection) {

            case TabLeftDirection:

                translation = translation;

                break;

            case TabRightDirection:

                translation = -translation;

                break;

            default:

                break;

        }

        [containerView addSubview:toViewController.view];

        toViewController.view.transform = CGAffineTransformMakeTranslation(-translation, 0);

        // 真正的变化

        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{

            fromViewController.view.transform = CGAffineTransformMakeTranslation(translation, 0);

            toViewController.view.transform = CGAffineTransformIdentity;

        } completion:^(BOOL finished) {

            fromViewController.view.transform = CGAffineTransformIdentity;

            toViewController.view.transform = CGAffineTransformIdentity;

            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];

        }];

    }

    @end

    在 TabBarController.m 中 实现的方法

    导入 ScrollTabBarDelegate 的头文件后,声明两个对象

    @property (nonatomic, assign) NSInteger subViewControllerCount;

    @property (nonatomic, strong) ScrollTabBarDelegate *tabBarDelegate;

    - (void)viewDidLoad {

        [super viewDidLoad];

        #pragma mark   tabbar滑动切换手势

        // 正确的给予 count

        self.subViewControllerCount = self.viewControllers ? self.viewControllers.count : 0;

    设置 tabbarViewController 的代理为 ScrollTabBarDelegate ,并给 tabbarViewController 的view添加滑动手势

        // 代理

        self.tabBarDelegate = [[ScrollTabBarDelegate alloc] init];

        self.delegate = self.tabBarDelegate;

        // 增加滑动手势

        self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panHandle:)];

        [self.view addGestureRecognizer:self.panGesture];

        

    }

     实现滑动手势,切换tabbarViewController的item到不同的控制器

    - (void)panHandle:(UIPanGestureRecognizer *)panGesture {

        // 获取滑动点

        CGFloat translationX = [panGesture translationInView:self.view].x;

        CGFloat progress = fabs(translationX)/self.view.frame.size.width;

        

        switch (panGesture.state) {

            case UIGestureRecognizerStateBegan:

            {

                self.tabBarDelegate.interactive = YES;

                CGFloat velocityX = [panGesture velocityInView:self.view].x;

                if (velocityX < 0) {

                    if (self.selectedIndex < self.subViewControllerCount - 1) {

                        self.selectedIndex += 1;

                    }

                }

                else {

                    if (self.selectedIndex > 0) {

                        self.selectedIndex -= 1;

                    }

                }

            }

                break;

            case UIGestureRecognizerStateChanged:

            {

                [self.tabBarDelegate.interactionController updateInteractiveTransition:progress];

            }

                

                break;

            case UIGestureRecognizerStateEnded:

            case UIGestureRecognizerStateFailed:

            case UIGestureRecognizerStateCancelled:

            {

                if (progress > 0.3) {

                    self.tabBarDelegate.interactionController.completionSpeed = 0.99;

                    [self.tabBarDelegate.interactionController finishInteractiveTransition];

                }else{

                    //转场取消后,UITabBarController 自动恢复了 selectedIndex 的值,不需要我们手动恢复。

                    self.tabBarDelegate.interactionController.completionSpeed = 0.99;

                    [self.tabBarDelegate.interactionController cancelInteractiveTransition];

                }

                self.tabBarDelegate.interactive = NO;

            }

                break;

            default:

                break;

        }

    }

    这样实现以后,会出现一个问题,就是当跳转到子控制器的时候,子控制器也可以滑动,这就不对了,于是果断的开始查找原因,发现所有的控制器的 

    rootViewController 都是 tabbarViewController,所以需要在跳转的时候吧 tabbarViewController 的view的滑动手势给移除掉,当返回来的时候再给加上去,于是把 UIPanGestureRecognizer 的对象在tabbarViewController.h 中搞成一个全局对象 

    @property (nonatomic, strong) UIPanGestureRecognizer *panGesture;

    在自定义的 UINavigationController 中,重写 pushViewController 方法,在此方法中移除tabbarViewController 的view的滑动手势,代码如下: 

    - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {

        

        if (self.viewControllers.count > 0) {

            viewController.hidesBottomBarWhenPushed = YES;

            // 跳转后移除滑动手势

            [[UIApplication sharedApplication].delegate.window.rootViewController.view removeGestureRecognizer:viewController.cyl_tabBarController.panGesture];

       注册一个通知,通知在第一层的控制器吧tabbarViewController 的view的滑动手势给添加上去

            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollNextViewController) name:@"SCROLLTABBARCONTROLLER" object:nil];

        }

            [super pushViewController:viewController animated:animated];

    }

    当返回到第一层的控制器的时候,在返回按钮点击的时候发布一个通知,通知在第一层的控制器吧tabbarViewController 的view的滑动手势给添加上去

    -(void)scrollNextViewController {

        

        if (self.childViewControllers.count == 1 && [(AppDelegate *)[UIApplication sharedApplication].delegate isBackBtn] == YES) {

            // 返回后重新添加滑动手势

            [[UIApplication sharedApplication].delegate.window.rootViewController.view addGestureRecognizer:[UIApplication sharedApplication].delegate.window.rootViewController.cyl_tabBarController.panGesture];

        }

    }

    结束后别忘了移除通知

    - (void)dealloc {

        [[NSNotificationCenter defaultCenter] removeObserver:self];

    }

    到此处,关于tabbarViewController的左右滑动切换的问题算是解决了。

  • 相关阅读:
    一次安装。net core的经历
    c# task 等待所有子线程执行完的写法
    .net 中的async,await理解
    dbeaver pgsql连接工具
    oracle 导出表结构和备注
    abp
    发布站点
    excel 拆分多个excel并保持
    重定向和反向代理的区别
    es6中的解构赋值
  • 原文地址:https://www.cnblogs.com/zhufengshibei/p/7358159.html
Copyright © 2011-2022 走看看