iPhone - 在 UIViewController 中处理触摸幻灯片

Posted

技术标签:

【中文标题】iPhone - 在 UIViewController 中处理触摸幻灯片【英文标题】:iPhone - Handle touch slide in a UIViewController 【发布时间】:2010-06-22 13:24:14 【问题描述】:

我想在 UIViewController 子类中处理触摸(特别是水平滑动),但问题是控制器的视图包含一个覆盖整个屏幕的 UIScrollView,因此“touchesBegan:”和“touchesEnded:”事件在我的控制器中永远不会被调用。滚动视图只垂直滚动。

让它能够处理这些事件的最佳方法是什么?让我的 UIViewController 也继承自 UIScrollView 并根据需要处理触摸(并删除当前的滚动视图),或者使用 UIScrollView 子类代替我当前的滚动视图,这将为我需要的情况调用委托方法?还是有别的办法?

这是我当前的代码:

// View creation and adding to parent
NewViewController* newViewController = [[newViewController alloc] initWithNibName:@"NewViewController" bundle:nil];
[self.view addSubview:newViewController.view];

// NewViewController.h
@interface NewViewController : UIViewController 
    IBOutlet UIScrollView*  scrollView;

    // other outlets and properties

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event;

在 IB 中,NewViewController 的视图包含滚动视图,其中包含所有其他出口(标签、按钮)... 目标是让 NewViewController 的 scrollView 调用 NewViewController 的 touchesBegan 和 touchesEnded 方法。

更新: ScrollViewSuite 帮助我了解了如何处理触摸回调。 UIScrollView 仅在触摸不滚动时才调用它们。

所以,三种情况:

倾斜滑动(即使是轻微的,只要滚动条出现):没有调用touches 方法 完全水平滑动(不出现滚动条):touchesBegantouchesMovedtouchesEnded 被调用 任何不引起滚动的触摸(触摸而不移动,或水平移动)然后稍微垂直滑动:touchesBegantouchesMovedtouchesCancelled 都会被调用;

可以通过将UIScrollViewcanCancelContentTouches 设置为FALSE 来避免取消触摸,但这显然只有在调用touchesBegan 时才有效,这意味着在第一种情况下仍然不会调用触摸方法。

但是UIScrollView 有一个名为delaysContentTouches 的属性,默认设置为TRUE,它会在触摸开始时稍等片刻,以查看是否会让他滚动。如果设置为FALSE,则在触摸开始时立即调用触摸方法,并允许子类根据需要处理它们。

TL;DR: 对我来说似乎最简单的方法(如果你不能使用UIGestureRecognizer)是继承UIScrollView,将其delayContentTouches 属性设置为@987654340 @ 并根据您的需要覆盖触摸功能(touchesShouldBegin / touchesShouldCancel 以及 touchesBegan / touchesMoved...)。

【问题讨论】:

scrollView 的 contentSize 属性在哪里设置? 在 NewViewController 的 viewDidLoad 中。我根据插座的大小放置插座,最后设置 scrollView 的内容高度。但是使用此代码滚动工作,唯一的问题是不调用触摸方法。 【参考方案1】:

如果您正在为 iPhone OS 3.2 或更高版本构建,您可以使用 Gesture Recognizer 对象。根据您的描述,您可能想要UIPanGestureRecognizer 或UISwipeGestureRecognizer。实例化适当的对象,使用 [addGestureRecognizer:] 方法将其添加到 viewController 的视图中,并在 viewController 中实现委托方法。

供参考:iPhone Event Handling Guide: Gesture RecognizersUIGestureRecognizer Reference(抽象超类)UIGestureRecognizerDelegate Protocol Reference

【讨论】:

好吧,我曾经为 3.1.3 ios 构建,而我使用的 iPhone 目前也是 3.1.3。如果我找不到任何简单的东西,我会尝试升级并查看这些手势识别器,谢谢。【参考方案2】:

您的 viewController 的视图应该是 UIScrollView 的子视图。 创建一个 UIScrollView 添加为窗口的子视图,然后创建一个具有滑块的 viewController 实例并添加到滚动视图的子视图中。

UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:[window bounds]];
[window addSubView:scrollView];
UIViewController *vc = [[UIViewController alloc] initWithNibNamed:@"MyVC" bundle:nil];
[scrollView addSubView:[vc view]];

我怀疑您没有收到事件是因为 IB 中缺少连接,或者 scrollView 正在将事件转发到 newViewController 视图的父视图。

UIRespondernextResponder 属性的 Apple 文档中。

UIResponder 类不会自动存储或设置下一个响应者,而是默认返回 nil。子类必须重写此方法以设置下一个响应者。 UIView 通过返回管理它的 UIViewController 对象(如果有)或其父视图(如果没有)来实现此方法; UIViewController 通过返回其视图的父视图来实现该方法; UIWindow 返回应用程序对象,UIApplication 返回 nil。

尝试几件事。

    在 NewViewController.m 中,覆盖 canBecomeFirstResponder
    
    - (BOOL)canBecomeFirstResponder
    
        return YES;
    
    
    因为您只是将新视图添加为子视图,而不是使用导航或模式视图,请确保 newViewController 的父视图不再是第一响应者。添加:
    
    // View creation and adding to parent
    NewViewController* newViewController = [[newViewController alloc] initWithNibName:@"NewViewController" bundle:nil];
    [self.view addSubview:newViewController.view];
    [self.view resignFirstResponder];
    
    确保 `NextViewController' 的视图已连接到 IB 中的 File's Owner。 确保视图的 userInteractionEnabled 属性为 YES

还请查看ScrollViewSuite 示例代码。 我注意到包含从 scrollView 接收事件的视图的控制器实现了视图的委托方法。您可以尝试的一种方法是将 scrollView 中的视图子类化,并根据示例代码将事件处理委托给您的控制器。

还有其他答案中讨论的新 UIGesturizer 的示例。请注意,guesturizers 被添加到视图中,并且 guesturizers 的处理被委托给另一个对象(通常是视图的控制器)

您说按钮和标签是作为 IB 中滚动视图的子视图添加的。看来您应该有一个 UIView 作为按钮和标签的容器。只是一个想法,我无法从代码 sn-p 中看出。

UIScrollView
  -> UIView
      ->UIButton
      ->UILabel
      ..
      ..

【讨论】:

哼,我不确定我明白你的意思。事情是我的 viewControllers 的视图已经是应用程序中前一个屏幕中另一个 VC 视图的子视图,所以我尝试从 nib 中删除 scrollView,像在我当前的 VC 的 viewDidLoad 中那样手动创建它,将它添加到 VC 的超级视图,最后将VC的视图添加到scrollView的子视图中。但这无济于事,我既没有滚动也没有 touchesBegan/Ended 回调。 我用原始代码更新了我的问题。不过没什么可看的。 我覆盖了 canBecomeFirstResponder,辞去了 superview 的第一响应者并检查了 IB 中的所有内容,但仍然没有调用 touches 方法。我首先尝试了我的想法,我创建了一个 UIScrollView 的子类,它覆盖了触摸方法(在调用 [super touches...] 之前存储了一些数据)并用它替换了我的 scrollView。这可行,但并不是每次都调用这些方法......它甚至是非常随机的。如果我想确保调用这两种方法,就必须慢慢滑动并避免滚动,就好像有某种过滤器一样......这似乎不是一个好方法。 添加了更多尝试 抱歉耽搁了,我正在处理其他事情。我想我已经找到了解决方案,我更新了原始问题。现在我将看看手动处理所有内容是否可行。非常感谢您的帮助,ScrollViewSuite 是个好主意。

以上是关于iPhone - 在 UIViewController 中处理触摸幻灯片的主要内容,如果未能解决你的问题,请参考以下文章

在 UITableview 中显示图像

未调用 DidEndSendingToApplication

SwiftUI 导出或共享文件

将 SKScene 添加到 UIViewController?

.showsPhysics的内存泄漏

如何在 Swift 中获取按钮的当前标题?