iOS-在关闭和滚动手势之间切换
我正试图模仿Line messenger应用程序(日本事实上的messenger应用程序)中的一种行为 基本上,他们有一个模态视图控制器,里面有一个滚动视图。当滚动动作到达其内容的顶部时,视图控制器将无缝切换到交互式动画。此外,当手势将视图返回到屏幕顶部时,控制将返回到滚动视图 这是它的gif图像 就我个人而言,我不知道他们是怎么做到的。我试过几种不同的方法,但都失败了,我也没有主意了。谁能给我指出正确的方向吗 EDIT2 要澄清的是,我想要模仿的行为不仅仅是将窗口向下拖动。我能做到,没问题 我想知道相同的滚动手势(不抬起手指)是如何触发切换的,然后在视图被拖回原始位置后将控制权转移回滚动视图 这是我无法理解的部分 结束编辑2 EDIT1 这是我到目前为止所拥有的。我能够使用scroll view delegate方法添加一个处理常规动画的目标选择器,但它仍然不能按预期工作 我使用iOS-在关闭和滚动手势之间切换,ios,uiscrollview,uigesturerecognizer,modalviewcontroller,Ios,Uiscrollview,Uigesturerecognizer,Modalviewcontroller,我正试图模仿Line messenger应用程序(日本事实上的messenger应用程序)中的一种行为 基本上,他们有一个模态视图控制器,里面有一个滚动视图。当滚动动作到达其内容的顶部时,视图控制器将无缝切换到交互式动画。此外,当手势将视图返回到屏幕顶部时,控制将返回到滚动视图 这是它的gif图像 就我个人而言,我不知道他们是怎么做到的。我试过几种不同的方法,但都失败了,我也没有主意了。谁能给我指出正确的方向吗 EDIT2 要澄清的是,我想要模仿的行为不仅仅是将窗口向下拖动。我能做到,没问题
UIWebView
作为属性创建了一个UIViewController
。然后我把它放在一个UINavigationController
中,它以模态的形式呈现
导航控制器使用动画/过渡控制器进行常规交互(可以通过在导航栏上做手势来完成)
从这里开始,一切正常,但不能从滚动视图触发解雇
导航控制器
@interface NavigationController : UINavigationController <UIViewControllerTransitioningDelegate>
@property (nonatomic, strong) UIPanGestureRecognizer *gestureRecog;
- (void)handleGesture:(UIPanGestureRecognizer*)gestureRecognizer;
@end
@界面导航控制器:UINavigationController
@属性(非原子,强)UIPangestureRecognitor*gestureRecog;
-(无效)手势识别器:(UIPangestureRecognitor*)手势识别器;
@结束
导航控制器
#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
#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];
}
#导入“NavigationController.h”
#导入“AnimationController.h”
#导入“TransitionController.h”
@实现导航控制器{
AnimationController*\u animator;
TransitionController*\u交互器;
}
-(instancetype)初始化{
self=[super init];
self.transitioningDelegate=self;
_animator=[[AnimationController alloc]init];
_interactor=[[TransitionController alloc]init];
回归自我;
}
-(无效)viewDidLoad{
[超级视图下载];
//设置手势识别器
self.gestureRecog=[[UIPangestureRecognitizer alloc]initWithTarget:self action:@selector(HandleTesture:)];
[self.view addgestureRecognitor:\u gestureRecog];
}
-(id)InteractionControllerFordisessal:(id)动画师{
if(animator==\u animator&&u interactitor.hasStarted){
返回交互器;
}
返回零;
}
-(id)animationControllerForDismissedController:(UIViewController*)已解除{
if(discomered==self | |[self.viewControllers indexOfObject:discomered]!=NSNotFound){
返回动画;
}
返回零;
}
-(无效)手势测试:(UIPangestureRecognitor*)手势记录{
CGFloat阈值=0.3f;
CGPoint translation=[gestureRecog translationview:self.view];
CGFloat verticalMovement=translation.y/self.view.bounds.size.height;
CGFloat向下移动=fmaxf(垂直移动,0.0f);
CGFloat向下移动百分比=fminf(向下移动,1.0f);
开关(手势记录状态){
案例UIgestureRecognitzerStateStart:{
_interactior.hasStarted=是;
[自我解除视图控制器激活:是完成:无];
打破
}
案例UIgestureRecognitzerStateChanged:{
if(!\u interactior.hasStarted){
_interactior.hasStarted=是;
[自我解除视图控制器激活:是完成:无];
}
_interactor.shouldFinish=向下移动百分比>阈值;
[\u Interactitor updateInteractiveTransition:downwardMovementPercent];
打破
}
案例UIgestureRecognitizerState已取消:{
_interactior.hasStarted=否;
[\u Interactior cancelInteractiveTransition];
打破
}
案例UIgestureRecognitzerStateEnded:{
_interactior.hasStarted=否;
if(_interactior.shouldFinish){
[_交互者完成交互转换];
}否则{
[\u Interactior cancelInteractiveTransition];
}
打破
}
默认值:{
打破
}
}
}
@结束
现在,我必须在滚动视图到达顶部时触发手势处理。下面是我在视图控制器中所做的
WebViewController.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
#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];
}
#导入“WebViewController.h”
#导入“NavigationController.h”
@接口WebViewController()
@属性(弱、非原子)ibuiwebview*webView;
@结束
@WebViewController的实现{
波尔·伊山灵潘;
CGPoint _topContentOffset;
}
-(无效)viewDidLoad{
[超级视图下载];
[self.webView.scrollView setDelegate:self];
}
-(无效)scrollViewDidScroll:(UIScrollView*)scrollView{
如果((scrollView.panGestureRecognizer.state==UIgestureRecognizerStateStart||
scrollView.panGestureRecognizer.state==UIGestureRecognizerStateChanged)&&
!\u isHandlingPan&&
scrollView.contentOffset.yfunc shouldHandlePanelInteractionGesture() -> Bool {
return (scrollView.contentOffset.y == 0);
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
scrollView.bounces = (scrollView.contentOffset.y > 10);
}
ScrollViewController.transitioningDelegate = self.panelTransitioningDelegate
ScrollViewController.modalPresentationStyle = .custom