iOS – 在解散和滚动手势之间切换

Line Messenger应用程序(日本的事实上的Messenger软件)中有一个行为,我试图效仿。

基本上,他们有一个模式的视图控制器内的滚动视图。 当滚动动作到达其内容的顶部时,视图控制器无缝切换到交互式解除animation。 另外,当手势将视图返回到屏幕的顶部时,控制将返回到滚动视图。

这是它的外观的一个GIF。

演示gif

对于我的生活,我无法弄清楚他们是如何做到的。 我尝试了一些不同的方法,但都失败了,我没有想法。 任何人都可以指向正确的方向吗?

EDIT2

为了澄清,我想模仿的行为不仅仅是拖动窗口。 我可以做到这一点,没问题。

我想知道如何使用相同的滚动手势(不用抬起手指)触发解除转换,然后在视图被拖回到原始位置后,将控制权转移回滚动视图。

这是我无法弄清的部分。

结束编辑2

EDIT1

这是我迄今为止。 我能够使用滚动视图委托方法来添加处理常规解雇animation的目标select器,但它仍然不能按预期工作。

我创build一个UIWebView作为属性的UIViewController 。 然后我把它放在一个UINavigationController ,这是以模态方式呈现的。

导航控制器使用animation/转换控制器进行常规的交互式解除(可以通过在导航栏上进行手势来完成)。

从这里,一切正常,但不能从滚动视图触发解雇。

NavigationController.h

 @interface NavigationController : UINavigationController <UIViewControllerTransitioningDelegate> @property (nonatomic, strong) UIPanGestureRecognizer *gestureRecog; - (void)handleGesture:(UIPanGestureRecognizer*)gestureRecognizer; @end 

NavigationController.m

 #import "NavigationController.h" #import "AnimationController.h" #import "TransitionController.h" @implementation NavigationController { AnimationController *_animator; TransitionController *_interactor; } - (instancetype)init { self = [super init]; self.transitioningDelegate = self; _animator = [[AnimationController alloc] init]; _interactor = [[TransitionController alloc] init]; return self; } - (void)viewDidLoad { [super viewDidLoad]; // Set the gesture recognizer self.gestureRecog = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)]; [self.view addGestureRecognizer:_gestureRecog]; } - (id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator { if (animator == _animator && _interactor.hasStarted) { return _interactor; } return nil; } - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed { if (dismissed == self || [self.viewControllers indexOfObject:dismissed] != NSNotFound) { return _animator; } return nil; } - (void)handleGesture:(UIPanGestureRecognizer *)gestureRecog { CGFloat threshold = 0.3f; CGPoint translation = [gestureRecog translationInView:self.view]; CGFloat verticalMovement = translation.y / self.view.bounds.size.height; CGFloat downwardMovement = fmaxf(verticalMovement, 0.0f); CGFloat downwardMovementPercent = fminf(downwardMovement, 1.0f); switch (gestureRecog.state) { case UIGestureRecognizerStateBegan: { _interactor.hasStarted = YES; [self dismissViewControllerAnimated:YES completion:nil]; break; } case UIGestureRecognizerStateChanged: { if (!_interactor.hasStarted) { _interactor.hasStarted = YES; [self dismissViewControllerAnimated:YES completion:nil]; } _interactor.shouldFinish = downwardMovementPercent > threshold; [_interactor updateInteractiveTransition:downwardMovementPercent]; break; } case UIGestureRecognizerStateCancelled: { _interactor.hasStarted = NO; [_interactor cancelInteractiveTransition]; break; } case UIGestureRecognizerStateEnded: { _interactor.hasStarted = NO; if (_interactor.shouldFinish) { [_interactor finishInteractiveTransition]; } else { [_interactor cancelInteractiveTransition]; } break; } default: { break; } } } @end 

现在,当滚动视图到达顶端时,我必须得到这个手势处理才能触发。 所以,这是我在视图控制器中所做的。

WebViewController.m

 #import "WebViewController.h" #import "NavigationController.h" @interface WebViewController () @property (weak, nonatomic) IBOutlet UIWebView *webView; @end @implementation WebViewController { BOOL _isHandlingPan; CGPoint _topContentOffset; } - (void)viewDidLoad { [super viewDidLoad]; [self.webView.scrollView setDelegate:self]; } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if ((scrollView.panGestureRecognizer.state == UIGestureRecognizerStateBegan || scrollView.panGestureRecognizer.state == UIGestureRecognizerStateChanged) && ! _isHandlingPan && scrollView.contentOffset.y < self.navigationController.navigationBar.translucent ? -64.0f : 0) { NSLog(@"Adding scroll target"); _topContentOffset = CGPointMake(scrollView.contentOffset.x, self.navigationController.navigationBar.translucent ? -64.0f : 0); _isHandlingPan = YES; [scrollView.panGestureRecognizer addTarget:self action:@selector(handleGesture:)]; } } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { NSLog(@"Did End Dragging"); if (_isHandlingPan) { NSLog(@"Removing action"); _isHandlingPan = NO; [scrollView.panGestureRecognizer removeTarget:self action:@selector(handleGesture:)]; } } - (void)handleGesture:(UIPanGestureRecognizer*)gestureRecognizer { [(NavigationController*)self.navigationController handleGesture:gestureRecognizer]; } 

这仍然不正确。 即使在解散animation期间,滚动视图仍然以该手势滚动。

结束编辑1

这是一个自定义的交互式转换。

首先,你需要设置UIViewController transitioningDelegate

 id<UIViewControllerTransitioningDelegate> transitioningDelegate; 

然后把这两种方法归为一类

  //Asks your delegate for the transition animator object to use when dismissing a view controller. - animationControllerForDismissedController: //Asks your delegate for the interactive animator object to use when dismissing a view controller. - interactionControllerForDismissal: 

当拖到最顶端,开始转换时,可以使用UIPercentDrivenInteractiveTransition来控制滚动期间的进度。

您也可以参考ZFDragableModalTransition的源代码

ZFDragableModalTransition的图像