关于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的左右滑动切换的问题算是解决了。

时间: 2024-09-27 08:51:48

关于tabbarViewController的左右滑动切换的相关文章

带有ListView的界面无法通过手势左右滑动切换界面问题解决办法

问题描述: 在做OnGestureListener滑动切换窗口的时候,会遇到这样的问题.就是当界面中含有ListView的时候,OnGestureListener的左右触屏滑动就被ListView自己吃掉了. 问题分析: 在Android系统中,事件的分发和响应都按照一定的优先级仅仅有条的进行着.如果Activity中包含ListView那么系统的onTouchEvent事件会优先分发给ListView去处理,这时ListView的OnItemClickListener监听器会优先响应onTou

用jQuery.touchSwipe插件实现手机端场景滑动切换效果

使用jQuery的touchSwipe插件监听触摸滑动事件,结合css3实现手机端场景滑动切换效果.最好在手机端测试代码,也可以在PC端用鼠标点击模拟滑动. 1.html代码: <div class="container"> <div class="page page0 page_current"> <h1>你好,我是0号屏幕,第一屏,鼠标单击向下/向上拖动</h1> </div> <div clas

Android:简单实现ViewPager+TabHost+TabWidget实现导航栏导航和滑动切换

viewPager是v4包里的一个组件,可以实现滑动显示多个界面. android也为viewPager提供了一个adapter,此adapter最少要重写4个方法: public int getCount() public boolean isViewFromObject(View view, Object o) public void destroyItem(ViewGroup container, int position, Object object)  public Object in

仿美团外卖,饿了吗 两个ListView联动,左边点击切换右边,右边滑动切换左边

先上效果图: 实现思路: 1.先说右边标题: 首先,右边的数据源集合中的Javabean中含有三个属性name,type,title,而每个条目中会默认含有一个标题. 如果这是第一个条目,就让标题显示出来,再如果这个条目的类型和上一个条目的类型不一样,就让这个条目的标题显示出来,否则,就隐藏标题,  这样我们就做到了每种类型只有第一个数据标题显示出来 接着,在Listview的外层(也就是MainActivity的布局文件中),默认放一个标题(下面都称作是主标题) 最后,设置右边Listview

基于jQuery左右滑动切换特效 附源码

分享一款基于脚jQuery左右滑动切换特效.这是一款鼠标点击左右箭头按钮图片滚动切换,鼠标移到图片上显示透明边框特效. 效果图如下: 废话不多说,代码奉上! html代码: 1 <div class="bodyCon08"><!--学员--> 2 <div class="students"> 3 4 <div id="four_flash"> 5 <div class="flashB

ViewPager页面滑动切换

我们日常生活中用到的微博,QQ,微信等app在进行页面左右滑动的时候,很多都可以用ViewPager来实现.可以说,ViewPager在android开发中十分常见并且特别实用. Viewpager在android.support.v4.view这个软件包中,  android.support.v4.view.jar是谷歌官方给我们提供的一个兼容低版本安卓设备的软件包,里面包囊了只有在安卓3.0以上可以使用的api.所以低版本开发时必须加入android-support-v4.jar,并且在XM

[Android] 使用Include布局+Fragment滑动切换屏幕

    前面的文章已经讲述了"随手拍"项目图像处理的技术部分,该篇文章主要是主界面的布局及屏幕滑动切换,并结合鸿洋大神的视频和郭神的第一行代码(强推两人Android博客),完成了下面的内容:     (1).学习使用Include布局XML     (2).通过添加适配器加载fragment     (3).实现滑动触摸切换屏幕ViewPager     (4).改变图标及背景,并响应fragment中控件及传递参数 参考资料: 郭霖大神的<Android第一行代码> 鸿

【Android UI】案例03滑动切换效果的实现(ViewPager)

本例使用ViewPager实现滑动切换的效果.本例涉及的ViewPager,为android.support.v4.view.ViewPager.所以需要在android项目中导入android-support-v4.jar. 本例中ViewPager是实现滑动效果的核心部分.对其设置PageChangeListener监听事件,是实现滑动效果的核心思路. [转载使用,请注明出处:http://blog.csdn.net/mahoking] 首先是主界面layout.xml文件,activity

如果写一个android桌面滑动切换屏幕的控件(二)

在viewgroup执行: public void snapToScreen(int whichScreen) { whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1)); boolean changingScreens = whichScreen != mCurrentScreen; mNextScreen = whichScreen; int mScrollX = this.getScrollX(); fin