iOS - 在关闭和滚动手势之间切换

2024-03-18

我正在尝试模仿 Line 通讯应用程序(日本事实上的通讯应用程序)中的一种行为。

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

这是它的外观 gif。

对于我的一生,我无法弄清楚他们是如何做到的。我尝试了几种不同的方法,但都失败了,我没有主意。有人能指出我正确的方向吗?

EDIT2

需要澄清的是,我想要模拟的行为不仅仅是简单地向下拖动窗口。我可以做到,没问题。

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

这是我无法弄清楚的部分。

结束编辑2

EDIT1

这是我到目前为止所拥有的。我能够使用滚动视图委托方法添加一个处理常规解雇动画的目标选择器,但它仍然无法按预期工作。

我创建一个UIViewController with a UIWebView作为财产。然后我把它放在一个UINavigationController,这是模态呈现的。

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

从这里开始,一切正常,但无法从滚动视图触发解雇。

导航控制器.h

@interface NavigationController : UINavigationController <UIViewControllerTransitioningDelegate>

@property (nonatomic, strong) UIPanGestureRecognizer *gestureRecog;

- (void)handleGesture:(UIPanGestureRecognizer*)gestureRecognizer;

@end

导航控制器.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];
}

这仍然不太正常。即使在关闭动画期间,滚动视图仍然随着手势滚动。

结束编辑1


这是一个自定义的交互式过渡。

首先,你需要设置transitioningDelegate of UIViewController

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 https://github.com/zoonooz/ZFDragableModalTransition

ZFDragableModalTransition 的图像

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS - 在关闭和滚动手势之间切换 的相关文章

随机推荐

  • Yii - ajax 加载的表单元素的用户端验证

    我在静态表单中使用 Yii 用户端验证 这非常棒 但我不知道如何为 ajax 加载的元素添加验证器 我有一个简单的表单小部件 我想通过 AJAX 加载更多的输入字段 对于小型 jQuery 脚本来说这不是问题 但我不知道如何为加载的元素添加
  • WPF 中的进度条样式是老式的。酒吧增量。如何实现带有vista或windows-7阴影发光效果的进度条?

    WPF 中的进度条样式是老式的 酒吧增量 如何实现带有 vista 或 windows 7 阴影发光效果的进度条 图片http quickshare my3gb com download 2 JPG http quickshare my3g
  • C 指针和内存分配:Realloc 数组和指针传递

    对于那些有 C 经验的人来说 这将是一个简单的内存分配 引用问题 这是我的数据结构 struct configsection char name unsigned int numopts configoption options typed
  • 有没有办法用 Moq 来一般模拟 DbSet.Find 方法?

    我目前正在使用扩展方法来将 DbSets 一般模拟为列表 public static DbSet
  • CSV 未附加到应用程序电子邮件中?

    所以我有一段时间遇到这个问题但无法让它工作 我一直在构建一个调查应用程序 用户只需在其中输入信息并将其保存到 csv 文件中 我现在正处于需要将应用程序内的 csv 文件附加到电子邮件地址的阶段 我刚刚在我的新手机上测试了这个 收到电子邮件
  • 在 ipython 笔记本中测量单元执行时间的简单方法

    除了单元的原始输出之外 我还想获取单元执行所花费的时间 为此 我尝试了 timeit r1 n1但它不会公开单元格内定义的变量 time适用于仅包含 1 条语句的单元格 In 1 time 1 CPU times user 4 s sys
  • 为什么 UITableView 单元格在滚动时重叠?

    我有一个UITableView大约有 100 行 每个单元格都检查了图像 但是当我们滚动时UITableView 所有单元格在未检查的单元格中重叠 UITableViewCell tableView UITableView tableVie
  • 重载new和delete

    我尝试遵循这篇文章 http flipcode com archives How To Find Memory Leaks shtml http flipcode com archives How To Find Memory Leaks
  • 相对URL问题

    我将有多个文件夹 模块来访问常用文件 但访问它们对我来说似乎很重要 我确实通过这个链接来了解相对定位并设法解决了一些问题 但不是所有的 参考 php 中的相对 URL 路径 https stackoverflow com questions
  • IOS - 如果用户点击随机元素而不是背景,如何隐藏键盘?

    在我的应用程序中我有这样的东西 IBAction backgroundTouch id sender businessDescription resignFirstResponder self view endEditing YES 我不确
  • 如何使用 C# 读取 XML 元素的内容? [复制]

    这个问题在这里已经有答案了 可能的重复 解析 xml 文件的最佳实践 https stackoverflow com questions 55828 best practices to parse xml files 我希望能够在 XML
  • Spring WebFlux 创建无阻塞线程池

    我决定用 Java 重写我的 Web 应用程序 之前是用 Python 编写的 在我的应用程序中 我使用了无阻塞 I O 我有工作池 Celery Eventlet 线程 我在其中传递由数百个 API 调用组成的任务 现在我正在使用Spri
  • 如何使用 Process.Start 启动管道并重定向命令?

    我正在使用 System Diagnostics Process Start 在 Linux 操作系统上远程启动命令 到目前为止 我已经能够启动简单的命令 然后读取输出 例如我可以执行命令echo Hello World并阅读Hello W
  • 跨线程操作错误

    if listBox1 InvokeRequired listBox new StringBuilder this listBox1 Text 这是 c 中的代码 执行时会对 listBox1 产生无效的跨线程操作错误 listBox1 是
  • 透明背景上的 TKinter 按钮

    我试图了解如何将按钮应用到透明背景 同时保持其形状 当我生成下面的代码时 边框周围出现灰色背景 而且看起来也失去了形状 使用的颜色 侧边栏 2E3A4B 53 按钮 2C2F33 100 from tkinter import def bt
  • Laravel artisan cron 不工作

    我有一个页面在 beanstalked 中对电子邮件进行排队 该脚本按预期工作 当我有队列侦听器时 电子邮件会被触发 即 php artisan queue listen 但是当我删除侦听器并将其添加到 cron 作业时 usr bin p
  • 带有数字键的动态 json 对象

    我有一个 json 对象 在以下命令的帮助下将其转换为动态 C 对象this https stackoverflow com questions 3142495 deserialize json into c dynamic object
  • 如何获取 web.config appSettings 作为 ConfigurationSection 而不是 NameValueCollection

    ConfigurationManager AppSettings 属性 返回一个 NameValueCollection 对象 其中包含当前应用程序默认配置的 AppSettingsSection 对象的内容 但我需要 AppSetting
  • 如何检测 VPN 或代理连接? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想阻止所有使用 VPN 或代理服务器的连接 是否有办法检测是否正在使用 VPN 或代理连接 如果没有 我是否可以检查使用 VPN 或
  • iOS - 在关闭和滚动手势之间切换

    我正在尝试模仿 Line 通讯应用程序 日本事实上的通讯应用程序 中的一种行为 基本上 它们有一个模态视图控制器 内部有滚动视图 当滚动操作到达其内容的顶部时 视图控制器无缝切换到交互式解除动画 此外 当手势将视图返回到屏幕顶部时 控制权将