IOS手势滑动返回总结(边缘+全屏) | 您所在的位置:网站首页 › ipad如何手势返回上一级 › IOS手势滑动返回总结(边缘+全屏) |
为了提高用户体验,在controller会加上这个操作,我自己写了好多次,但是没有系统的整理过,这会儿又做到这个功能了,索性整理一下。 一、边缘滑动返回在远古时代,大概是ios7之前,滑动返回这个事儿是不被官方支持的,因为手机屏幕没那么大,IOS7以后,苹果为了提升用户体验,增加了【边缘返回】的手势,注意是边缘,不是全屏,并且在特定条件下,边缘返回会失效,具体是以下几种情况: 1. 自定义了navigationItem的leftBarButtonItem或leftBarButtonItems 2. self.navigationItem.hidesBackButton = YES 3. self.navigationItem.leftItemsSupplementBackButton = NO 为了解决以上问题,有两个方案,拿捏: 方案一:在UINavigationController基类添加以下: - (void)viewDidLoad { [super viewDidLoad]; //设置右滑返回手势的代理为自身 __weak typeof(self) weakself = self; if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.interactivePopGestureRecognizer.delegate = (id)weakself; } } #pragma mark - UIGestureRecognizerDelegate //这个方法是在手势将要激活前调用:返回YES允许右滑手势的激活,返回NO不允许右滑手势的激活 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { if (gestureRecognizer == self.interactivePopGestureRecognizer) { //屏蔽调用rootViewController的滑动返回手势,避免右滑返回手势引起crash if (self.viewControllers.count < 2 || self.visibleViewController == [self.viewControllers objectAtIndex:0]) { return NO; } } //这里就是非右滑手势调用的方法啦,统一允许激活 return YES; } 那么,在特定场景下,我们不希望用户轻易返回,比如在直播间内、在扫码界面等,拿捏: 创建一个UIViewController 的分类: + (void)popGestureClose:(UIViewController *)VC { // 禁用侧滑返回手势 if ([VC.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { //这里对添加到右滑视图上的所有手势禁用 for (UIGestureRecognizer *popGesture in VC.navigationController.interactivePopGestureRecognizer.view.gestureRecognizers) { popGesture.enabled = NO; } //若开启全屏右滑,不能再使用下面方法,请对数组进行处理 //VC.navigationController.interactivePopGestureRecognizer.enabled = NO; } } + (void)popGestureOpen:(UIViewController *)VC { // 启用侧滑返回手势 if ([VC.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { //这里对添加到右滑视图上的所有手势启用 for (UIGestureRecognizer *popGesture in VC.navigationController.interactivePopGestureRecognizer.view.gestureRecognizers) { popGesture.enabled = YES; } //若开启全屏右滑,不能再使用下面方法,请对数组进行处理 //VC.navigationController.interactivePopGestureRecognizer.enabled = YES; } } 使用: - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [UIViewController popGestureClose:self]; //关闭边缘返回 } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [UIViewController popGestureOpen:self]; //启动边缘返回 } 方案二:每个UIViewController都有一个backBarButtonItem,这是个特殊属性,只响应页面的返回和销毁,表现为:只能自定义image和title,不能重写target 或 action。(注意:UINavigationController的左侧是不支持右滑返回手势的)我们通过自定义backBarButtonItem,来实现:既实现“自定义返回按钮(通常自定义leftBarButtonItem或leftBarButtonItems都是为了实现自定义返回按钮)”又保留滑动返回。 拿捏: 在UIViewController基类: - (void)viewDidLoad{ [super viewDidLoad]; UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil]; //自定义返回按钮的视图 [self.navigationController.navigationBar setBackIndicatorImage:[UIImage imageNamed:@"navi_back_icon"]]; [self.navigationController.navigationBar setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"navi_back_icon"]]; //设置tintColor 改变自定图片颜色 self.navigationController.navigationBar.tintColor = [UIColor whiteColor]; //设置自定义的返回按钮 self.navigationItem.backBarButtonItem = backItem; } 那么在这种方案下,在特定场景我们不希望用户轻易返回,如何做? 拿捏: 自定义`leftBarButtonItem`或`leftBarButtonItems`,并设置`leftItemsSupplementBackButton = YES`。 - (void)viewDidLoad{ [super viewDidLoad]; //自定义返回按钮 UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom]; [studySearch setImage:[UIImage imageNamed:@"back_icon"] forState:UIControlStateNormal]; [studySearch sizeToFit]; [studySearch addTarget:self action:@selector(backAction) forControlEvents:UIControlEventTouchUpInside]; UIBarButtonItem *studySearchItem = [[UIBarButtonItem alloc] initWithCustomView:studySearch]; self.navigationItem.leftBarButtonItems = @[studySearchItem]; //是否支持显示左滑返回按钮, //NO不显示:leftBarButtonItems覆盖backBarButtonItem, //YES显示:backBarButtonItem 显示在leftBarButtonItems左侧 //leftItemsSupplementBackButton必须在自定义leftBarButtonItem或leftBarButtonItems后才有效 self.navigationItem.leftItemsSupplementBackButton = YES; } 以上两个方案已经可以满足大部分开发需求,但还有一种情况,在UIScrollView(UICollectionView)下,返回手势会失灵。 我们先来看看啥原理: UIScrollView(包括其子类UITextView、UITableView、UICollectionView等)的panGestureRecognizer先接收到手势事件,处理后不再往下传递。即是否让两个panGestureRecognizer都起作用的问题,默认情况下scrollView的手势会让系统的手势失效。so,显而易见,我们需要让两个手势同时启用。 拿捏: 创建UIScrollView的分类 @implementation UIScrollView (PopGesture) //此方法返回YES时,手势事件会一直往下传递,不论当前层次是否对该事件进行响应。 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ return YES; } - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{ return YES; } @end 二、全屏滑动返回全屏返回这种骚功能,官方从未提供过,可爱的程序员们自己搞出来,以前的做法(ios7之前)大概就是“手势+截图”,画风是这样的: - (void)viewDidLoad{ [super viewDidLoad]; UIImageView *shadowImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"leftside_shadow_bg"]]; shadowImageView.frame = CGRectMake(-10, 0, 10, self.view.frame.size.height); [self.view addSubview:shadowImageView]; UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(paningGestureReceive:)]; [recognizer setDelegate:self]; [recognizer delaysTouchesBegan]; [self.view addGestureRecognizer:recognizer]; } - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{ if (self.viewControllers.count > 0) { [self.screenShotsList addObject:[self capture]]; //截图,并放入数组 } [super pushViewController:viewController animated:animated]; } - (nullable NSArray *)popToRootViewControllerAnimated:(BOOL)animated { [self.screenShotsList removeAllObjects]; //清空截图 return [super popToRootViewControllerAnimated:animated]; } - 感兴趣的同学可以在 这里 看到完整代码 - 自从ios7支持【边缘滑动】返回后,【全屏返回】的实现又多了一种思路,江湖人称:移花接木。同样有两个方案。 拿捏: 方案一:在UINavigationController基类中: - (void)viewDidLoad{ [super viewDidLoad]; // 获取系统自带滑动手势的target对象 id target = self.interactivePopGestureRecognizer.delegate; // 创建全屏滑动手势,调用系统自带滑动手势的target的action方法 SEL handler = NSSelectorFromString(@"handleNavigationTransition:"); UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:handler]; //设置手势代理,拦截手势触发 pan.delegate = self; //添加全屏滑动手势 [self.interactivePopGestureRecognizer.view addGestureRecognizer:pan]; // 禁止使用系统自带的边缘滑动手势 self.interactivePopGestureRecognizer.enabled = NO; //设置右滑返回手势的代理为自身 __weak typeof(self) weakself = self; if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.interactivePopGestureRecognizer.delegate = (id)weakself; } } 注意,这里的 pan.delegate = self; 可能系统会打警告⚠️,因为没有申明和实现代理 UIGestureRecognizerDelegate ,不实现也木有关系的,不过实现的话,可以再加一些判断,出于安全和为了去掉警告,我们来加一下。 拿捏: @interface UIViewController() @end ... ... - (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer{ //控制器栈里只有一个,不响应 if (self.navigationController.viewControllers.count |
今日新闻 |
推荐新闻 |
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 |